@zvndev/darkmown 1.4.0 → 2.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 (106) hide show
  1. package/AGENTS.md +17 -3
  2. package/CHANGELOG.md +38 -0
  3. package/README.md +114 -17
  4. package/SECURITY.md +21 -18
  5. package/docs/cli.md +5 -1
  6. package/docs/spec-alignment.md +31 -4
  7. package/package.json +1 -1
  8. package/site/_/base.skin +239 -18
  9. package/site/_/base.wd +4 -0
  10. package/site/_/feature-card.wd +4 -0
  11. package/site/_/footer.wd +4 -0
  12. package/site/_/nav.wd +5 -1
  13. package/site/_/scoped-promo.wd +4 -0
  14. package/site/_/scoped-stat.wd +4 -0
  15. package/site/pages/404.wd +1 -0
  16. package/site/pages/app.skin +27 -5
  17. package/site/pages/app.wd +1 -0
  18. package/site/pages/blog/_schema.wd +15 -0
  19. package/site/pages/blog/collections-and-pagination.md +38 -0
  20. package/site/pages/blog/collections-and-pagination.skin +127 -0
  21. package/site/pages/blog/drafts-that-never-leak.md +2 -0
  22. package/site/pages/blog/drafts-that-never-leak.skin +127 -0
  23. package/site/pages/blog/index.skin +144 -0
  24. package/site/pages/blog/index.wd +74 -0
  25. package/site/pages/blog/shipping-feeds.md +1 -0
  26. package/site/pages/blog/shipping-feeds.skin +127 -0
  27. package/site/pages/blog/typed-frontmatter.md +45 -0
  28. package/site/pages/blog/typed-frontmatter.skin +127 -0
  29. package/site/pages/blog/unfinished-thoughts.skin +127 -0
  30. package/site/pages/blog/zero-js-by-default.md +31 -0
  31. package/site/pages/blog/zero-js-by-default.skin +127 -0
  32. package/site/pages/carousel/index.wd +1 -0
  33. package/site/pages/compass/index.wd +1 -0
  34. package/site/pages/data.skin +50 -9
  35. package/site/pages/data.wd +3 -0
  36. package/site/pages/docs/-relative-note.wd +4 -0
  37. package/site/pages/docs/index.skin +27 -0
  38. package/site/pages/docs/index.wd +115 -11
  39. package/site/pages/folio/-style.wd +4 -0
  40. package/site/pages/folio/cart.wd +1 -0
  41. package/site/pages/folio/index.wd +1 -0
  42. package/site/pages/forge/index.wd +1 -0
  43. package/site/pages/highlight/index.wd +1 -0
  44. package/site/pages/index.wd +1 -0
  45. package/site/pages/interactions/index.wd +1 -0
  46. package/site/pages/ledger/index.wd +1 -0
  47. package/site/pages/loops.skin +43 -6
  48. package/site/pages/loops.wd +1 -0
  49. package/site/pages/media/index.wd +1 -0
  50. package/site/pages/pulse/index.wd +1 -0
  51. package/site/pages/reactive.skin +38 -6
  52. package/site/pages/reactive.wd +1 -0
  53. package/site/pages/scoped/index.wd +1 -0
  54. package/site/pages/showcase/index.wd +1 -0
  55. package/site/pages/store.skin +43 -6
  56. package/site/pages/store.wd +1 -0
  57. package/site/pages/theme.wd +1 -0
  58. package/src/builder.js +535 -48
  59. package/src/cli.js +96 -18
  60. package/src/compiler/actions.js +303 -0
  61. package/src/compiler/body.js +36 -24
  62. package/src/compiler/collections.js +316 -0
  63. package/src/compiler/context.js +83 -6
  64. package/src/compiler/directives.js +31 -1470
  65. package/src/compiler/fetch.js +159 -0
  66. package/src/compiler/format.js +17 -4
  67. package/src/compiler/forms.js +456 -0
  68. package/src/compiler/frontmatter.js +10 -5
  69. package/src/compiler/includes.js +66 -1
  70. package/src/compiler/index.js +15 -3
  71. package/src/compiler/loops.js +181 -31
  72. package/src/compiler/markdown.js +65 -15
  73. package/src/compiler/media.js +133 -0
  74. package/src/compiler/page.js +78 -41
  75. package/src/compiler/state.js +168 -0
  76. package/src/compiler/structure.js +377 -0
  77. package/src/dev.js +76 -0
  78. package/src/headers.js +56 -17
  79. package/src/router.js +12 -1
  80. package/src/runtime.js +5 -3
  81. package/src/statics.js +63 -12
  82. package/src/templates/blog/README.md +13 -4
  83. package/src/templates/blog/site/_/nav.wd +4 -0
  84. package/src/templates/blog/site/pages/index.skin +87 -0
  85. package/src/templates/blog/site/pages/index.wd +10 -4
  86. package/src/templates/blog/site/pages/posts/_schema.wd +16 -0
  87. package/src/templates/blog/site/pages/posts/hello-darkmown.md +2 -0
  88. package/src/templates/blog/site/pages/posts/hello-darkmown.skin +59 -0
  89. package/src/templates/blog/site/pages/posts/markdown-native.md +9 -4
  90. package/src/templates/blog/site/pages/posts/markdown-native.skin +59 -0
  91. package/src/templates/dashboard/site/_/nav.wd +4 -0
  92. package/src/templates/dashboard/site/pages/index.skin +84 -0
  93. package/src/templates/dashboard/site/pages/index.wd +1 -0
  94. package/src/templates/landing/site/_/nav.wd +4 -0
  95. package/src/templates/landing/site/pages/index.skin +113 -6
  96. package/src/templates/landing/site/pages/index.wd +1 -0
  97. package/src/templates/starter/site/_/nav.wd +4 -0
  98. package/src/templates/starter/site/pages/about.md +18 -1
  99. package/src/templates/starter/site/pages/about.skin +69 -0
  100. package/src/templates/starter/site/pages/index.skin +81 -3
  101. package/src/templates/starter/site/pages/index.wd +1 -0
  102. package/src/templates/store/site/_/nav.wd +4 -0
  103. package/src/templates/store/site/pages/index.skin +93 -11
  104. package/src/templates/store/site/pages/index.wd +1 -0
  105. package/site/pages/blog/index.md +0 -13
  106. package/src/templates/blog/site/_/posts.json +0 -16
