@zvndev/darkmown 0.20.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.
Files changed (57) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +13 -0
  3. package/README.md +115 -5
  4. package/docs/spec-alignment.md +16 -3
  5. package/package.json +3 -3
  6. package/site/_/base.skin +372 -0
  7. package/site/_/base.wd +4 -0
  8. package/site/_/footer.wd +14 -0
  9. package/site/_/metrics.json +13 -0
  10. package/site/_/nav.skin +35 -12
  11. package/site/_/nav.wd +8 -10
  12. package/site/_/products.json +10 -0
  13. package/site/pages/app.wd +1 -1
  14. package/site/pages/carousel/index.js +82 -0
  15. package/site/pages/carousel/index.skin +185 -0
  16. package/site/pages/carousel/index.wd +109 -0
  17. package/site/pages/carousel/slide-1.jpg +0 -0
  18. package/site/pages/carousel/slide-2.jpg +0 -0
  19. package/site/pages/carousel/slide-3.jpg +0 -0
  20. package/site/pages/carousel/slide-4.jpg +0 -0
  21. package/site/pages/carousel/slide-5.jpg +0 -0
  22. package/site/pages/compass/index.skin +247 -0
  23. package/site/pages/compass/index.wd +194 -0
  24. package/site/pages/docs/index.skin +48 -28
  25. package/site/pages/docs/index.wd +71 -5
  26. package/site/pages/folio/-style.skin +375 -0
  27. package/site/pages/folio/-style.wd +6 -0
  28. package/site/pages/folio/cart.skin +309 -0
  29. package/site/pages/folio/cart.wd +201 -0
  30. package/site/pages/folio/index.skin +24 -0
  31. package/site/pages/folio/index.wd +167 -0
  32. package/site/pages/forge/index.skin +676 -0
  33. package/site/pages/forge/index.wd +330 -0
  34. package/site/pages/index.skin +135 -144
  35. package/site/pages/index.wd +17 -5
  36. package/site/pages/ledger/index.skin +257 -0
  37. package/site/pages/ledger/index.wd +174 -0
  38. package/site/pages/media/clip-poster.jpg +0 -0
  39. package/site/pages/media/clip.mp4 +0 -0
  40. package/site/pages/media/index.skin +82 -0
  41. package/site/pages/media/index.wd +84 -0
  42. package/site/pages/media/tone.mp3 +0 -0
  43. package/site/pages/pulse/index.skin +434 -0
  44. package/site/pages/pulse/index.wd +178 -0
  45. package/site/pages/showcase/index.skin +130 -0
  46. package/site/pages/showcase/index.wd +168 -0
  47. package/src/compiler/body.js +26 -1
  48. package/src/compiler/context.js +1 -1
  49. package/src/compiler/directives.js +199 -3
  50. package/src/compiler/format.js +244 -0
  51. package/src/compiler/interpolation.js +35 -1
  52. package/src/compiler/loops.js +95 -24
  53. package/src/compiler/markdown.js +16 -7
  54. package/src/compiler/predicates.js +35 -2
  55. package/src/headers.js +5 -0
  56. package/src/runtime.js +168 -14
  57. package/src/skin.js +9 -1
