@@ -1,168 +1,330 @@
1+-- A comprehensive tour of htmlang: layout, style, components, and control flow.
1−@page htmlang Showcase
2+@page htmlang Demo
4+@meta description A one-page tour of htmlang.
4−-- Design tokens
8+-- Design tokens become both $vars and CSS custom properties
5−@let primary #3b82f6
10+ primary #3b82f6
7−@let ink #0f172a
11+ ink #0f172a
8−@let muted #64748b
12+ muted #64748b
10−@let bg #f8fafc
13+ subtle #f8fafc
15+-- Computed @let with arithmetic
12@let base 8
16@let base 8
13@let gap = $base * 2
17@let gap = $base * 2
18+@let gutter = $gap + $base
15−-- Style presets
20+-- Reusable attribute bundle
16@define card [
21@define card [
17− padding 24, background $surface, rounded $radius,
22+ padding $gap,
18− border 1 #e2e8f0,
25+ border 1 #e5e7eb,
19− dark:background #1e293b, dark:border 1 #334155
26+ shadow 0 1px 3px rgba(0,0,0,0.05)
29+-- Composable style group (used with spread)
22−@mixin lift [
30+@mixin interactive [
23− transition all 0.2s ease,
31+ cursor pointer,
24− hover:shadow 0 12px 24px rgba(0,0,0,0.08)
32+ hover:shadow 0 4px 12px rgba(0,0,0,0.08),
33+ transition all 0.2s ease
27−-- Components (functions with parameters, defaults, and slots)
36+-- Keyframes using attribute syntax
38+ from [opacity 0, transform translateY(8px)]
39+ to [opacity 1, transform translateY(0)]
41+-- Raw HTML escape hatch
43+<noscript><style>.needs-js{display:none}</style></noscript>
46+-- Component with default parameter + @children slot
47+@fn card $title $icon=◆
48+ @article [$card, ...$interactive, animate fade-up 0.3s ease]
49+ @row [spacing 10, align-items center]
50+ @text [size 20, color $primary] $icon
51+ @text [bold, size 16, color $ink] $title
54+-- Component that wraps children in a titled section (function + slot)
56+ @section [spacing 12, padding-y $base]
57+ @text [bold, size 22, color $ink] $title
67+ dark:background #0b1220,
71+ -- Header: nav + hero
72+ @header [spacing $base]
73+ @nav [spacing 6, color $muted, size 13]
74+ @row [spacing 6, align-items center]
75+ @link [color $muted] / Home
77+ @link [color $muted] /demos Demos
79+ @text [color $ink] htmlang
81+ @row [spacing $gap, align-items center]
82+ @column [width fill, spacing 6]
83+ @text [bold, size 40, color $ink, dark:color white] Welcome to htmlang
84+ @paragraph [line-height 1.6, color $muted]
85+ A minimalist layout language that compiles to
86+ {@text [bold, color $primary] static HTML} — no JS, no build step.
87+ Visit the {@link [color $primary, underline] https://github.com repo} for more.
88+ @image [width 72, height 72, rounded 36, alt "Avatar"] https://picsum.photos/72
90+ @hr [border-top 1 #e5e7eb]
92+ -- Feature grid using @card + @titled components
93+ @titled [title Features]
94+ @row [wrap, gap $base]
95+ @card [title Simple, icon ✦]
96+ Write layouts without CSS classes.
97+ @card [title Fast, icon ⚡]
98+ Compiles to a single self-contained HTML file.
99+ @card [title Minimal, icon ○]
100+ Zero runtime JavaScript by default.
102+ LSP with diagnostics and go-to-definition.
104+ -- Typography showcase: inline elements, blockquote, code
105+ @titled [title Typography]
106+ @paragraph [line-height 1.7]
107+ A quick brown fox jumps over {@text [bold] the lazy} {@text [italic] dog}.
109+ padding 2 6, background #f1f5f9, rounded 4,
110+ font monospace, size 13
111+ ] Ctrl+K} to search. {@mark [background #fef08a] Highlighted} uses mark.
112+ {@abbr [title HyperText Markup Language + language] htmlang} is an abbreviation.
115+ padding-inline-start $gap, border-left 3 $primary,
116+ color $muted, italic
118+ Layout is code. Style is code. Everything should compose.
122+ background #0f172a, color #e2e8f0,
123+ padding 16, rounded 8, font monospace, size 13,
28−@fn button $label $variant=primary
127+@fn button $label
29− @el [
128+ @el [padding 12, background blue]
30− padding 10 20, rounded 8, cursor pointer, bold,
31− background if($variant == primary, $primary, transparent),
32− color if($variant == primary, white, $primary),
33− border 1 $primary, transition all 0.15s ease,
34− hover:opacity 0.9, active:opacity 0.8
36 @text $label
129 @text $label
38−@fn feature $title $emoji
132+ -- Control flow: @each, @else, @repeat, @for, @match, if()
39− @el [$card, ...$lift, spacing 10]
133+ @titled [title Control flow]
40− @text [size 32] $emoji
134+ @column [spacing 6]
41− @text [bold, size 18, color $ink, dark:color #f1f5f9] $title
135+ @each $name, $role in Alice Engineer, Bob Designer, Carol PM
42− @paragraph [color $muted, line-height 1.6]
136+ @row [spacing 10, align-items baseline]
43− @children
137+ @text [bold, min-width 80] $name
44−
138+ @text [color $muted] $role
45−@fn stat $value $label
139+
46− @column [spacing 4, text-align center, padding 12]
140+ -- @each ... @else fallback for empty list
47− @text [bold, size 40, color $primary] $value
141+ @let nothing ""
48− @text [color $muted, size 12, text-transform uppercase, letter-spacing 2] $label
142+ @each $x in $nothing
51−@column [background $bg, dark:background #0f172a, min-height 100vh]
145+ @text [color $muted, italic, data-state $nothing] (Nothing — @each ... @else fallback)
53− -- Header
147+ -- @repeat
54− @header [
148+ @row [spacing 6]
55− padding 16 32, background $surface, dark:background #1e293b,
149+ @repeat 6
56− border-bottom 1 #e2e8f0, dark:border-bottom 1 #334155
150+ @el [width 18, height 18, rounded 9, background $primary, opacity 0.4]
58− @row [center-y, max-width 1100, center-x, width 100%]
152+ -- @for range
59− @text [bold, size 18, color $ink, dark:color #f1f5f9] htmlang
153+ @row [spacing 4]
60− @el [width fill]
154+ @for $i in 1..6
61− @row [spacing 24]
155+ @el [
62− @link [color $muted, hover:color $primary] #docs Docs
156+ width 24, height 24, rounded 4,
63− @link [color $muted, hover:color $primary] #blog Blog
157+ background $primary, color white,
64− @link [color $muted, hover:color $primary] #github GitHub
158+ text-align center, size 12, bold, line-height 24
66− -- Hero
162+ -- @if / @else if / @else (with @assert to verify at compile time)
67− @section [padding 80 32, max-width 900, center-x, text-align center, spacing 20]
163+ @let count 3
165+ @row [spacing 6, align-items center]
166+ @text [bold, min-width 64] Count:
168+ @text [color $muted] Empty
169+ @else if $count == 1
170+ @text [color $primary] Exactly one
172+ @text [color $primary, bold] $count items
178+ @text [color #f59e0b] Pending…
180+ @text [color #10b981, bold] ✓ Ready
182+ @text [color #ef4444] Error
186+ -- Conditional attribute value + before: pseudo-element
187+ @let emphasized true
69− padding 6 14, rounded 999,
189+ padding 12, rounded 6,
70− background $primary|alpha:0.12, color $primary,
190+ background if($emphasized, $primary, #e5e7eb),
71− bold, size 12, text-transform uppercase, letter-spacing 2,
191+ color if($emphasized, white, $ink),
72− before:content "* "
192+ before:content "→ ", before:bold
74− Built with htmlang
194+ Conditional styling via {@code if(cond, a, b)}.
75− @text [bold, size 56, color $ink, dark:color #f1f5f9, line-height 1.1]
195+
76− Layouts that just {@text [italic, color $primary] make sense}.
196+ -- Forms + pseudo-states
197+ @titled [title Forms]
198+ @form [spacing 10, max-width 420] /subscribe
199+ @label [bold, size 13, for email] Email
201+ id email, type email, name email,
202+ placeholder you@example.com, required,
203+ padding 10, border 1 #e5e7eb, rounded 6,
204+ focus:border 1 $primary,
205+ valid:border 1 #10b981,
206+ invalid:border 1 #ef4444,
207+ transition border 0.15s ease
209+ @label [bold, size 13, for role] Role
210+ @select [id role, name role, padding 10, border 1 #e5e7eb, rounded 6]
211+ @option [value dev] Developer
212+ @option [value designer] Designer
213+ @option [value other] Other
214+ @label [bold, size 13, for msg] Message
216+ id msg, name msg, rows 3,
217+ padding 10, border 1 #e5e7eb, rounded 6
222+ padding 10 16, background $primary, color white, bold,
223+ rounded 6, border 0,
224+ hover:background $primary|darken:10,
225+ active:background $primary|darken:20,
226+ transition background 0.15s ease,
231+ padding 10 16, background white,
232+ border 1 #e5e7eb, rounded 6, cursor pointer
234+ @progress [value 60, max 100]
237+ @titled [title Data]
238+ @row [gap $gap, wrap]
239+ @column [width fill, spacing $base, min-width 240]
240+ @text [bold] Unordered
241+ @list [spacing 4, list-style disc, padding-inline-start 20]
242+ @item [display list-item] Composable with @each
243+ @item [display list-item] Indent to nest children
244+ @item [display list-item] Bold list items work too
245+ @text [bold] Ordered
246+ @list [ordered, list-style decimal, padding-inline-start 20]
247+ @item [display list-item] First
248+ @item [display list-item] Second
249+ @item [display list-item] Third
251+ @column [width fill, spacing $base, min-width 240]
256+ @th [text-align left, padding 8] Item
257+ @th [text-align right, padding 8] Qty
260+ @td [padding 8, border-top 1 #e5e7eb] Widgets
261+ @td [padding 8, border-top 1 #e5e7eb, text-align right] 12
263+ @td [padding 8, border-top 1 #e5e7eb] Gadgets
264+ @td [padding 8, border-top 1 #e5e7eb, text-align right] 7
267+ @image [alt "A random placeholder", rounded 8] https://picsum.photos/640/200
268+ @figcaption [color $muted, size 13, text-align center]
269+ A placeholder image.
271+ -- Disclosure + named grid areas
272+ @titled [title Disclosure + grid areas]
273+ @details [padding 12, border 1 #e5e7eb, rounded 6, background $subtle]
274+ @summary [bold, cursor pointer] What is htmlang?
77− @paragraph [max-width 600, center-x, color $muted, line-height 1.7, size 18]
275+ @paragraph [color $muted, line-height 1.6, padding-block-start 6]
78− A minimalist DSL that compiles to a single static HTML file.
276+ htmlang is a layout-first language that compiles to a single,
79− No cascade, no JavaScript, no build chain.
277+ self-contained HTML file with embedded CSS.
80− @row [center-x, spacing 12, wrap]
278+
81− @button [label Get Started]
279+ -- Implicit @el via bare [attrs] line
82− @button [label Star on GitHub, variant ghost]
280+ [
84− -- Stats (each iteration could go here too)
282+ grid-template-columns 1fr 2fr,
85− @section [padding 24 32, max-width 800, center-x]
283+ grid-template-areas "h h" "s m" "f f",
86− @row [wrap, center-x, spacing 20]
284+ gap $base,
87− @stat [value 0kb, label JavaScript]
285+ padding $base, background $subtle, rounded 8
88− @stat [value 1, label HTML File]
89− @stat [value 100%, label Static]
91− -- Features (grid layout)
92− @section [padding 64 32, max-width 1100, center-x, spacing 24]
93− @column [spacing 8, text-align center]
94− @text [bold, size 32, color $ink, dark:color #f1f5f9] Why htmlang?
95− @text [color $muted] Primitives over CSS quirks.
97− @el [grid, grid-cols 3, gap $gap]
98− @feature [title Composable, emoji X]
99− Functions, mixins, and slots make components first-class.
100− @feature [title Predictable, emoji Y]
101− Flex-based layout - no cascade, no surprises.
102− @feature [title Static, emoji Z]
103− One file out. Deploy anywhere. Loads instantly.
105− -- Quote (semantic blockquote + cite)
106− @section [padding 32, max-width 720, center-x]
108− padding 24 32, background $surface, dark:background #1e293b,
109− border-left 4 $primary, rounded $radius, italic,
110− color $ink, dark:color #f1f5f9, line-height 1.7, size 18
112− "I want to lay out an interface, not argue with the cascade."
287+ @el [grid-area h, padding 10, background $primary, color white, rounded 6, text-align center]
113− @cite [color $muted, size 13, italic]
288+ Header
114− - every frontend dev, eventually
289+ @el [grid-area s, padding 10, background white, rounded 6, border 1 #e5e7eb]
116− -- Team (each + destructuring)
291+ @el [grid-area m, padding 10, background white, rounded 6, border 1 #e5e7eb]
117− @section [padding 48 32, max-width 1100, center-x, spacing 16]
292+ Main
118− @text [bold, size 24, color $ink, dark:color #f1f5f9] The team
293+ @el [grid-area f, padding 10, background $ink, color white, rounded 6, text-align center]
120− @row [wrap, spacing 12]
295+
121− @each $name, $role in Ada Engineer, Grace Architect, Linus Maintainer, Ken Researcher
296+ -- Misc: address, time, meter
122− @column [$card, ...$lift, spacing 6, width 200, text-align center]
297+ @titled [title Misc]
123− @text [bold, color $ink, dark:color #f1f5f9] $name
298+ @address [spacing 4, font-style normal]
124− @text [color $muted, size 13] $role
299+ @text [bold] htmlang HQ
125−
300+ @text 123 Flexbox Avenue
126− -- FAQ (native disclosure widget + inline elements)
301+ @link [color $primary] mailto:hi@htmlang.dev hi@htmlang.dev
127− @section [padding 48 32, max-width 720, center-x, spacing 12]
302+ @row [spacing 10, align-items center]
128− @text [bold, size 24, color $ink, dark:color #f1f5f9] FAQ
303+ @text [size 13, color $muted] Published
129−
304+ @time [datetime 2026-04-16, size 13] April 16 2026
131− @summary [bold, color $ink, dark:color #f1f5f9, cursor pointer]
132− Does it support dark mode?
133− @paragraph [color $muted, line-height 1.7]
134− Yes - prefix any style with {@code [background $bg, padding 2 6, rounded 4, color $accent] dark:} and it generates a media query.
137− @summary [bold, color $ink, dark:color #f1f5f9, cursor pointer]
138− How do reusable components work?
139− @paragraph [color $muted, line-height 1.7]
140− Use {@code [background $bg, padding 2 6, rounded 4, color $accent] @fn} for parameters and {@code [background $bg, padding 2 6, rounded 4, color $accent] @children} as a slot.
142− -- Native widgets (progress + meter)
143− @section [padding 48 32, max-width 720, center-x, spacing 16]
144− @text [bold, size 24, color $ink, dark:color #f1f5f9] Native widgets
146− @column [$card, spacing 16]
148− @row [center-y, spacing 12]
305+ @row [spacing 10, align-items center]
149− @text [color $ink, dark:color #f1f5f9] Coverage
306+ @text [size 13, color $muted] Confidence
151− @text [color $muted, size 13] 70%
152− @progress [value 70, max 100, width 100%]
155− @text [color $ink, dark:color #f1f5f9] Battery
156− @meter [value 6, min 0, max 10, low 3, high 8, width 100%]
307+ @meter [value 8, min 0, max 10, low 3, high 7] 8/10
158− -- Footer (hr divider + breadcrumb)
309+ -- Footer: hover/active button, visited link, print-hidden
159− @hr [border-top 1 #e2e8f0, dark:border-top 1 #334155]
310+ @footer [
160− @footer [padding 32, max-width 1100, center-x]
311+ padding-block-start $gutter, margin-block-start $gutter,
161− @row [center-y, wrap, spacing 16, width 100%]
312+ border-top 1 #e5e7eb, spacing $base,
162− @text [color $muted, size 13]
313+ print:display none
163− Made with htmlang.
314+ ]
315+ @row [spacing $base, align-items center]
317+ padding 12 20, background $primary, color white, bold, rounded 8,
318+ hover:background $primary|darken:10,
319+ active:background $primary|darken:20,
320+ transition all 0.15s ease,
322+ ] > @link https://github.com
326+ visited:color #8b5cf6,
328+ ] https://github.com Browse source
164 @el [width fill]
329 @el [width fill]
165− @breadcrumb [spacing 8]
166− @link [color $muted, hover:color $primary] / Home
167− @link [color $muted, hover:color $primary] /docs Docs
168− @text [color $muted, size 13] v1.0
330+ @text [color $muted, size 13] © 2026 htmlang