@zvndev/darkmown 0.19.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +25 -0
- package/README.md +115 -5
- package/docs/spec-alignment.md +16 -3
- package/package.json +22 -4
- package/site/_/base.skin +372 -0
- package/site/_/base.wd +4 -0
- package/site/_/footer.wd +14 -0
- package/site/_/metrics.json +13 -0
- package/site/_/nav.skin +35 -12
- package/site/_/nav.wd +8 -10
- package/site/_/products.json +10 -0
- package/site/pages/app.wd +1 -1
- package/site/pages/carousel/index.js +82 -0
- package/site/pages/carousel/index.skin +185 -0
- package/site/pages/carousel/index.wd +109 -0
- package/site/pages/carousel/slide-1.jpg +0 -0
- package/site/pages/carousel/slide-2.jpg +0 -0
- package/site/pages/carousel/slide-3.jpg +0 -0
- package/site/pages/carousel/slide-4.jpg +0 -0
- package/site/pages/carousel/slide-5.jpg +0 -0
- package/site/pages/compass/index.skin +247 -0
- package/site/pages/compass/index.wd +194 -0
- package/site/pages/docs/index.skin +48 -28
- package/site/pages/docs/index.wd +71 -5
- package/site/pages/folio/-style.skin +375 -0
- package/site/pages/folio/-style.wd +6 -0
- package/site/pages/folio/cart.skin +309 -0
- package/site/pages/folio/cart.wd +201 -0
- package/site/pages/folio/index.skin +24 -0
- package/site/pages/folio/index.wd +167 -0
- package/site/pages/forge/index.skin +676 -0
- package/site/pages/forge/index.wd +330 -0
- package/site/pages/index.skin +135 -144
- package/site/pages/index.wd +17 -5
- package/site/pages/ledger/index.skin +257 -0
- package/site/pages/ledger/index.wd +174 -0
- package/site/pages/media/clip-poster.jpg +0 -0
- package/site/pages/media/clip.mp4 +0 -0
- package/site/pages/media/index.skin +82 -0
- package/site/pages/media/index.wd +84 -0
- package/site/pages/media/tone.mp3 +0 -0
- package/site/pages/pulse/index.skin +434 -0
- package/site/pages/pulse/index.wd +178 -0
- package/site/pages/showcase/index.skin +130 -0
- package/site/pages/showcase/index.wd +168 -0
- package/src/builder.js +20 -14
- package/src/cli.js +216 -77
- package/src/compiler/body.js +457 -0
- package/src/compiler/context.js +160 -0
- package/src/compiler/directives.js +1345 -0
- package/src/compiler/format.js +244 -0
- package/src/compiler/frontmatter.js +117 -0
- package/src/compiler/includes.js +116 -0
- package/src/compiler/index.js +22 -0
- package/src/compiler/interpolation.js +223 -0
- package/src/compiler/loops.js +715 -0
- package/src/compiler/markdown.js +242 -0
- package/src/compiler/page.js +267 -0
- package/src/compiler/predicates.js +314 -0
- package/src/compiler.js +26 -2932
- package/src/dev.js +3 -1
- package/src/headers.js +8 -4
- package/src/index.js +22 -0
- package/src/router.js +3 -1
- package/src/runtime.js +168 -14
- package/src/scaffold.js +158 -131
- package/src/skin.js +11 -2
- package/site/_/og.png +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Folio — your basket
|
|
3
|
+
description: The Folio checkout. The same :store cart shared with the catalog, a per-row remove, and a form that round-trips to a server — all written in Markdown.
|
|
4
|
+
image: https://darkmown.com/__wd/media/og-folio.png
|
|
5
|
+
transitions: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
@include /nav.wd
|
|
9
|
+
@include /base.wd
|
|
10
|
+
@include ./-style.wd
|
|
11
|
+
|
|
12
|
+
<main class="wide app-folio">
|
|
13
|
+
|
|
14
|
+
::: section #checkout
|
|
15
|
+
|
|
16
|
+
:store cart = []
|
|
17
|
+
:computed count = cart.length
|
|
18
|
+
:computed subtotal = sum(cart, price)
|
|
19
|
+
:computed tax = subtotal * 0.08
|
|
20
|
+
:computed total = subtotal * 1.08
|
|
21
|
+
|
|
22
|
+
::: shop-head
|
|
23
|
+
::: shop-mark
|
|
24
|
+
::: shop-eyebrow
|
|
25
|
+
Checkout
|
|
26
|
+
:::
|
|
27
|
+
|
|
28
|
+
# Your *basket*
|
|
29
|
+
|
|
30
|
+
::: shop-tagline
|
|
31
|
+
The same basket you filled on the shelf — it carried over on its own. Review it, then place a test order through a live server round-trip.
|
|
32
|
+
:::
|
|
33
|
+
:::
|
|
34
|
+
|
|
35
|
+
::: cart-peek
|
|
36
|
+
{ count } items
|
|
37
|
+
:::
|
|
38
|
+
:::
|
|
39
|
+
|
|
40
|
+
::: cart-grid
|
|
41
|
+
|
|
42
|
+
::: cart-lines
|
|
43
|
+
|
|
44
|
+
## Items
|
|
45
|
+
|
|
46
|
+
@loop cart into item
|
|
47
|
+
::: card .line
|
|
48
|
+
::: line-emoji
|
|
49
|
+
{ item.emoji }
|
|
50
|
+
:::
|
|
51
|
+
::: line-body
|
|
52
|
+
::: line-name
|
|
53
|
+
{ item.name }
|
|
54
|
+
:::
|
|
55
|
+
::: line-cat
|
|
56
|
+
{ item.category }
|
|
57
|
+
:::
|
|
58
|
+
:::
|
|
59
|
+
::: line-price
|
|
60
|
+
{ item.price | money }
|
|
61
|
+
:::
|
|
62
|
+
:button "Remove" -> cart remove item
|
|
63
|
+
:::
|
|
64
|
+
@empty
|
|
65
|
+
::: card .cart-blank
|
|
66
|
+
**Your basket is empty.**
|
|
67
|
+
|
|
68
|
+
Nothing here yet — the shelf is just a click away.
|
|
69
|
+
|
|
70
|
+
[← Back to the shop](/folio/)
|
|
71
|
+
:::
|
|
72
|
+
@endloop
|
|
73
|
+
|
|
74
|
+
:if count > 0
|
|
75
|
+
::: card .order-summary
|
|
76
|
+
### Order summary
|
|
77
|
+
|
|
78
|
+
::: sum-row
|
|
79
|
+
Subtotal ({ count | pluralize:"item" })
|
|
80
|
+
::: sum-val
|
|
81
|
+
{ subtotal | money }
|
|
82
|
+
:::
|
|
83
|
+
:::
|
|
84
|
+
::: sum-row
|
|
85
|
+
Tax (8%)
|
|
86
|
+
::: sum-val
|
|
87
|
+
{ tax | money }
|
|
88
|
+
:::
|
|
89
|
+
:::
|
|
90
|
+
::: sum-row .sum-total
|
|
91
|
+
**Total**
|
|
92
|
+
::: sum-val
|
|
93
|
+
**{ total | money }**
|
|
94
|
+
:::
|
|
95
|
+
:::
|
|
96
|
+
|
|
97
|
+
:button "Clear basket" -> cart clear
|
|
98
|
+
:::
|
|
99
|
+
:endif
|
|
100
|
+
|
|
101
|
+
:::
|
|
102
|
+
|
|
103
|
+
::: checkout-panel
|
|
104
|
+
|
|
105
|
+
## Place your order
|
|
106
|
+
|
|
107
|
+
This is a real form. With the runtime it posts over `fetch` and shows the reply inline; with JavaScript off, the identical markup degrades to a native POST. The demo endpoint simply echoes your order back.
|
|
108
|
+
|
|
109
|
+
:form action="/__wd/echo" into receipt
|
|
110
|
+
:input name placeholder="Full name" required
|
|
111
|
+
:input email type=email placeholder="you@studio.com" required
|
|
112
|
+
:select shipping
|
|
113
|
+
- Standard — 3-5 days
|
|
114
|
+
- Express — overnight
|
|
115
|
+
- Local pickup
|
|
116
|
+
:submit "Place order"
|
|
117
|
+
:endform
|
|
118
|
+
|
|
119
|
+
:if receipt
|
|
120
|
+
::: card .receipt
|
|
121
|
+
**Order received ✓**
|
|
122
|
+
|
|
123
|
+
Thank you, **{ receipt.received.name }** — a confirmation is on its way to { receipt.received.email }. Shipping: { receipt.received.shipping }.
|
|
124
|
+
|
|
125
|
+
::: receipt-stamp
|
|
126
|
+
Logged by the server at { receipt.at }
|
|
127
|
+
:::
|
|
128
|
+
:::
|
|
129
|
+
:else
|
|
130
|
+
::: checkout-hint
|
|
131
|
+
Fill in your details and place the order to see the server's reply appear right here.
|
|
132
|
+
:::
|
|
133
|
+
:endif
|
|
134
|
+
|
|
135
|
+
:if receipt_error
|
|
136
|
+
::: card .receipt-error
|
|
137
|
+
Something went wrong: { receipt_error }
|
|
138
|
+
:::
|
|
139
|
+
:endif
|
|
140
|
+
|
|
141
|
+
:::
|
|
142
|
+
|
|
143
|
+
:::
|
|
144
|
+
|
|
145
|
+
::: persist-note
|
|
146
|
+
::: dot
|
|
147
|
+
✷
|
|
148
|
+
:::
|
|
149
|
+
This basket is the **same `:store`** declared on the catalog — one name, one shared storage. Remove a line here and it's gone on the shelf too, in every open tab, even after a reload.
|
|
150
|
+
:::
|
|
151
|
+
|
|
152
|
+
<details class="source-reveal">
|
|
153
|
+
<summary>View source — it's Markdown</summary>
|
|
154
|
+
|
|
155
|
+
```wd
|
|
156
|
+
:store cart = []
|
|
157
|
+
:computed count = cart.length
|
|
158
|
+
:computed subtotal = sum(cart, price)
|
|
159
|
+
:computed total = subtotal * 1.08
|
|
160
|
+
|
|
161
|
+
@loop cart into item
|
|
162
|
+
::: card .line
|
|
163
|
+
{ item.emoji } **{ item.name }** — { item.price | money }
|
|
164
|
+
:button "Remove" -> cart remove item
|
|
165
|
+
:::
|
|
166
|
+
@empty
|
|
167
|
+
Your basket is empty.
|
|
168
|
+
@endloop
|
|
169
|
+
|
|
170
|
+
Subtotal ({ count | pluralize:"item" }) — **{ subtotal | money }**
|
|
171
|
+
Total with tax — **{ total | money }**
|
|
172
|
+
|
|
173
|
+
:button "Clear basket" -> cart clear
|
|
174
|
+
|
|
175
|
+
:form action="/__wd/echo" into receipt
|
|
176
|
+
:input name placeholder="Full name" required
|
|
177
|
+
:input email type=email placeholder="you@studio.com" required
|
|
178
|
+
:select shipping
|
|
179
|
+
- Standard — 3-5 days
|
|
180
|
+
- Express — overnight
|
|
181
|
+
- Local pickup
|
|
182
|
+
:submit "Place order"
|
|
183
|
+
:endform
|
|
184
|
+
|
|
185
|
+
:if receipt
|
|
186
|
+
Thank you, { receipt.received.name }!
|
|
187
|
+
:endif
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
</details>
|
|
191
|
+
|
|
192
|
+
::: folio-foot
|
|
193
|
+
Keep browsing —
|
|
194
|
+
[← Back to the shop](/folio/)
|
|
195
|
+
:::
|
|
196
|
+
|
|
197
|
+
:::
|
|
198
|
+
|
|
199
|
+
</main>
|
|
200
|
+
|
|
201
|
+
@include /footer.wd
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* Folio catalog page — thin layer over style.skin (the shared boutique look)
|
|
2
|
+
and /base.wd. Only the catalog-specific header chip lives here. */
|
|
3
|
+
|
|
4
|
+
/* The live basket count, sitting in the storefront header. */
|
|
5
|
+
.app-folio .cart-peek
|
|
6
|
+
display inline-flex
|
|
7
|
+
align-items center
|
|
8
|
+
gap .45rem
|
|
9
|
+
font-family system-ui, -apple-system, "Segoe UI", Roboto, sans-serif
|
|
10
|
+
font-size .82rem
|
|
11
|
+
font-weight 600
|
|
12
|
+
text-transform uppercase
|
|
13
|
+
letter-spacing .08em
|
|
14
|
+
color var(--brand-deep)
|
|
15
|
+
background var(--brand-soft)
|
|
16
|
+
border 1px solid var(--brand)
|
|
17
|
+
padding .5rem .9rem
|
|
18
|
+
radius 999px
|
|
19
|
+
white-space nowrap
|
|
20
|
+
|
|
21
|
+
.app-folio .cart-peek::before
|
|
22
|
+
content "✦"
|
|
23
|
+
font-size .9rem
|
|
24
|
+
color var(--brand)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Folio — a boutique storefront
|
|
3
|
+
description: A multi-page store written in pure Markdown. The cart persists across pages, reloads, and browser tabs; navigation is instant. No framework JavaScript written by hand.
|
|
4
|
+
image: https://darkmown.com/__wd/media/og-folio.png
|
|
5
|
+
transitions: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
@include /nav.wd
|
|
9
|
+
@include /base.wd
|
|
10
|
+
@include ./-style.wd
|
|
11
|
+
|
|
12
|
+
<main class="wide app-folio">
|
|
13
|
+
|
|
14
|
+
::: section #store
|
|
15
|
+
|
|
16
|
+
:store cart = []
|
|
17
|
+
:computed count = cart.length
|
|
18
|
+
:state q = ""
|
|
19
|
+
|
|
20
|
+
::: shop-head
|
|
21
|
+
::: shop-mark
|
|
22
|
+
::: shop-eyebrow
|
|
23
|
+
Objects for everyday rituals
|
|
24
|
+
:::
|
|
25
|
+
|
|
26
|
+
# Fol*i*o
|
|
27
|
+
|
|
28
|
+
::: shop-tagline
|
|
29
|
+
A small, considered shop — eight things, chosen well. Your basket follows you from page to page, through a reload, even into a second tab.
|
|
30
|
+
:::
|
|
31
|
+
:::
|
|
32
|
+
|
|
33
|
+
::: cart-peek
|
|
34
|
+
{ count } in your basket
|
|
35
|
+
:::
|
|
36
|
+
:::
|
|
37
|
+
|
|
38
|
+
::: shop-layout
|
|
39
|
+
|
|
40
|
+
::: shop-main
|
|
41
|
+
|
|
42
|
+
::: shop-search
|
|
43
|
+
:bind q placeholder="Search the shop…"
|
|
44
|
+
|
|
45
|
+
::: shop-hint
|
|
46
|
+
Type to filter the shelf — it narrows as you go, no page reload.
|
|
47
|
+
:::
|
|
48
|
+
:::
|
|
49
|
+
|
|
50
|
+
::: catalog
|
|
51
|
+
@loop /products.json into p where p.name contains q
|
|
52
|
+
::: card .product
|
|
53
|
+
::: chip
|
|
54
|
+
{ p.emoji }
|
|
55
|
+
:::
|
|
56
|
+
::: body
|
|
57
|
+
::: pname
|
|
58
|
+
{ p.name }
|
|
59
|
+
:::
|
|
60
|
+
|
|
61
|
+
::: tag
|
|
62
|
+
{ p.category }
|
|
63
|
+
:::
|
|
64
|
+
|
|
65
|
+
::: blurb
|
|
66
|
+
{ p.blurb }
|
|
67
|
+
:::
|
|
68
|
+
|
|
69
|
+
::: foot
|
|
70
|
+
::: price
|
|
71
|
+
{ p.price | money }
|
|
72
|
+
:::
|
|
73
|
+
:button "Add" -> cart += p
|
|
74
|
+
:::
|
|
75
|
+
:::
|
|
76
|
+
:::
|
|
77
|
+
@empty
|
|
78
|
+
::: card .catalog-empty
|
|
79
|
+
**Nothing on the shelf matches "{ q }".**
|
|
80
|
+
|
|
81
|
+
Try a shorter word, or clear the search to see all eight pieces.
|
|
82
|
+
:::
|
|
83
|
+
@endloop
|
|
84
|
+
:::
|
|
85
|
+
|
|
86
|
+
:::
|
|
87
|
+
|
|
88
|
+
::: cart-rail
|
|
89
|
+
::: rail-eyebrow
|
|
90
|
+
Your basket
|
|
91
|
+
{ count } items
|
|
92
|
+
:::
|
|
93
|
+
|
|
94
|
+
::: rail-count
|
|
95
|
+
{ count }
|
|
96
|
+
:::
|
|
97
|
+
|
|
98
|
+
::: rail-sub
|
|
99
|
+
Saved to this browser. Add a few pieces, then head to checkout when you're ready.
|
|
100
|
+
:::
|
|
101
|
+
|
|
102
|
+
[View basket →](/folio/cart/){.rail-link}
|
|
103
|
+
|
|
104
|
+
::: rail-note
|
|
105
|
+
Persisted with a single `:store cart = []`. The very same line on the cart page shares this basket — no backend, no wiring.
|
|
106
|
+
:::
|
|
107
|
+
:::
|
|
108
|
+
|
|
109
|
+
:::
|
|
110
|
+
|
|
111
|
+
::: persist-note
|
|
112
|
+
::: dot
|
|
113
|
+
✷
|
|
114
|
+
:::
|
|
115
|
+
**Your basket persists across pages, reloads, and tabs.** Open this page in two tabs, add something in one, and watch the count rise in the other — that's a `:store`, synced over the browser's storage event.
|
|
116
|
+
:::
|
|
117
|
+
|
|
118
|
+
## Built from Markdown
|
|
119
|
+
|
|
120
|
+
Every product card, the live search, and the running count are written as plain Markdown with a handful of Darkmown directives. The catalog unrolls from a JSON file; the basket is one shared `:store`. No components, no JSX, no hand-written event handlers.
|
|
121
|
+
|
|
122
|
+
<details class="source-reveal">
|
|
123
|
+
<summary>View source — it's Markdown</summary>
|
|
124
|
+
|
|
125
|
+
```wd
|
|
126
|
+
:store cart = []
|
|
127
|
+
:computed count = cart.length
|
|
128
|
+
:state q = ""
|
|
129
|
+
|
|
130
|
+
:bind q placeholder="Search the shop…"
|
|
131
|
+
|
|
132
|
+
::: catalog
|
|
133
|
+
@loop /products.json into p where p.name contains q
|
|
134
|
+
::: card .product
|
|
135
|
+
::: chip
|
|
136
|
+
{ p.emoji }
|
|
137
|
+
:::
|
|
138
|
+
::: body
|
|
139
|
+
::: pname
|
|
140
|
+
{ p.name }
|
|
141
|
+
:::
|
|
142
|
+
::: foot
|
|
143
|
+
::: price
|
|
144
|
+
{ p.price | money }
|
|
145
|
+
:::
|
|
146
|
+
:button "Add" -> cart += p
|
|
147
|
+
:::
|
|
148
|
+
:::
|
|
149
|
+
:::
|
|
150
|
+
@empty
|
|
151
|
+
Nothing matches "{ q }".
|
|
152
|
+
@endloop
|
|
153
|
+
:::
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
</details>
|
|
157
|
+
|
|
158
|
+
::: folio-foot
|
|
159
|
+
A storefront in two `.wd` files.
|
|
160
|
+
[Open the basket →](/folio/cart/)
|
|
161
|
+
:::
|
|
162
|
+
|
|
163
|
+
:::
|
|
164
|
+
|
|
165
|
+
</main>
|
|
166
|
+
|
|
167
|
+
@include /footer.wd
|