@@ -0,0 +1,330 @@
1
+ ---
2
+ title: Forge your plan — a live pricing configurator in Markdown
3
+ description: Build your plan, toggle features, adjust the seat count, and watch the price, savings, and upsell hints update instantly. A classic "this needs React" interaction — written as one Markdown file with a reactive :computed pricing engine.
4
+ image: https://darkmown.com/__wd/media/og-forge.png
5
+ transitions: true
6
+ ---
7
+
8
+ @include /nav.wd
9
+ @include /base.wd
10
+
11
+ <main class="wide app-forge">
12
+
13
+ ::: section #forge .forge-shell
14
+ :state base = 20
15
+ :state seats = 3
16
+ :state analytics = false
17
+ :state sso = false
18
+ :state priority = false
19
+
20
+ :computed seatCost = seats*8
21
+ :computed total = base + seats*8 + analytics*25 + sso*50 + priority*40
22
+ :computed annual = total*12
23
+ :computed annualBill = total*10
24
+ :computed annualSaved = total*2
25
+ :computed addons = analytics*25 + sso*50 + priority*40
26
+
27
+ <section class="forge-hero">
28
+ <span class="eyebrow">Build your plan</span>
29
+
30
+ # Forge your plan.
31
+
32
+ A pricing page is usually a React app in disguise — toggles, steppers, a total that recomputes, upsell logic, the works. This one is a single Markdown file. Pick a tier, set your seats, switch features on, and watch the price move.
33
+
34
+ <div class="forge-trust">
35
+ <span class="forge-trust-item">No credit card</span>
36
+ <span class="forge-trust-item">14-day trial</span>
37
+ <span class="forge-trust-item">Cancel anytime</span>
38
+ </div>
39
+ </section>
40
+
41
+ ::: div .forge-layout
42
+
43
+ ::: div .forge-build
44
+
45
+ ## 1 · Choose a tier
46
+
47
+ ::: div .tier-grid
48
+
49
+ ::: card .tier .on when base == 12
50
+ ### Starter
51
+ **$12**/mo base
52
+
53
+ For solo builders and side projects finding their footing.
54
+
55
+ :button "Select Starter" -> base = 12
56
+ :if base == 12
57
+ ::: div .tier-active
58
+ Current tier
59
+ :::
60
+ :endif
61
+ :::
62
+
63
+ ::: card .tier .on when base == 20
64
+ ### Team
65
+ **$20**/mo base
66
+
67
+ The popular pick — for small teams shipping every week.
68
+
69
+ :button "Select Team" -> base = 20
70
+ :if base == 20
71
+ ::: div .tier-active
72
+ Current tier
73
+ :::
74
+ :endif
75
+ :::
76
+
77
+ ::: card .tier .on when base == 40
78
+ ### Business
79
+ **$40**/mo base
80
+
81
+ Scale, controls, and the headroom growing orgs need.
82
+
83
+ :button "Select Business" -> base = 40
84
+ :if base == 40
85
+ ::: div .tier-active
86
+ Current tier
87
+ :::
88
+ :endif
89
+ :::
90
+
91
+ :::
92
+
93
+ ## 2 · Set your seats
94
+
95
+ Every plan includes a generous base; each additional seat is a flat **$8/mo**. The stepper is just `:button` actions on a `:state` number.
96
+
97
+ ::: card .seats-card
98
+
99
+ ::: div .seat-stepper
100
+ :button "–" -> seats -= 1
101
+ ::: div .seat-count
102
+ **{ seats }** seats
103
+ :::
104
+ :button "+" -> seats++
105
+ :::
106
+
107
+ ::: div .seat-meta
108
+ That's **${ seatCost }/mo** in seats right now.
109
+ :::
110
+
111
+ :if seats > 25
112
+ ::: div .seat-hint
113
+ At 25+ seats, talk to us — volume pricing kicks in.
114
+ :::
115
+ :endif
116
+ :::
117
+
118
+ ## 3 · Add features
119
+
120
+ Toggle the capabilities you need. Each card lights up when it's on and folds straight into the total.
121
+
122
+ ::: div .feature-grid
123
+
124
+ ::: card .feature .on when analytics
125
+ ::: div .feature-head
126
+ ### Advanced analytics
127
+ **+$25**/mo
128
+ :::
129
+
130
+ Funnels, retention cohorts, and a real-time dashboard your whole team can read.
131
+
132
+ :if analytics
133
+ ::: div .feature-state .is-on
134
+ On — counted in your total
135
+ :::
136
+ :button "Remove" -> analytics toggle
137
+ :else
138
+ :button "Add analytics" -> analytics toggle
139
+ :endif
140
+ :::
141
+
142
+ ::: card .feature .on when sso
143
+ ::: div .feature-head
144
+ ### SSO & SAML
145
+ **+$50**/mo
146
+ :::
147
+
148
+ One-click sign-in with Okta, Google Workspace, or Entra — plus SCIM provisioning.
149
+
150
+ :if sso
151
+ ::: div .feature-state .is-on
152
+ On — counted in your total
153
+ :::
154
+ :button "Remove" -> sso toggle
155
+ :else
156
+ :button "Add SSO" -> sso toggle
157
+ :endif
158
+ :::
159
+
160
+ ::: card .feature .on when priority
161
+ ::: div .feature-head
162
+ ### Priority support
163
+ **+$40**/mo
164
+ :::
165
+
166
+ A private channel, a named engineer, and a one-hour first-response SLA.
167
+
168
+ :if priority
169
+ ::: div .feature-state .is-on
170
+ On — counted in your total
171
+ :::
172
+ :button "Remove" -> priority toggle
173
+ :else
174
+ :button "Add priority" -> priority toggle
175
+ :endif
176
+ :::
177
+
178
+ :::
179
+
180
+ ::: div .forge-hints
181
+ :if sso and not priority
182
+ ::: div .hint .hint-suggest
183
+ Teams that turn on **SSO** almost always add **Priority support** — fewer locked-out admins at 2am.
184
+ :::
185
+ :endif
186
+ :if analytics and total > 120
187
+ ::: div .hint .hint-good
188
+ Nice stack. With analytics on a plan this size, most teams see ROI inside the first month.
189
+ :::
190
+ :endif
191
+ :if total > 150
192
+ ::: div .hint .hint-unlock
193
+ You've unlocked the **annual discount** — pay yearly and two months are on us.
194
+ :::
195
+ :endif
196
+ :if total <= 80
197
+ ::: div .hint
198
+ Just the essentials so far. Add a feature above to see how the total moves.
199
+ :::
200
+ :endif
201
+ :::
202
+
203
+ :::
204
+
205
+ ::: aside .forge-summary
206
+ ::: div .summary-card
207
+
208
+ ### Your plan
209
+
210
+ ::: div .price-block
211
+ ::: div .price-now
212
+ **${ total }**
213
+ :::
214
+ ::: div .price-unit
215
+ per month
216
+ :::
217
+ :::
218
+
219
+ ::: div .summary-lines
220
+ ::: div .summary-line
221
+ Base plan · ${ base }/mo
222
+ :::
223
+ ::: div .summary-line
224
+ { seats } seats · ${ seatCost }/mo
225
+ :::
226
+ ::: div .summary-line
227
+ Add-ons · ${ addons }/mo
228
+ :::
229
+ :::
230
+
231
+ ::: div .annual-block
232
+ Billed annually: **${ annualBill }/yr** — you save **${ annualSaved }** vs. monthly.
233
+ :::
234
+
235
+ ::: div .summary-cta
236
+ :button "Reset everything" -> base reset; seats reset; analytics reset; sso reset; priority reset
237
+ :::
238
+
239
+ A month-to-month list price would run **${ annual }/yr**. Choose yearly at checkout to lock the discount.
240
+ :::
241
+ :::
242
+
243
+ :::
244
+
245
+ ## 4 · Start your trial
246
+
247
+ Drop in your details and we'll spin up your **${ total }/mo** workspace — no charge for 14 days.
248
+
249
+ ::: div .checkout-card
250
+ :form action="/__wd/echo" into receipt
251
+ :input name placeholder="Your name"
252
+ :input email placeholder="Work email"
253
+ :submit "Start 14-day trial"
254
+ :endform
255
+
256
+ :if receipt
257
+ ::: div .receipt
258
+ ### You're in 🎉
259
+
260
+ We've reserved your plan at **${ total }/mo** ({ seats } seats). Confirmation sent at **{ receipt.at }** — check your inbox to finish setup.
261
+ :::
262
+ :else
263
+ ::: div .checkout-note
264
+ Your plan today: **${ total }/mo** · billed annually at **${ annualBill }/yr**. You can change tiers or seats any time.
265
+ :::
266
+ :endif
267
+
268
+ :if receipt_error
269
+ ::: div .checkout-error
270
+ Something went wrong: { receipt_error }
271
+ :::
272
+ :endif
273
+ :::
274
+
275
+ ---
276
+
277
+ ## It's just Markdown
278
+
279
+ No JSX, no `useState`, no pricing library. The tier buttons, the seat stepper, the feature toggles, the live total, the upsell hints, and the checkout are all directives in one `.wd` file. The pricing engine is a single `:computed` line:
280
+
281
+ <details class="source-reveal"><summary>View source — it's Markdown</summary>
282
+
283
+ ```wd
284
+ :state base = 20
285
+ :state seats = 3
286
+ :state analytics = false
287
+ :state sso = false
288
+ :state priority = false
289
+
290
+ :computed total = base + seats*8 + analytics*25 + sso*50 + priority*40
291
+ :computed annualBill = total*10
292
+ :computed annualSaved = total*2
293
+
294
+ The price is ${ total }/mo.
295
+
296
+ ::: card .tier .on when base == 20
297
+ :button "Select Team" -> base = 20
298
+ :::
299
+
300
+ :button "–" -> seats -= 1
301
+ :button "+" -> seats++
302
+
303
+ ::: card .feature .on when analytics
304
+ :if analytics
305
+ :button "Remove" -> analytics toggle
306
+ :else
307
+ :button "Add analytics" -> analytics toggle
308
+ :endif
309
+ :::
310
+
311
+ :if sso and not priority
312
+ Teams that turn on SSO almost always add Priority support.
313
+ :endif
314
+
315
+ :if total > 150
316
+ You've unlocked the annual discount.
317
+ :endif
318
+
319
+ :button "Reset everything" -> base reset; seats reset; analytics reset; sso reset; priority reset
320
+ ```
321
+
322
+ </details>
323
+
324
+ Booleans coerce in arithmetic, so `analytics*25` is `25` when the toggle is on and `0` when it's off — that one rule is the whole pricing engine. [Read the docs](/docs/) or [see the reactive page](/reactive/).
325
+
326
+ :::
327
+
328
+ </main>
329
+
330
+ @include /footer.wd
@@ -1,140 +1,65 @@
1
- tokens
2
- ink #171717
3
- paper #fbfaf7
4
- panel #ffffff
5
- line #dedbd3
6
- accent #16645a
7
- warm #a83f2a
8
- muted #666158
9
- gap 1rem
10
- radius 8px
1
+ /* Landing page — layers on /base.wd (tokens, type, components, dark mode).
2
+ Only landing-specific layout lives here. */
11
3
 