@@ -0,0 +1,127 @@
1
+ /* Colocated post styling — a .skin next to a .md attaches automatically, so
2
+ these prose pages stay static (zero JS) yet still read on-brand. A .md can't
3
+ @include /base.wd, so this reading skin carries the site's tokens itself.
4
+ Kept in sync with site/_/base.skin; copy it beside each new post. */
5
+
6
+ tokens
7
+ ink #1c1814
8
+ ink-soft #4b4239
9
+ muted #756a5d
10
+ paper #faf8f3
11
+ panel #ffffff
12
+ sunk #efe9dc
13
+ line #e7e1d4
14
+ accent #0f6b5e
15
+ accent-deep #0a4f45
16
+ accent-soft #e3f0ec
17
+ code-bg #1b2420
18
+ code-ink #e9efe7
19
+ code-line #2c3b34
20
+ radius 12px
21
+
22
+ tokens dark
23
+ ink #ece6db
24
+ ink-soft #c3bbab
25
+ muted #9a9081
26
+ paper #14110d
27
+ panel #1e1913
28
+ sunk #221d17
29
+ line #2f281f
30
+ accent #5ccab4
31
+ accent-deep #8fe0cf
32
+ accent-soft #16302a
33
+ code-bg #100d0a
34
+ code-ink #e4ebe2
35
+ code-line #2a231b
36
+
37
+ html
38
+ bg $paper
39
+
40
+ page
41
+ max-width 720px
42
+ margin 0 auto
43
+ padding 3rem 1.5rem 5rem
44
+ font-family ui-serif, "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, Cambria, serif
45
+ font-size 18px
46
+ line-height 1.7
47
+ color $ink
48
+ bg $paper
49
+ -webkit-font-smoothing antialiased
50
+ text-rendering optimizeLegibility
51
+
52
+ h1
53
+ font-size clamp(2rem, 5vw, 2.8rem)
54
+ line-height 1.12
55
+ letter-spacing -.022em
56
+ margin 1rem 0 1.25rem
57
+ color $ink
58
+
59
+ h2
60
+ font-size 1.5rem
61
+ line-height 1.2
62
+ letter-spacing -.012em
63
+ margin 2.4rem 0 .6rem
64
+ color $ink
65
+
66
+ h3
67
+ font-size 1.2rem
68
+ margin 1.8rem 0 .4rem
69
+ color $ink
70
+
71
+ p
72
+ margin 1.1rem 0
73
+
74
+ a
75
+ color $accent
76
+ text-underline-offset 2px
77
+
78
+ a:hover
79
+ color $accent-deep
80
+
81
+ strong
82
+ font-weight 650
83
+ color $ink
84
+
85
+ hr
86
+ border 0
87
+ border-top 1px solid $line
88
+ margin 2.5rem 0
89
+
90
+ ul, ol
91
+ margin 1.1rem 0
92
+ padding-left 1.4rem
93
+
94
+ li
95
+ margin .35rem 0
96
+
97
+ code
98
+ font-family ui-monospace, "SF Mono", Menlo, Consolas, monospace
99
+ font-size .88em
100
+ bg $sunk
101
+ color $accent-deep
102
+ padding .12rem .36rem
103
+ radius 6px
104
+
105
+ pre
106
+ bg $code-bg
107
+ color $code-ink
108
+ padding 1.2rem 1.35rem
109
+ margin 1.5rem 0
110
+ radius $radius
111
+ overflow-x auto
112
+ line-height 1.62
113
+ font-size .87rem
114
+ box-shadow inset 0 0 0 1px $code-line
115
+
116
+ pre code
117
+ bg transparent
118
+ color inherit
119
+ padding 0
120
+ font-size 1em
121
+
122
+ blockquote
123
+ margin 1.6rem 0
124
+ padding .6rem 1.3rem
125
+ border-left 3px solid $accent
126
+ color $ink-soft
127
+ font-style italic
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Zero JavaScript, by default
3
+ description: A Darkmown page ships no framework JavaScript unless it declares reactive behavior. The blog you are reading proves it.
4
+ date: 2026-06-25
5
+ excerpt: View source on this page. There is no runtime script tag, because nothing on it is reactive — and the framework knows the difference.
6
+ tags: [performance, philosophy]
7
+ ---
8
+
9
+ # Zero JavaScript, by default
10
+
11
+ Open your browser's view-source on this post. Look for a `<script>` that loads a
12
+ framework runtime. There isn't one — and there isn't one on the blog index, or
13
+ on any of its paginated pages either. None of them declare reactive behavior, so
14
+ none of them pay for it.
15
+
16
+ That is the whole bargain. A `.md` file is plain CommonMark. Rename it to `.wd`
17
+ and you unlock directives — state, loops, conditionals — but you only ship the
18
+ ~7.4 KB runtime on the pages that actually use them. A listing built from a
19
+ collection loop resolves entirely at build time, so it stays static HTML.
20
+
21
+ ## The extension is the feature gate
22
+
23
+ There is no flag to toggle, no "static export" mode to remember. The compiler
24
+ tracks whether a page declared anything reactive and emits `runtime: false` into
25
+ `routes.json` when it didn't. A collection listing, a paginated archive, a page
26
+ of prose with a code block — all static, all cacheable on a CDN forever, all
27
+ fast on the first byte because there is nothing to hydrate.
28
+
29
+ When you do want an island of interactivity — a search box, a cart, a sortable
30
+ table — you declare it, and only that page loads the runtime. The rest of the
31
+ site stays weightless.
@@ -0,0 +1,127 @@
1
+ /* Colocated post styling — a .skin next to a .md attaches automatically, so
2
+ these prose pages stay static (zero JS) yet still read on-brand. A .md can't
3
+ @include /base.wd, so this reading skin carries the site's tokens itself.
4
+ Kept in sync with site/_/base.skin; copy it beside each new post. */
5
+
6
+ tokens
7
+ ink #1c1814
8
+ ink-soft #4b4239
9
+ muted #756a5d
10
+ paper #faf8f3
11
+ panel #ffffff
12
+ sunk #efe9dc
13
+ line #e7e1d4
14
+ accent #0f6b5e
15
+ accent-deep #0a4f45
16
+ accent-soft #e3f0ec
17
+ code-bg #1b2420
18
+ code-ink #e9efe7
19
+ code-line #2c3b34
20
+ radius 12px
21
+
22
+ tokens dark
23
+ ink #ece6db
24
+ ink-soft #c3bbab
25
+ muted #9a9081
26
+ paper #14110d
27
+ panel #1e1913
28
+ sunk #221d17
29
+ line #2f281f
30
+ accent #5ccab4
31
+ accent-deep #8fe0cf
32
+ accent-soft #16302a
33
+ code-bg #100d0a
34
+ code-ink #e4ebe2
35
+ code-line #2a231b
36
+
37
+ html
38
+ bg $paper
39
+
40
+ page
41
+ max-width 720px
42
+ margin 0 auto
43
+ padding 3rem 1.5rem 5rem
44
+ font-family ui-serif, "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, Cambria, serif
45
+ font-size 18px
46
+ line-height 1.7
47
+ color $ink
48
+ bg $paper
49
+ -webkit-font-smoothing antialiased
50
+ text-rendering optimizeLegibility
51
+
52
+ h1
53
+ font-size clamp(2rem, 5vw, 2.8rem)
54
+ line-height 1.12
55
+ letter-spacing -.022em
56
+ margin 1rem 0 1.25rem
57
+ color $ink
58
+
59
+ h2
60
+ font-size 1.5rem
61
+ line-height 1.2
62
+ letter-spacing -.012em
63
+ margin 2.4rem 0 .6rem
64
+ color $ink
65
+
66
+ h3
67
+ font-size 1.2rem
68
+ margin 1.8rem 0 .4rem
69
+ color $ink
70
+
71
+ p
72
+ margin 1.1rem 0
73
+
74
+ a
75
+ color $accent
76
+ text-underline-offset 2px
77
+
78
+ a:hover
79
+ color $accent-deep
80
+
81
+ strong
82
+ font-weight 650
83
+ color $ink
84
+
85
+ hr
86
+ border 0
87
+ border-top 1px solid $line
88
+ margin 2.5rem 0
89
+
90
+ ul, ol
91
+ margin 1.1rem 0
92
+ padding-left 1.4rem
93
+
94
+ li
95
+ margin .35rem 0
96
+
97
+ code
98
+ font-family ui-monospace, "SF Mono", Menlo, Consolas, monospace
99
+ font-size .88em
100
+ bg $sunk
101
+ color $accent-deep
102
+ padding .12rem .36rem
103
+ radius 6px
104
+
105
+ pre
106
+ bg $code-bg
107
+ color $code-ink
108
+ padding 1.2rem 1.35rem
109
+ margin 1.5rem 0
110
+ radius $radius
111
+ overflow-x auto
112
+ line-height 1.62
113
+ font-size .87rem
114
+ box-shadow inset 0 0 0 1px $code-line
115
+
116
+ pre code
117
+ bg transparent
118
+ color inherit
119
+ padding 0
120
+ font-size 1em
121
+
122
+ blockquote
123
+ margin 1.6rem 0
124
+ padding .6rem 1.3rem
125
+ border-left 3px solid $accent
126
+ color $ink-soft
127
+ font-style italic
@@ -1,4 +1,5 @@
1
1
  ---
