@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,434 @@
1
+ /* ===================================================================
2
+ Pulse — a dark, glassy observability dashboard.
3
+ Layers on /base.wd (tokens, type, components). Everything here is
4
+ scoped under `.app-pulse` so the dashboard owns its own dark surface
5
+ and cyan/mint accent without leaking into the rest of the site.
6
+ Dark-first by design, but legible in light mode too.
7
+ =================================================================== */
8
+
9
+ /* ── Accent + local dark surface (scoped, never global) ─────────────
10
+ The dashboard paints its own deep panels so it reads "premium
11
+ observability tool" even in OS light mode. Numbers go mono. */
12
+
13
+ .app-pulse
14
+ --brand #18b89a
15
+ --brand-dim #0e8d77
16
+ --ok #2bd4a8
17
+ --warn #f0b429
18
+ --down #ff6b6b
19
+ --surface #0d1117
20
+ --surface-2 #131a23
21
+ --surface-3 #1a232e
22
+ --hair #243140
23
+ --hair-soft #1b2531
24
+ --txt #e7eef5
25
+ --txt-soft #aab7c4
26
+ --txt-mute #6b7a89
27
+ --mono ui-monospace, "SF Mono", SFMono-Regular, "JetBrains Mono", Menlo, Consolas, monospace
28
+ color $txt
29
+
30
+ @media (prefers-color-scheme: dark)
31
+ .app-pulse
32
+ --brand #2fe0c0
33
+ --surface #0a0e14
34
+ --surface-2 #10161f
35
+ --surface-3 #161f2a
36
+
37
+ /* The wrapper itself becomes the dark canvas with a faint radial glow. */
38
+ .app-pulse
39
+ background radial-gradient(1200px 600px at 80% -10%, rgba(47,224,192,.08), transparent 60%), $surface
40
+ border 1px solid $hair
41
+ border-radius 18px
42
+ padding 1.75rem 1.9rem 2.1rem
43
+ margin-top 1.5rem
44
+ box-shadow 0 30px 80px -40px rgba(0,0,0,.7)
45
+
46
+ .app-pulse h1
47
+ color $txt
48
+ letter-spacing -.02em
49
+ margin 0
50
+
51
+ .app-pulse a
52
+ color $brand
53
+
54
+ .app-pulse strong
55
+ color $txt
56
+
57
+ .app-pulse code
58
+ background $surface-3
59
+ color $brand
60
+ border 1px solid $hair
61
+
62
+ /* ── Masthead ───────────────────────────────────────────────────── */
63
+
64
+ .pulse-head
65
+ display flex
66
+ flex-wrap wrap
67
+ align-items center
68
+ justify-content space-between
69
+ gap 1rem
70
+ padding-bottom 1.25rem
71
+ border-bottom 1px solid $hair
72
+
73
+ .pulse-id
74
+ display flex
75
+ align-items center
76
+ gap .85rem
77
+
78
+ .pulse-mark
79
+ width 2.4rem
80
+ height 2.4rem
81
+ border-radius 12px
82
+ background linear-gradient(145deg, $brand, $brand-dim)
83
+ display inline-flex
84
+ align-items center
85
+ justify-content center
86
+ font-size 1.3rem
87
+ box-shadow 0 0 0 1px rgba(47,224,192,.4), 0 8px 24px -8px rgba(47,224,192,.5)
88
+ flex-shrink 0
89
+
90
+ .pulse-name
91
+ font-size 1.7rem
92
+ font-weight 700
93
+ letter-spacing -.03em
94
+ line-height 1
95
+ color $txt
96
+
97
+ .pulse-sub
98
+ margin .35rem 0 0
99
+ font-size .82rem
100
+ color $txt-soft
101
+ font-family $mono
102
+
103
+ .pulse-actions
104
+ display flex
105
+ align-items center
106
+ gap .75rem
107
+
108
+ /* The live status line: a pulsing dot + monospace label. */
109
+ .pulse-live
110
+ display inline-flex
111
+ align-items center
112
+ gap .5rem
113
+ font-family $mono
114
+ font-size .78rem
115
+ letter-spacing .1em
116
+ text-transform uppercase
117
+ color $txt-soft
118
+ padding .45rem .8rem
119
+ background $surface-2
120
+ border 1px solid $hair
121
+ border-radius 999px
122
+
123
+ .pulse-live .dot
124
+ width .5rem
125
+ height .5rem
126
+ border-radius 50%
127
+ background $ok
128
+ box-shadow 0 0 0 0 rgba(43,212,168,.55)
129
+ animation pulse-beat 2s infinite
130
+
131
+ /* ── Toolbar (summary line + refresh) ───────────────────────────── */
132
+
133
+ .pulse-bar
134
+ display flex
135
+ flex-wrap wrap
136
+ align-items center
137
+ justify-content space-between
138
+ gap .75rem
139
+ margin 1.25rem 0 .25rem
140
+
141
+ .pulse-summary
142
+ font-family $mono
143
+ font-size .85rem
144
+ color $txt-soft
145
+
146
+ .pulse-summary p
147
+ margin 0
148
+
149
+ .app-pulse .btn
150
+ background $surface-2
151
+ color $txt
152
+ border 1px solid $hair
153
+ font-size .85rem
154
+ padding .5rem 1rem
155
+ box-shadow none
156
+
157
+ .app-pulse .btn:hover
158
+ border-color $brand
159
+ color $txt
160
+ transform translateY(-1px)
161
+ box-shadow 0 6px 18px -10px rgba(47,224,192,.6)
162
+
163
+ /* ── Stat cards (rollups) — one tidy row ────────────────────────── */
164
+
165
+ .pulse-stats
166
+ display grid
167
+ grid-template-columns repeat(4, 1fr)
168
+ gap .85rem
169
+ margin 1rem 0 1.5rem
170
+
171
+ @media (max-width: 720px)
172
+ .pulse-stats
173
+ grid-template-columns 1fr 1fr
174
+
175
+ .stat
176
+ background linear-gradient(180deg, $surface-2, $surface)
177
+ border 1px solid $hair
178
+ border-radius 12px
179
+ padding .9rem 1rem
180
+ position relative
181
+ overflow hidden
182
+
183
+ .stat::after
184
+ content ""
185
+ position absolute
186
+ inset 0 auto 0 0
187
+ width 3px
188
+ background $brand
189
+ opacity .55
190
+
191
+ /* Label = the first <p><strong> the directive emits for `**Label**`. */
192
+ .stat > p
193
+ margin 0
194
+
195
+ .stat > p:first-child
196
+ font-size .68rem
197
+ text-transform uppercase
198
+ letter-spacing .1em
199
+ color $txt-mute
200
+ margin-bottom .4rem
201
+
202
+ .stat > p:first-child strong
203
+ font-weight 600
204
+ color $txt-mute
205
+
206
+ .stat .stat-value
207
+ font-family $mono
208
+ font-size 1.6rem
209
+ font-weight 600
210
+ letter-spacing -.02em
211
+ color $txt
212
+ line-height 1
213
+
214
+ .stat .stat-value p
215
+ margin 0
216
+
217
+ /* Foot = the trailing caption paragraph after the value block. */
218
+ .stat > p:last-child
219
+ margin-top .4rem
220
+ font-size .72rem
221
+ color $txt-soft
222
+ font-family $mono
223
+ line-height 1.4
224
+
225
+ .stat.is-ok::after
226
+ background $ok
227
+ .stat.is-warn::after
228
+ background $warn
229
+ .stat.is-down::after
230
+ background $down
231
+
232
+ .stat.is-ok .stat-value
233
+ color $ok
234
+ .stat.is-warn .stat-value
235
+ color $warn
236
+ .stat.is-down .stat-value
237
+ color $down
238
+
239
+ /* ── Lifecycle states (loading / error / empty) — one quiet line ── */
240
+
241
+ .pulse-state
242
+ display flex
243
+ align-items center
244
+ gap .65rem
245
+ padding .7rem 1rem
246
+ border-radius 10px
247
+ border 1px solid $hair
248
+ background $surface-2
249
+ font-family $mono
250
+ font-size .82rem
251
+ color $txt-soft
252
+ margin .75rem 0 0
253
+
254
+ .pulse-state p
255
+ margin 0
256
+
257
+ .pulse-state.is-error
258
+ border-color rgba(255,107,107,.5)
259
+ background rgba(255,107,107,.08)
260
+ color $down
261
+
262
+ .pulse-state.is-empty
263
+ border-style dashed
264
+ color $txt-mute
265
+
266
+ .pulse-spin
267
+ width 1rem
268
+ height 1rem
269
+ border-radius 50%
270
+ border 2px solid $hair
271
+ border-top-color $brand
272
+ animation pulse-spin .8s linear infinite
273
+ flex-shrink 0
274
+ display inline-block
275
+
276
+ /* ── Services table — aligned rows, monospace numerics ──────────── */
277
+
278
+ .svc-table
279
+ border 1px solid $hair
280
+ border-radius 14px
281
+ overflow hidden
282
+ background $surface-2
283
+
284
+ /* Shared column grid: status · name · latency · uptime · region.
285
+ Applied to BOTH the header and every loop row so columns line up. */
286
+ .svc-row
287
+ display grid
288
+ grid-template-columns 7.5rem minmax(8rem, 1fr) 6.5rem 6rem 5rem
289
+ align-items center
290
+ gap 1rem
291
+ padding .7rem 1.1rem
292
+ border-top 1px solid $hair-soft
293
+
294
+ .svc-head
295
+ border-top none
296
+ background $surface-3
297
+ font-family $mono
298
+ font-size .68rem
299
+ text-transform uppercase
300
+ letter-spacing .1em
301
+ color $txt-mute
302
+
303
+ .svc-head .c-num
304
+ text-align right
305
+
306
+ /* Each loop row arrives wrapped in <div data-wd-loop-piece>; reset that
307
+ wrapper so rows stack flush and the grid lives on .svc-row itself. */
308
+ .app-pulse [data-wd-loop-out]
309
+ display block
310
+
311
+ .app-pulse [data-wd-loop-piece]
312
+ display block
313
+
314
+ .app-pulse .svc-row:not(.svc-head)
315
+ transition background .15s ease
316
+
317
+ .app-pulse [data-wd-loop-piece]:first-child .svc-row
318
+ border-top none
319
+
320
+ .app-pulse .svc-row:not(.svc-head):hover
321
+ background $surface-3
322
+
323
+ .app-pulse .svc-row p
324
+ margin 0
325
+
326
+ /* Status cell: a colored dot + a small pill, both driven by `.class when`. */
327
+ .c-status
328
+ display flex
329
+ align-items center
330
+ gap .55rem
331
+
332
+ .c-status .dot
333
+ width .6rem
334
+ height .6rem
335
+ border-radius 50%
336
+ background $txt-mute
337
+ flex-shrink 0
338
+
339
+ .app-pulse .svc-ok .c-status .dot
340
+ background $ok
341
+ .app-pulse .svc-warn .c-status .dot
342
+ background $warn
343
+ .app-pulse .svc-down .c-status .dot
344
+ background $down
345
+ box-shadow 0 0 10px $down
346
+
347
+ .app-pulse .svc-row .pill
348
+ font-family $mono
349
+ font-size .68rem
350
+ letter-spacing .06em
351
+ padding .12rem .5rem
352
+ border-radius 999px
353
+ background $surface-3
354
+ color $txt-soft
355
+ border 1px solid $hair
356
+
357
+ .app-pulse .svc-ok .pill
358
+ background rgba(43,212,168,.14)
359
+ color $ok
360
+ border-color rgba(43,212,168,.4)
361
+
362
+ .app-pulse .svc-warn .pill
363
+ background rgba(240,180,41,.14)
364
+ color $warn
365
+ border-color rgba(240,180,41,.4)
366
+
367
+ .app-pulse .svc-down .pill
368
+ background rgba(255,107,107,.16)
369
+ color $down
370
+ border-color rgba(255,107,107,.45)
371
+
372
+ /* Name column. */
373
+ .c-name strong
374
+ font-size .95rem
375
+ color $txt
376
+
377
+ /* Numeric columns — monospace, right-aligned. */
378
+ .c-num
379
+ font-family $mono
380
+ font-size .9rem
381
+ color $txt
382
+ text-align right
383
+ font-variant-numeric tabular-nums
384
+
385
+ .app-pulse .svc-warn .c-num.is-latency
386
+ color $warn
387
+ .app-pulse .svc-down .c-num.is-latency
388
+ color $down
389
+
390
+ /* Region column. */
391
+ .c-region
392
+ font-family $mono
393
+ font-size .76rem
394
+ letter-spacing .08em
395
+ text-transform uppercase
396
+ color $txt-mute
397
+ text-align right
398
+
399
+ /* An empty feed renders the @empty branch instead of rows. */
400
+ .svc-table .pulse-state
401
+ margin 0
402
+ border none
403
+ border-radius 0
404
+
405
+ /* ── Source reveal (dark variant) ───────────────────────────────── */
406
+
407
+ .app-pulse .source-reveal
408
+ background $surface-2
409
+ border 1px solid $hair
410
+ margin-top 1.75rem
411
+
412
+ .app-pulse .source-reveal summary
413
+ color $brand
414
+
415
+ .app-pulse .source-reveal pre
416
+ background #060a0f
417
+ box-shadow inset 0 0 0 1px $hair
418
+
419
+ /* Animations (@keyframes pulse-beat / pulse-spin) and the
420
+ prefers-reduced-motion guard live in an inline <style> in index.wd,
421
+ because the .skin compiler emits one rule per declaration — which
422
+ would split a multi-stop @keyframes into separate (last-wins) blocks. */
423
+
424
+ /* ── Responsive ─────────────────────────────────────────────────── */
425
+
426
+ @media (max-width: 600px)
427
+ .app-pulse
428
+ padding 1.4rem 1.1rem 1.8rem
429
+ .svc-row
430
+ grid-template-columns 5rem minmax(6rem, 1fr) 5rem 5rem
431
+ gap .6rem
432
+ padding .65rem .8rem
433
+ .c-region
434
+ display none
@@ -0,0 +1,178 @@
1
+ ---
2
+ title: Pulse — service status
3
+ description: A calm, dark observability panel built in one Markdown file — a live :fetch board, build-time rollups, and a keyed services table, all with zero hand-written JavaScript.
4
+ image: https://darkmown.com/__wd/media/og-pulse.png
5
+ transitions: true
6
+ ---
7
+
8
+ @include /nav.wd
9
+ @include /base.wd
10
+
11
+ <main class="wide app-pulse">
12
+
13
+ <style>
14
+ @keyframes pulse-beat {
15
+ 0% { box-shadow: 0 0 0 0 rgba(43, 212, 168, .5); }
16
+ 70% { box-shadow: 0 0 0 6px rgba(43, 212, 168, 0); }
17
+ 100% { box-shadow: 0 0 0 0 rgba(43, 212, 168, 0); }
18
+ }
19
+ @keyframes pulse-spin { to { transform: rotate(360deg); } }
20
+ @media (prefers-reduced-motion: reduce) {
21
+ .app-pulse .pulse-live .dot,
22
+ .app-pulse .pulse-spin { animation: none; }
23
+ }
24
+ </style>
25
+
26
+ :fetch board from "/__wd/data/metrics.json"
27
+ :every 10s -> board refetch
28
+
29
+ :computed totalServices = board.services.length
30
+
31
+ <header class="pulse-head">
32
+ <div class="pulse-id">
33
+ <span class="pulse-mark">◐</span>
34
+ <div>
35
+ <h1 class="pulse-name">Pulse</h1>
36
+ <p class="pulse-sub">Infrastructure status · all regions</p>
37
+ </div>
38
+ </div>
39
+ <div class="pulse-actions">
40
+ <span class="pulse-live"><span class="dot"></span>live</span>
41
+ </div>
42
+ </header>
43
+
44
+ <div class="pulse-bar">
45
+
46
+ ::: div .pulse-summary
47
+ { totalServices } services · sorted slowest first
48
+ :::
49
+
50
+ :button "↻ Refresh" -> board refetch
51
+
52
+ </div>
53
+
54
+ :if board_loading
55
+ ::: div .pulse-state .is-loading
56
+ <span class="pulse-spin"></span> Refreshing…
57
+ :::
58
+ :else if board_error
59
+ ::: div .pulse-state .is-error
60
+ ✕ Feed unreachable — { board_error }
61
+ :::
62
+ :endif
63
+
64
+ <div class="pulse-stats">
65
+
66
+ ::: stat .is-ok
67
+ **Services tracked**
68
+
69
+ ::: div .stat-value
70
+ { totalServices }
71
+ :::
72
+
73
+ iad · sfo · fra · global
74
+ :::
75
+
76
+ ::: stat .is-ok
77
+ **Snapshot**
78
+
79
+ ::: div .stat-value
80
+ 06:05
81
+ :::
82
+
83
+ Sampled UTC, this morning
84
+ :::
85
+
86
+ ::: stat .is-warn
87
+ **Source**
88
+
89
+ ::: div .stat-value
90
+ :fetch
91
+ :::
92
+
93
+ Live JSON endpoint
94
+ :::
95
+
96
+ ::: stat
97
+ **Framework JS**
98
+
99
+ ::: div .stat-value
100
+ 0 KB
101
+ :::
102
+
103
+ Until this page fetched
104
+ :::
105
+
106
+ </div>
107
+
108
+ <div class="svc-table">
109
+
110
+ <div class="svc-row svc-head">
111
+ <span class="c-status">status</span>
112
+ <span class="c-name">service</span>
113
+ <span class="c-num">latency</span>
114
+ <span class="c-num">uptime</span>
115
+ <span class="c-region">region</span>
116
+ </div>
117
+
118
+ @loop board.services into s sort by s.latency desc
119
+ ::: div .svc-row .svc-ok when s.status == "ok" .svc-warn when s.status == "warn" .svc-down when s.status == "down"
120
+ ::: div .c-status
121
+ ::: span .dot
122
+ :::
123
+ ::: span .pill
124
+ { s.status }
125
+ :::
126
+ :::
127
+ ::: div .c-name
128
+ **{ s.name }**
129
+ :::
130
+ ::: div .c-num .is-latency
131
+ { s.latency }ms
132
+ :::
133
+ ::: div .c-num
134
+ { s.uptime }%
135
+ :::
136
+ ::: div .c-region
137
+ { s.region }
138
+ :::
139
+ :::
140
+ @empty
141
+ ::: div .pulse-state .is-empty
142
+ ○ No services in the feed.
143
+ :::
144
+ @endloop
145
+
146
+ </div>
147
+
148
+ <details class="source-reveal"><summary>Built with <code>:fetch</code> — view source</summary>
149
+
150
+ ```wd
151
+ :fetch board from "/__wd/data/metrics.json"
152
+ :every 10s -> board refetch
153
+
154
+ :computed totalServices = board.services.length
155
+
156
+ :if board_loading
157
+ Refreshing…
158
+ :else if board_error
159
+ Feed unreachable — { board_error }
160
+ :endif
161
+
162
+ :button "↻ Refresh" -> board refetch
163
+
164
+ @loop board.services into s sort by s.latency desc
165
+ ::: div .svc-row .svc-ok when s.status == "ok" .svc-warn when s.status == "warn" .svc-down when s.status == "down"
166
+ **{ s.name }** · { s.region }
167
+ { s.latency }ms · { s.uptime }%
168
+ :::
169
+ @empty
170
+ No services in the feed.
171
+ @endloop
172
+ ```
173
+
174
+ </details>
175
+
176
+ </main>
177
+
178
+ @include /footer.wd