12
- page
13
- margin 0
14
- font ui-serif, Georgia, Cambria, serif
15
- color $ink
16
- bg $paper
17
- line-height 1.6
18
- padding 0 0 4rem
4
+ /* ── Hero ───────────────────────────────────────────────────────── */
19
5
 
20
6
  .hero
21
- display flex
22
- flex-direction column
23
- align-items flex-start
24
- justify-content center
25
- padding 2.5rem 0 2.25rem
7
+ padding 3.5rem 0 2.75rem
26
8
  border-bottom 1px solid $line
27
9
  margin-bottom 2.5rem
28
10
 
29
- .hero > p:not(.eyebrow)
30
- max-width 70ch
31
- margin .75rem 0 1.5rem
32
-
33
- .eyebrow
34
- color $accent
35
- text-transform uppercase
36
- letter-spacing .08em
37
- font-size .78rem
38
- margin 0
39
-
40
- main
41
- max-width 920px
42
- margin 0 auto
43
- padding 0 2rem 2rem
44
-
45
- h1
46
- font-size clamp(2.4rem, 6vw, 5rem)
47
- line-height .95
48
- margin .75rem 0 1rem
49
- max-width 14ch
50
-
51
- h2
52
- margin-top 2.75rem
53
- border-bottom 1px solid $line
54
- padding-bottom .35rem
11
+ .hero h1
12
+ max-width 16ch
55
13
 