2
+ html: true
2
3
  title: Swiper — a draggable carousel wired to wd.subscribe
3
4
  description: An image carousel with arrow-key nav, pointer drag / swipe, and a sliding transition — the things a deliberately tiny framework leaves to you. Darkmown owns the reactive slide state, the dots, and the readout declaratively; a colocated index.js adds the gestures through window.wd.subscribe and window.wd.set.
4
5
  image: https://darkmown.com/__wd/media/og-showcase.png
@@ -1,4 +1,5 @@
1
1
  ---
2
+ html: true
2
3
  title: Compass — find your match
3
4
  description: A guided product-finder quiz built in one Markdown file. Four questions advance a state machine with :if branching, accumulate scores with :button actions, and a :computed recommendation lands the perfect pick. Zero hand-written JavaScript.
4
5
  image: https://darkmown.com/__wd/media/og-compass.png
@@ -29,18 +29,44 @@ h2
29
29
  padding-top 1.2rem
30
30
 
31
31
  button
32
- border 1px solid $ink
33
- bg $ink
32
+ display inline-flex
33
+ align-items center
34
+ justify-content center
35
+ gap .5rem
36
+ border 1px solid $accent
37
+ bg $accent
34
38
  color white
35
- padding .72rem 1rem
39
+ padding .6rem 1.1rem
36
40
  margin .3rem .5rem .3rem 0
