@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,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
|