56
- a
14
+ .hero h1 em
15
+ font-style italic
57
16
  color $accent
58
17
 
59
- .btn
60
- display inline-block
61
- margin .5rem .5rem .5rem 0
62
- padding .75rem 1rem
63
- border 1px solid $line
64
- radius $radius
65
- bg $panel
66
- text-decoration none
67
-
68
- .btn.primary
69
- bg $ink
70
- color white
71
- border 1px solid $ink
72
-
73
- .note
74
- border 1px solid $line
75
- bg $panel
76
- padding 1rem
77
- radius $radius
18
+ .hero > p
19
+ max-width 64ch
20
+ font-size 1.18rem
21
+ color $ink-soft
22
+ margin 1rem 0 1.75rem
78
23
 
79
- .try-card
80
- display inline-flex
81
- align-items center
82
- gap .65rem
83
- margin .35rem .5rem .35rem 0
84
- padding .75rem 1rem
85
- border 1px solid $line
86
- radius $radius
87
- bg $panel
88
- text-decoration none
89
-
90
- .try-card span
91
- color white
92
- bg $accent
93
- padding .1rem .45rem
24
+ .hero .eyebrow
25
+ background $accent-soft
26
+ padding .3rem .7rem
94
27
  radius 999px
95
28
 
96
- .feature-card
97
- display grid
98
- gap .35rem
99
- margin 1rem 0
100
- padding 1rem
101
- bg $panel
102
- border 1px solid $line
103
- radius $radius
104
-
105
- .feature-card strong
106
- color $warm
107
-
108
- .pulse-button
109
- border 0
110
- bg $ink
111
- color white
112
- padding .85rem 1rem
113
- radius $radius
114
- font inherit
115
- cursor pointer
116
-
117
- .pulse-button.is-on
118
- bg $warm
29
+ .hero-cta
30
+ display flex
31
+ flex-wrap wrap
32
+ margin-bottom 2rem
119
33
 
