| name | dryui-build |
| description | Experimental DryUI fixture-first page skill for image-to-app layout tests. Use when testing stage 1 page classification, stage 2 constrained DryUI implementation, and stage 3 build repair. |
DryUI Page Layout: Fixture First
Build the supplied design image as a finished DryUI app page. Optimize for a clean build, lint-safe layout, and responsive shell fidelity before visual embellishment.
Harness Rule
Run bun run build before final. Do not run dev servers, browser checks, extra audits, or broad package searches. The harness captures mobile, tablet, and desktop after you finish.
Stage 1: Pick One Recipe
Identify the page as one of these recipes and keep the fixed shell:
dashboard: metrics in primary, chart/table panels below, activity in secondary.
settings: nav in navigation, form/status panels in primary, help/activity in secondary.
crm: pipeline/list panels in primary, deal summary in secondary.
kanban: board columns in primary, project health in secondary.
knowledge: documents/search/results in primary, source summary in secondary.
Use this shell exactly:
<main data-layout="app-shell">
<div data-layout-area="page">
<header data-layout-area="topbar">...</header>
<nav data-layout-area="navigation">...</nav>
<section data-layout-area="primary">...</section>
<aside data-layout-area="secondary">...</aside>
</div>
</main>
Stage 2: Build With Safe Elements
Use these imports only unless build reports a missing import:
import {Badge} from '@dryui/ui/badge'; import {Button} from '@dryui/ui/button'; import {Heading} from
'@dryui/ui/heading'; import {Image} from '@dryui/ui/image'; import {Input} from '@dryui/ui/input'; import
{Link} from '@dryui/ui/link'; import {Separator} from '@dryui/ui/separator'; import {Table} from '@dryui/ui/table';
import {Text} from '@dryui/ui/text';
Do not use raw text/media/link elements: no <p>, <span>, <strong>, <img>, <a>, <ul>, or <li>. Use Heading, Text, Image, Link, Button, Badge, and Table.
Raw structural elements are allowed only when they have data-layout or data-layout-area and that layout name exists in src/layout.css.
Good panel pattern:
<article data-layout="panel-stack" data-tone="surface">
<div data-layout="section-heading">
<Heading level={2}>Revenue mix</Heading>
<Text color="muted" size="sm">Updated 4 minutes ago</Text>
</div>
<div data-layout="row-cluster">
<Badge color="green">Live</Badge>
<Button variant="outline">Open</Button>
</div>
</article>
Rules:
- No
<style> in src/routes/+page.svelte.
- No
class= or class: on DryUI components.
- No inline
style= or style: directives.
- Keep content real enough: headings, labels, metrics, statuses, and table rows.
- Prefer simple static blocks over complex chart mechanics. Use
data-layout="chart-grid" with nested data-layout="chart-bar" wrappers if needed.
Stage 3: Copy src/layout.css Exactly
Replace src/layout.css with this exact structural stylesheet. Do not add, remove, or edit selectors/properties.
[data-layout='app-shell'] {
container: page / inline-size;
min-block-size: 100dvh;
}
[data-layout='app-shell'] > [data-layout-area='page'] {
display: grid;
min-block-size: 100dvh;
grid-template-areas:
'topbar'
'primary'
'secondary'
'navigation';
grid-template-columns: minmax(0, 1fr);
grid-template-rows: auto minmax(0, 1fr) auto auto;
gap: var(--dry-space-3);
}
[data-layout='app-shell'] > [data-layout-area='page'] > [data-layout-area='topbar'] {
grid-area: topbar;
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--dry-space-3);
}
[data-layout='app-shell'] > [data-layout-area='page'] > [data-layout-area='navigation'] {
grid-area: navigation;
display: grid;
grid-template-columns: minmax(0, 1fr);
align-content: start;
gap: var(--dry-space-2);
}
[data-layout='app-shell'] > [data-layout-area='page'] > [data-layout-area='primary'],
[data-layout='app-shell'] > [data-layout-area='page'] > [data-layout-area='secondary'] {
display: grid;
grid-template-columns: minmax(0, 1fr);
align-content: start;
gap: var(--dry-space-3);
}
[data-layout='app-shell'] > [data-layout-area='page'] > [data-layout-area='primary'] {
grid-area: primary;
}
[data-layout='app-shell'] > [data-layout-area='page'] > [data-layout-area='secondary'] {
grid-area: secondary;
}
[data-layout='brand-cluster'],
[data-layout='toolbar-cluster'],
[data-layout='row-cluster'],
[data-layout='section-heading'] {
display: flex;
align-items: center;
gap: var(--dry-space-2);
flex-wrap: wrap;
}
[data-layout='toolbar-cluster'],
[data-layout='row-cluster'] {
justify-content: flex-end;
}
[data-layout='app-stack'],
[data-layout='panel-stack'],
[data-layout='list-stack'],
[data-layout='table-frame'],
[data-layout='preview-stack'] {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: var(--dry-space-3);
}
[data-layout='metric-grid'],
[data-layout='content-grid'],
[data-layout='board-grid'],
[data-layout='chart-grid'] {
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: var(--dry-space-3);
}
[data-layout='chart-bar'] {
display: grid;
align-items: end;
min-block-size: 8rem;
}
@container page (min-width: 48rem) {
[data-layout='app-shell'] > [data-layout-area='page'] {
grid-template-areas:
'topbar topbar'
'navigation primary'
'secondary secondary';
grid-template-columns: 13rem minmax(0, 1fr);
gap: var(--dry-space-4);
}
[data-layout='metric-grid'],
[data-layout='content-grid'],
[data-layout='board-grid'],
[data-layout='chart-grid'] {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@container page (min-width: 72rem) {
[data-layout='app-shell'] > [data-layout-area='page'] {
grid-template-areas:
'navigation topbar topbar'
'navigation primary secondary';
grid-template-columns: 14rem minmax(0, 1fr) minmax(18rem, 0.35fr);
grid-template-rows: auto minmax(0, 1fr);
}
[data-layout='metric-grid'] {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
[data-layout='content-grid'],
[data-layout='board-grid'],
[data-layout='chart-grid'] {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
Visual CSS
src/app.css is visual only. It may set colors, borders, radius, padding, margin, typography, shadows, custom properties, and overflow. It must not contain display, grid, flex, container, @container, or @media.