37
- radius $radius
38
- font inherit
41
+ radius 999px
42
+ font system-ui, -apple-system, "Segoe UI", Roboto, sans-serif
43
+ font-size .92rem
44
+ font-weight 560
45
+ line-height 1.15
39
46
  cursor pointer
47
+ appearance none
48
+ box-shadow 0 1px 2px rgba(23,23,23,.08)
49
+ transition transform .14s cubic-bezier(.2,.7,.3,1), box-shadow .14s ease, background .14s ease, border-color .14s ease
40
50
 
41
51
  button:hover
42
52
  bg $accent
43
53
  border-color $accent
54
+ transform translateY(-1px)
55
+ box-shadow 0 8px 18px -8px rgba(22,100,90,.5)
56
+
57
+ button:active
58
+ transform translateY(0)
59
+ box-shadow 0 1px 2px rgba(23,23,23,.08)
60
+
61
+ button:focus-visible
62
+ outline 2px solid $accent
63
+ outline-offset 2px
64
+
65
+ button:disabled
66
+ opacity .5
67
+ cursor not-allowed
68
+ box-shadow none
69
+ transform none
44
70
 
45
71
  a
46
72
  color $accent
@@ -75,21 +101,36 @@ form
75
101
  margin 1rem 0
76
102
 
77
103
  input