120
- .sprint-board
34
+ .hero-stats
121
35
  display grid
122
- grid-template-columns repeat(auto-fit, minmax(130px, 1fr))
123
- gap $gap
124
- margin 1rem 0
36
+ grid-template-columns repeat(4, auto)
37
+ gap 1.25rem 2.5rem
38
+ list-style none
39
+ padding 0
40
+ margin 0
41
+ border-top 1px solid $line-soft
42
+ padding-top 1.5rem
125
43
 
126
- .sprint-board article
127
- bg $panel
128
- border 1px solid $line
129
- padding 1rem
130
- radius $radius
44
+ .hero-stats li
45
+ display flex
46
+ flex-direction column
131
47
 
132
- .sprint-board span
133
- display block
48
+ .hero-stats strong
49
+ font-size 1.6rem
134
50
  color $accent
135
- font-size .9rem
51
+ letter-spacing -.02em
52
+
53
+ .hero-stats span
54
+ font-size .82rem
55
+ color $muted
56
+ max-width 18ch
57
+
58
+ @media (max-width: 720px)
59
+ .hero-stats
60
+ grid-template-columns 1fr 1fr
136
61
 
137
- /* ── vs-Markdoc comparison ───────────────────────────────────────── */
62
+ /* ── vs-Markdoc comparison ──────────────────────────────────────── */
138
63
 
139
64
  .versus
140
65
  display grid
@@ -147,15 +72,15 @@ a
147
72
  border 1px solid $line
148
73
  radius $radius
149
74
  bg $panel
150
- padding 1.25rem 1.25rem 1.1rem
75
+ padding 1.35rem
151
76
  display flex
152
77
  flex-direction column
153
78
  min-width 0
79
+ box-shadow 0 1px 2px rgba(28,24,20,.04)
154
80
 
155
81
  .vs-card.vs-dark
156
- bg #fbf7ef
157
- border 1px solid #e3d8c4
158
- box-shadow 0 1px 0 #efe7d6
82
+ background linear-gradient(180deg, $accent-soft, $panel)
83
+ border 1px solid $accent
159
84
 
160
85
  .vs-head
161
86
  display flex
@@ -179,7 +104,7 @@ a
179
104
 
180
105
  .vs-tag-md
181
106
  color $muted
182
- bg #efece3
107
+ bg $sunk
183
108
  border 1px solid $line
184
109
 
185
110
  .vs-sub
@@ -189,7 +114,7 @@ a
189
114
 
190
115
  .vs-card pre
191
116
  margin .25rem 0 0
192
- font-size .82rem
117
+ font-size .8rem
193
118
  line-height 1.55
194
119
 
195
120
  .vs-live-label
@@ -199,21 +124,22 @@ a
199
124
  font-style italic
200
125
 
201
126
  .vs-live
202
- border 1px dashed #cdbfa6
203
- radius $radius
204
- bg #fffdf8
127
+ border 1px dashed $accent
128
+ radius $radius-sm
129
+ background color-mix(in srgb, $accent-soft 50%, $panel)
205
130
  padding 1rem 1.1rem .85rem
206
131
  margin .15rem 0 0
207
132
 
208
133
  .vs-live input[data-wd-bind-input]
