212 lines
7.3 KiB
Plaintext
212 lines
7.3 KiB
Plaintext
// Layout tour. Route: /layout
|
|
//
|
|
// One page built out of the layout set, rather than showing each piece alone:
|
|
//
|
|
// PublicPageShell the outer shell, holding the page background
|
|
// Section each band down the page, with its own spacing and tint
|
|
// SectionHeader the eyebrow, heading and description of each band
|
|
// Container the reading width
|
|
// Grid the card deck, including an auto-fit track
|
|
// Columns the coarse two-way split
|
|
// LayoutSplitter a resizable pane, by drag or by arrow key
|
|
// CustomScrollbar a themed scrolling region
|
|
// Divider the rules between bands
|
|
// Typography the prose column
|
|
// Image, Link, Kbd the smaller pieces inside it
|
|
//
|
|
// CustomScrollbar sits beside the splitter rather than inside a pane of it: a
|
|
// component tag nested in another component slot is dropped, and only its
|
|
// children survive.
|
|
//
|
|
// The splitter does not report into a status line here. It emits a sizeChange
|
|
// output and the component does fire it, but a parent binding on the tag is
|
|
// not invoked, so wiring one up would show something that never updates.
|
|
page LayoutTour {
|
|
layout = "public"
|
|
|
|
seo {
|
|
title = "Layout tour"
|
|
description = "Every layout component working together on one page."
|
|
}
|
|
|
|
view {
|
|
<PublicPageShell background="default" minHeight="dvh" fullWidth={true}>
|
|
<Section spacing="lg" variant="soft" borderBottom={true}>
|
|
<Container maxWidth="lg" columns={1}>
|
|
<SectionHeader
|
|
eyebrow="Layout"
|
|
title="Composing a page"
|
|
description="Every band on this page is a Section. The width you are reading at is a Container, and the pieces inside are the rest of the layout set."
|
|
align="center"
|
|
maxWidth="2xl"
|
|
/>
|
|
</Container>
|
|
</Section>
|
|
|
|
<Section spacing="lg">
|
|
<Container maxWidth="lg" columns={1}>
|
|
<SectionHeader
|
|
eyebrow="Grid"
|
|
title="Card decks"
|
|
description="A fixed column count collapses at each breakpoint. Pass minItemWidth instead and the browser decides the count, reflowing continuously."
|
|
headingLevel={3}
|
|
/>
|
|
|
|
<Divider />
|
|
|
|
<Grid columns={3} gap="md">
|
|
<div class="tour-card">
|
|
<h4>Fixed columns</h4>
|
|
<p>Three tracks on a wide screen, two on a tablet, one on a phone.</p>
|
|
</div>
|
|
<div class="tour-card">
|
|
<h4>Themed</h4>
|
|
<p>Every surface here is a theme token, so light and dark both work.</p>
|
|
</div>
|
|
<div class="tour-card">
|
|
<h4>No Tailwind</h4>
|
|
<p>These components carry their own styles and no longer need it.</p>
|
|
</div>
|
|
</Grid>
|
|
|
|
<Divider label="auto fit" />
|
|
|
|
<Grid minItemWidth="12rem" gap="sm">
|
|
<div class="tour-card tour-card--compact"><h4>One</h4></div>
|
|
<div class="tour-card tour-card--compact"><h4>Two</h4></div>
|
|
<div class="tour-card tour-card--compact"><h4>Three</h4></div>
|
|
<div class="tour-card tour-card--compact"><h4>Four</h4></div>
|
|
<div class="tour-card tour-card--compact"><h4>Five</h4></div>
|
|
</Grid>
|
|
</Container>
|
|
</Section>
|
|
|
|
<Section spacing="lg" variant="soft" borderTop={true} borderBottom={true}>
|
|
<Container maxWidth="lg" columns={1}>
|
|
<SectionHeader
|
|
eyebrow="Split"
|
|
title="Columns and panes"
|
|
description="Columns is the coarse split of a page. LayoutSplitter is the one the reader can move."
|
|
headingLevel={3}
|
|
/>
|
|
|
|
<Columns columns={2} gap="lg">
|
|
<Typography maxWidth="full">
|
|
<h4>Prose</h4>
|
|
<p>
|
|
Typography caps the measure so a line never runs too long to
|
|
follow. Inside it you get the smaller pieces: a
|
|
<Link href="/navigation" label="link" /> to somewhere else, and
|
|
<Kbd label="Ctrl" /> <Kbd label="K" /> for a shortcut.
|
|
</p>
|
|
</Typography>
|
|
|
|
<Image src="" alt="Placeholder artwork" size="video" rounded={true} />
|
|
</Columns>
|
|
</Container>
|
|
</Section>
|
|
|
|
<Section spacing="lg">
|
|
<Container maxWidth="lg" columns={1}>
|
|
<SectionHeader
|
|
eyebrow="Interactive"
|
|
title="Resize and scroll"
|
|
description="The splitter resolves its size in the runtime and reports it here. The scrolling region themes its own scrollbar."
|
|
headingLevel={3}
|
|
/>
|
|
|
|
<p class="tour-status">
|
|
Drag the divider, or focus it and use the arrow keys. Home and End
|
|
go to the bounds. The live value is on the handle itself, as
|
|
aria-valuenow, which is what a screen reader announces.
|
|
</p>
|
|
|
|
<LayoutSplitter size={45} minSize={20} step={5} label="Resize the panes">
|
|
<div data-slot="start">
|
|
<div class="tour-pane">
|
|
<h4>Start pane</h4>
|
|
<p>Drag the divider, or focus it and use the arrow keys. Home and End go to the bounds.</p>
|
|
</div>
|
|
</div>
|
|
<div data-slot="end">
|
|
<div class="tour-pane">
|
|
<h4>End pane</h4>
|
|
<p>The size is resolved in the runtime and written onto the container, so the panes are plain grid tracks.</p>
|
|
</div>
|
|
</div>
|
|
</LayoutSplitter>
|
|
|
|
<Divider label="scrolling" />
|
|
|
|
<CustomScrollbar maxHeight="12rem" thickness={10}>
|
|
<div class="tour-scroll">
|
|
<p>This region scrolls, and its scrollbar follows the theme.</p>
|
|
<p>Scrollbar appearance is CSS rather than script.</p>
|
|
<p>scrollbar-width and scrollbar-color are the standard properties.</p>
|
|
<p>The webkit rules cover the engines that still need them.</p>
|
|
<p>Enough lines here that the region actually overflows.</p>
|
|
<p>Otherwise there would be no scrollbar to look at.</p>
|
|
<p>Which is the mistake the showcase demo made first time.</p>
|
|
</div>
|
|
</CustomScrollbar>
|
|
</Container>
|
|
</Section>
|
|
</PublicPageShell>
|
|
}
|
|
|
|
style {
|
|
.tour-card {
|
|
padding: 1rem;
|
|
border: 1px solid var(--wrn-color-border);
|
|
border-radius: var(--wrn-radius-md);
|
|
background: var(--wrn-color-surface);
|
|
}
|
|
|
|
.tour-card h4,
|
|
.tour-pane h4 {
|
|
margin: 0 0 0.35rem;
|
|
font-size: 0.95rem;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.tour-card p,
|
|
.tour-pane p,
|
|
.tour-scroll p {
|
|
margin: 0;
|
|
color: var(--wrn-color-text-muted);
|
|
font-size: 0.86rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.tour-card--compact {
|
|
text-align: center;
|
|
}
|
|
|
|
.tour-status {
|
|
margin: 0 0 0.75rem;
|
|
padding: 0.5rem 0.75rem;
|
|
border: 1px solid var(--wrn-color-border);
|
|
border-radius: var(--wrn-radius-sm);
|
|
background: var(--wrn-color-surface-soft);
|
|
color: var(--wrn-color-text-muted);
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
.tour-pane {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.tour-scroll {
|
|
display: grid;
|
|
gap: 0.6rem;
|
|
padding: 0.75rem;
|
|
}
|
|
|
|
/* The splitter panes need a floor or they collapse to their text. */
|
|
.tour-pane,
|
|
.tour-scroll {
|
|
min-height: 8rem;
|
|
}
|
|
}
|
|
}
|