78
- padding .7rem .9rem
104
+ padding .62rem .85rem
79
105
  border 1px solid $line
80
106
  radius $radius
81
107
  font inherit
108
+ font-size .95rem
82
109
  bg $panel
110
+ appearance none
111
+ transition border-color .14s ease, box-shadow .14s ease
112
+
113
+ input:hover
114
+ border-color $accent
115
+
116
+ input:focus-visible
117
+ outline none
118
+ border-color $accent
119
+ box-shadow 0 0 0 3px rgba(22,100,90,.18)
83
120
 
84
121
  .pulse-button
85
- border 0
122
+ border 1px solid $warm
86
123
  bg $warm
87
124
  color white
88
- padding .85rem 1rem
89
- radius $radius
125
+ padding .6rem 1.1rem
126
+ radius 999px
90
127
  font inherit
91
128
  cursor pointer
92
129
 
130
+ .pulse-button:hover
131
+ transform translateY(-1px)
132
+ box-shadow 0 8px 18px -8px rgba(168,63,42,.5)
133
+
93
134
  .tally-card
94
135
  border 1px solid $line
95
136
  bg $panel
@@ -1,4 +1,5 @@
1
1
  ---
2
+ html: true
2
3
  title: Data, forms, and persistence
3
4
  transitions: true
4
5
  ---
@@ -38,6 +39,8 @@ That loop also proves `:if` over loop items: the lead badge is decided per row.
38
39
 
39
40
  Every `:fetch` tracks the whole lifecycle — `loading`, `error`, `empty`, and data — so a page can answer each one. Here the same primitive shows an **error** (a missing URL 404s) and an **empty** result (a file that is just `[]`):
40
41
 
42
+ *(Heads up: the browser console will log a `404` for `intentionally-missing.json` on this page — that failure is deliberate, so the error branch below has something real to show.)*
43
+
41
44
  :fetch broken from "/__wd/data/intentionally-missing.json"
42
45
 
43
46
  :if broken_error
@@ -1,3 +1,7 @@
1
+ ---
2
+ html: true
3
+ ---
4
+
1
5
  <section class="feature-card">
2
6
 
3
7
  **Relative include:** this hidden block lives beside the docs page as `-relative-note.wd`, so it can be included without becoming a route.
@@ -17,6 +17,33 @@ main.docs
17
17
  color $ink-soft
18
18
  max-width 60ch
19
19
 
20
+ /* On-page TOC — a compact multi-column block of plain # anchors. */
21
+ .docs-toc
22
+ border 1px solid $line
23
+ bg $panel
24
+ radius $radius
25
+ padding 1.1rem 1.35rem
26
+ margin 1.25rem 0 .5rem
27
+
28
+ .docs-toc ul
29
+ columns 2
30
+ column-gap 2.5rem
31
+ margin .55rem 0 0
32
+ padding 0
33
+ list-style none
34
+
35
+ .docs-toc li
36
+ margin .18rem 0
37
+ break-inside avoid
38
+ font-size .95rem
39
+
40
+ .docs-toc a
41
+ font-weight 500
42
+
43
+ @media (max-width: 600px)
44
+ .docs-toc ul
45
+ columns 1
46
+
20
47
  /* Section headings get a quiet rule above them so the long page scans. */
21
48
  main.docs h2
22
49
  margin-top 3rem