209
134
  width 100%
210
135
  box-sizing border-box
211
- font inherit
136
+ font-family inherit
212
137
  font-size .95rem
213
138
  padding .55rem .7rem
214
139
  border 1px solid $line
215
- radius 6px
216
- bg white
140
+ radius 8px
141
+ bg $panel
142
+ color $ink
217
143
  margin 0 0 .75rem
218
144
 
219
145
  .vs-live .product
@@ -225,7 +151,7 @@ a
225
151
  margin .35rem 0
226
152
  bg $panel
227
153
  border 1px solid $line
228
- radius 6px
154
+ radius 8px
229
155
  font-size .95rem
230
156
 
231
157
  .vs-live .product p
@@ -235,15 +161,15 @@ a
235
161
  border 0
236
162
  bg $accent
237
163
  color white
238
- font inherit
164
+ font-family inherit
239
165
  font-size .82rem
240
- padding .35rem .7rem
241
- radius 6px
166
+ padding .4rem .8rem
167
+ radius 999px
242
168
  cursor pointer
243
169
  flex-shrink 0
244
170
 
245
171
  .vs-live .product button:hover
246
- bg #11514a
172
+ bg $accent-deep
247
173
 
248
174
  .vs-live > p:last-of-type
249
175
  margin .85rem 0 0
@@ -253,8 +179,8 @@ a
253
179
  margin 1rem 0 0
254
180
  padding 1rem 1.1rem
255
181
  border-left 3px solid $warm
256
- bg #fcf4ef
257
- radius 6px
182
+ bg $warm-soft
183
+ radius 8px
258
184
 
259
185
  .vs-needs strong
260
186
  color $warm
@@ -277,9 +203,14 @@ a
277
203
  font-size .95rem
278
204
 
279
205
  .vs-card.vs-dark .vs-caption
280
- color $accent
206
+ color $accent-deep
207
+
208
+ @media (max-width: 720px)
209
+ .versus
210
+ grid-template-columns 1fr
211
+ gap 1rem
281
212
 
282
- /* Secondary value-prop row, demoted below the comparison */
213
+ /* ── Secondary value props ──────────────────────────────────────── */
283
214
 
284
215
  .props
285
216
  margin 1.5rem 0 0
@@ -287,7 +218,67 @@ a
287
218
  .props h2
288
219
  margin-top 1.5rem
289
220
 
290
- @media (max-width: 720px)
291
- .versus
292
- grid-template-columns 1fr
293
- gap 1rem
221
+ /* ── Demo-directive widgets (`:try`, feature-card include, index.js) ─ */
222
+
223
+ .try-card
224
+ display inline-flex
225
+ align-items center
226
+ gap .65rem
227
+ margin .35rem .5rem .35rem 0
228
+ padding .75rem 1rem
229
+ border 1px solid $line
230
+ radius 999px
231
+ bg $panel
232
+ text-decoration none
233
+ color $ink
234
+
235
+ .try-card:hover
236
+ border-color $accent
237
+
238
+ .try-card span
239
+ color white
240
+ bg $accent
241
+ padding .1rem .5rem
242
+ radius 999px
243
+ font-size .8rem
244
+
245
+ .feature-card
246
+ display grid
247
+ gap .35rem
248
+ margin 1rem 0
249
+ padding 1.1rem 1.25rem
250
+ bg $panel
251
+ border 1px solid $line
252
+ radius $radius
253
+
254
+ .feature-card strong
255
+ color $warm
256
+
257
+ .pulse-button
258
+ border 0
259
+ bg $ink
260
+ color $paper
261
+ padding .85rem 1.15rem
262
+ radius 999px
263
+ font-family inherit
264
+ cursor pointer
265
+
266
+ .pulse-button.is-on
267
+ bg $warm
268
+
269
+ .sprint-board
270
+ display grid
271
+ grid-template-columns repeat(auto-fit, minmax(130px, 1fr))
272
+ gap 1rem
273
+ margin 1rem 0
274
+
275
+ .sprint-board article
276
+ bg $panel
277
+ border 1px solid $line
278
+ padding 1rem
279
+ radius $radius
280
+
281
+ .sprint-board span
282
+ display block
283
+ color $accent
284
+ font-size .9rem