@zvndev/darkmown 1.0.0 → 1.2.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 (56) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +64 -3
  3. package/docs/cli.md +46 -16
  4. package/docs/spec-alignment.md +16 -3
  5. package/package.json +2 -2
  6. package/site/_/roadmap.json +3 -1
  7. package/site/pages/app.wd +1 -1
  8. package/site/pages/data.wd +2 -2
  9. package/site/pages/docs/index.wd +22 -0
  10. package/site/pages/folio/cart.wd +2 -2
  11. package/site/pages/forge/index.wd +1 -1
  12. package/site/pages/interactions/index.skin +113 -0
  13. package/site/pages/interactions/index.wd +86 -0
  14. package/site/pages/ledger/index.wd +10 -1
  15. package/src/api-runner.js +219 -0
  16. package/src/behaviors/carousel.js +153 -0
  17. package/src/behaviors/sortable.js +175 -0
  18. package/src/builder.js +199 -4
  19. package/src/cli.js +79 -54
  20. package/src/compiler/body.js +78 -3
  21. package/src/compiler/context.js +12 -1
  22. package/src/compiler/directives.js +123 -0
  23. package/src/compiler/interpolation.js +15 -14
  24. package/src/compiler/loops.js +57 -8
  25. package/src/compiler/page.js +9 -3
  26. package/src/deploy.js +174 -0
  27. package/src/headers.js +4 -0
  28. package/src/runtime.js +3 -1
  29. package/src/scaffold.js +79 -147
  30. package/src/templates/blog/README.md +25 -0
  31. package/src/templates/blog/site/_/nav.wd +6 -0
  32. package/src/templates/blog/site/_/posts.json +16 -0
  33. package/src/templates/blog/site/pages/index.skin +51 -0
  34. package/src/templates/blog/site/pages/index.wd +24 -0
  35. package/src/templates/blog/site/pages/posts/hello-darkmown.md +16 -0
  36. package/src/templates/blog/site/pages/posts/markdown-native.md +20 -0
  37. package/src/templates/dashboard/README.md +25 -0
  38. package/src/templates/dashboard/api/metrics.js +15 -0
  39. package/src/templates/dashboard/site/_/nav.wd +6 -0
  40. package/src/templates/dashboard/site/pages/index.skin +74 -0
  41. package/src/templates/dashboard/site/pages/index.wd +75 -0
  42. package/src/templates/landing/README.md +25 -0
  43. package/src/templates/landing/site/_/nav.wd +6 -0
  44. package/src/templates/landing/site/pages/index.skin +140 -0
  45. package/src/templates/landing/site/pages/index.wd +54 -0
  46. package/src/templates/starter/README.md +32 -0
  47. package/src/templates/starter/site/_/nav.wd +7 -0
  48. package/src/templates/starter/site/pages/about.md +10 -0
  49. package/src/templates/starter/site/pages/index.skin +47 -0
  50. package/src/templates/starter/site/pages/index.wd +27 -0
  51. package/src/templates/store/README.md +28 -0
  52. package/src/templates/store/api/checkout.js +18 -0
  53. package/src/templates/store/site/_/nav.wd +6 -0
  54. package/src/templates/store/site/_/products.json +8 -0
  55. package/src/templates/store/site/pages/index.skin +100 -0
  56. package/src/templates/store/site/pages/index.wd +83 -0
@@ -0,0 +1,140 @@
1
+ tokens
2
+ ink #14161c
3
+ paper #ffffff
4
+ soft #f4f5f8
5
+ line #e6e8ee
6
+ accent #5b4bf5
7
+
8
+ page
9
+ margin 0
10
+ font ui-sans-serif, system-ui, sans-serif
11
+ color $ink
12
+ bg $paper
13
+ line-height 1.6
14
+
15
+ main
16
+ max-width 900px
17
+ margin 0 auto
18
+ padding 1rem 1.5rem 4rem
19
+
20
+ nav
21
+ display flex
22
+ align-items center
23
+ justify-content space-between
24
+ max-width 900px
25
+ margin 0 auto
26
+ padding 1.25rem 1.5rem
27
+
28
+ nav strong
29
+ font-size 1.15rem
30
+
31
+ nav a
32
+ color $accent
33
+ text-decoration none
34
+
35
+ .hero
36
+ text-align center
37
+ padding 3rem 1rem 2rem
38
+
39
+ .hero h1
40
+ font-size 2.75rem
41
+ margin 0 0 .5rem
42
+
43
+ .lede
44
+ font-size 1.2rem
45
+ color #555c6b
46
+ margin 0 0 1.5rem
47
+
48
+ .cta
49
+ display inline-block
50
+ bg $accent
51
+ color white
52
+ text-decoration none
53
+ padding .8rem 1.4rem
54
+ radius 10px
55
+ font-weight 600
56
+
57
+ .features
58
+ display grid
59
+ grid-template-columns repeat(auto-fit, minmax(220px, 1fr))
60
+ gap 1rem
61
+ margin 2rem 0
62
+
63
+ .feature
64
+ background $soft
65
+ border 1px solid $line
66
+ radius 12px
67
+ padding 1.25rem
68
+
69
+ .feature h3
70
+ margin .25rem 0 .5rem
71
+
72
+ .wd-carousel
73
+ position relative
74
+ margin 1rem 0 2rem
75
+
76
+ .wd-carousel-track
77
+ display flex
78
+ overflow-x auto
79
+ scroll-snap-type x mandatory
80
+ scroll-behavior smooth
81
+ gap 1rem
82
+
83
+ .wd-carousel-track .quote
84
+ flex 0 0 100%
85
+ scroll-snap-align start
86
+ background $soft
87
+ border 1px solid $line
88
+ radius 12px
89
+ padding 1.75rem
90
+ font-size 1.2rem
91
+
92
+ .quote .who
93
+ margin .5rem 0 0
94
+ color #555c6b
95
+ font-size .95rem
96
+
97
+ .wd-carousel-prev
98
+ position absolute
99
+ left -.5rem
100
+ top 40%
101
+
102
+ .wd-carousel-next
103
+ position absolute
104
+ right -.5rem
105
+ top 40%
106
+
107
+ .wd-carousel-prev, .wd-carousel-next
108
+ bg white
109
+ color $ink
110
+ border 1px solid $line
111
+ radius 999px
112
+ width 2.25rem
113
+ height 2.25rem
114
+ cursor pointer
115
+
116
+ .wd-carousel-dots
117
+ display flex
118
+ justify-content center
119
+ gap .5rem
120
+ margin-top .75rem
121
+
122
+ .wd-carousel-dot
123
+ width .6rem
124
+ height .6rem
125
+ padding 0
126
+ border 0
127
+ radius 999px
128
+ bg $line
129
+ cursor pointer
130
+
131
+ .wd-carousel-dot[aria-current="true"]
132
+ bg $accent
133
+
134
+ .cta-band
135
+ text-align center
136
+ background $soft
137
+ border 1px solid $line
138
+ radius 16px
139
+ padding 2.5rem
140
+ margin-top 2rem
@@ -0,0 +1,54 @@
1
+ ---
2
+ title: Acme — ship faster
3
+ description: A marketing one-pager built with Darkmown. Zero framework JS on the static parts, with a testimonials carousel.
4
+ transitions: true
5
+ ---
6
+
7
+ @include /nav.wd
8
+
9
+ <main>
10
+
11
+ ::: hero
12
+ # Ship faster with *Acme*
13
+ <p class="lede">The all-in-one toolkit your team actually enjoys using.</p>
14
+ <a class="cta" href="#start">Get started</a>
15
+ :::
16
+
17
+ ::: features
18
+ ::: feature
19
+ ### ⚡ Fast
20
+ Static pages, zero framework JavaScript. Instant loads, perfect Lighthouse.
21
+ :::
22
+ ::: feature
23
+ ### 🧩 Simple
24
+ Write Markdown. Add a directive only on the pages that need interactivity.
25
+ :::
26
+ ::: feature
27
+ ### 🚀 Deploy anywhere
28
+ One command to Vercel or Cloudflare — your API comes along for free.
29
+ :::
30
+ :::
31
+
32
+ ## What teams say
33
+
34
+ :carousel
35
+ ::: quote
36
+ > "Acme cut our launch time in half."
37
+ <p class="who">— Riley, Head of Product</p>
38
+ :::
39
+ ::: quote
40
+ > "The simplest stack we've ever shipped on."
41
+ <p class="who">— Sam, CTO</p>
42
+ :::
43
+ ::: quote
44
+ > "Our marketing pages load instantly now."
45
+ <p class="who">— Jordan, Growth</p>
46
+ :::
47
+ :endcarousel
48
+
49
+ ::: cta-band #start
50
+ ## Ready to build?
51
+ <a class="cta" href="/">Start now</a>
52
+ :::
53
+
54
+ </main>
@@ -0,0 +1,32 @@
1
+ # My Darkmown site
2
+
3
+ Run `npm install` and `npm run dev` to start the live compiler.
4
+
5
+ ## Commands
6
+
7
+ - `npm run dev` — live compiler on http://localhost:5173 with hot reload.
8
+ - `npm run build` — compile the site to `dist/`.
9
+ - `npm run preview` — serve the built `dist/` locally.
10
+
11
+ ## Deploy
12
+
13
+ One command (it builds, then prints your live URL — log in if prompted):
14
+
15
+ ```sh
16
+ npx darkmown deploy vercel # or: npx darkmown deploy cloudflare
17
+ ```
18
+
19
+ Or one-click, after pushing this repo to GitHub (replace `YOUR_REPO_URL`):
20
+
21
+ [![Deploy to Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=YOUR_REPO_URL)
22
+ &nbsp;
23
+ [![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=YOUR_REPO_URL)
24
+
25
+ ## Layout
26
+
27
+ - Pages live in `site/pages` — `.md` stays plain Markdown, `.wd` adds directives.
28
+ - Shared includes live in `site/_`.
29
+ - Backend functions live in `api/` — plain Web-standard `(request) => Response`.
30
+ They run in `darkmown dev` and on Vercel/Cloudflare with no extra config.
31
+ - Hidden route files start with `.` or `-`.
32
+ - Colocated `index.skin` and `index.js` attach to a page automatically.
@@ -0,0 +1,7 @@
1
+ <nav>
2
+ <strong>My site</strong>
3
+ <span class="links">
4
+ <a href="/">Home</a>
5
+ <a href="/about/">About</a>
6
+ </span>
7
+ </nav>
@@ -0,0 +1,10 @@
1
+ ---
2
+ title: About
3
+ ---
4
+
5
+ # About
6
+
7
+ This page is plain Markdown (`.md`) — strict CommonMark, zero framework JavaScript.
8
+ Rename it to `.wd` when you want directives like state, loops, or forms.
9
+
10
+ [Back home](/)
@@ -0,0 +1,47 @@
1
+ tokens
2
+ ink #172026
3
+ paper #f7f2e8
4
+ accent #0f8b8d
5
+
6
+ page
7
+ margin 0
8
+ font ui-sans-serif, system-ui, sans-serif
9
+ color $ink
10
+ bg $paper
11
+
12
+ main
13
+ max-width 760px
14
+ margin 0 auto
15
+ padding 3rem 1.5rem
16
+
17
+ nav
18
+ display flex
19
+ align-items center
20
+ justify-content space-between
21
+ gap 1rem
22
+ max-width 760px
23
+ margin 0 auto
24
+ padding 1.25rem 1.5rem
25
+
26
+ nav strong
27
+ font-size 1.1rem
28
+
29
+ nav .links
30
+ display flex
31
+ gap 1.25rem
32
+
33
+ nav a
34
+ color $ink
35
+ text-decoration none
36
+ opacity .8
37
+
38
+ nav a:hover
39
+ opacity 1
40
+ color $accent
41
+
42
+ button
43
+ bg $accent
44
+ color white
45
+ border 0
46
+ padding .75rem 1rem
47
+ radius 8px
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: My Darkmown site
3
+ ---
4
+
5
+ @include /nav.wd
6
+
7
+ <main>
8
+
9
+ # My Darkmown site
10
+
11
+ Plain Markdown works. Rename to `.wd` when you want directives.
12
+
13
+ :state count = 0
14
+
15
+ Count: { count }
16
+
17
+ :button "Increment" -> count++
18
+
19
+ :state todos = ["Write a page"]
20
+
21
+ @loop todos into todo
22
+ - { todo }
23
+ @endloop
24
+
25
+ :button "Add" -> todos += "Add a loop"
26
+
27
+ </main>
@@ -0,0 +1,28 @@
1
+ # Store — a Darkmown template
2
+
3
+ A storefront in Markdown: a product grid with live search, a shared `:store` cart,
4
+ and a checkout that POSTs to a serverless function.
5
+
6
+ - **Static catalog** — `site/pages/index.wd` loops `site/_/products.json`.
7
+ - **Cart** — a `:store` shared across the page; add/remove with `:button`.
8
+ - **Checkout** — `:form action="/api/checkout"` posts to `api/checkout.js`, a plain
9
+ Web-standard `(request) => Response` function that runs in `darkmown dev` and on
10
+ every host. Replace its body with your real payment + fulfilment logic.
11
+
12
+ ## Commands
13
+
14
+ - `npm run dev` — live compiler + the local `/api/*` runner on http://localhost:5173.
15
+ - `npm run build` — compile to `dist/`.
16
+ - `npm run preview` — serve the built `dist/` locally (static only; use `dev` for `/api`).
17
+
18
+ ## Deploy
19
+
20
+ ```sh
21
+ npx darkmown deploy vercel # or: npx darkmown deploy cloudflare
22
+ ```
23
+
24
+ Your `api/checkout.js` deploys automatically alongside the static site.
25
+
26
+ [![Deploy to Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=YOUR_REPO_URL)
27
+ &nbsp;
28
+ [![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=YOUR_REPO_URL)
@@ -0,0 +1,18 @@
1
+ // Demo checkout endpoint. A plain Web-standard `(request) => Response` handler:
2
+ // it runs in `darkmown dev` and on Vercel Edge / Cloudflare Pages with no extra
3
+ // config. Echoes the order back with an id — swap in your real payment and
4
+ // fulfilment logic here (validate input, charge, write to a DB, send email).
5
+ export const config = { runtime: "edge" };
6
+
7
+ export default async function (request) {
8
+ if (request.method !== "POST") {
9
+ return Response.json({ ok: false, error: "POST only" }, { status: 405 });
10
+ }
11
+ const order = Object.fromEntries(await request.formData());
12
+ return Response.json({
13
+ ok: true,
14
+ received: order,
15
+ orderId: `ORD-${Date.now().toString(36).toUpperCase()}`,
16
+ at: new Date().toISOString()
17
+ });
18
+ }
@@ -0,0 +1,6 @@
1
+ <nav>
2
+ <strong>Shop</strong>
3
+ <span class="links">
4
+ <a href="/">Catalog</a>
5
+ </span>
6
+ </nav>
@@ -0,0 +1,8 @@
1
+ [
2
+ { "name": "Ceramic Mug", "emoji": "☕️", "price": 18 },
3
+ { "name": "Linen Tote", "emoji": "👜", "price": 32 },
4
+ { "name": "Pocket Notebook", "emoji": "📓", "price": 12 },
5
+ { "name": "Desk Lamp", "emoji": "💡", "price": 64 },
6
+ { "name": "Plant Pot", "emoji": "🪴", "price": 24 },
7
+ { "name": "Wall Clock", "emoji": "🕰️", "price": 48 }
8
+ ]
@@ -0,0 +1,100 @@
1
+ tokens
2
+ ink #1a1f2b
3
+ paper #fbfbf9
4
+ line #e6e4dd
5
+ accent #146b54
6
+
7
+ page
8
+ margin 0
9
+ font ui-sans-serif, system-ui, sans-serif
10
+ color $ink
11
+ bg $paper
12
+ line-height 1.55
13
+
14
+ main
15
+ max-width 860px
16
+ margin 0 auto
17
+ padding 2rem 1.5rem
18
+
19
+ nav
20
+ display flex
21
+ align-items center
22
+ justify-content space-between
23
+ max-width 860px
24
+ margin 0 auto
25
+ padding 1.25rem 1.5rem
26
+
27
+ nav strong
28
+ font-size 1.1rem
29
+
30
+ nav a
31
+ color $accent
32
+ text-decoration none
33
+
34
+ input
35
+ font inherit
36
+ padding .6rem .75rem
37
+ border 1px solid $line
38
+ radius 8px
39
+ width 100%
40
+ max-width 320px
41
+
42
+ .catalog
43
+ display grid
44
+ grid-template-columns repeat(auto-fill, minmax(160px, 1fr))
45
+ gap 1rem
46
+ margin 1.5rem 0
47
+
48
+ .product
49
+ border 1px solid $line
50
+ radius 12px
51
+ padding 1rem
52
+ text-align center
53
+ background white
54
+
55
+ .emoji
56
+ font-size 2.25rem
57
+
58
+ .pname
59
+ font-weight 600
60
+ margin .35rem 0 .15rem
61
+
62
+ .price
63
+ color $accent
64
+ font-weight 600
65
+ margin-bottom .6rem
66
+
67
+ button
68
+ font inherit
69
+ bg $accent
70
+ color white
71
+ border 0
72
+ padding .55rem .9rem
73
+ radius 8px
74
+ cursor pointer
75
+
76
+ .line
77
+ display flex
78
+ align-items center
79
+ justify-content space-between
80
+ gap 1rem
81
+ border 1px solid $line
82
+ radius 10px
83
+ padding .6rem .9rem
84
+ margin .4rem 0
85
+ background white
86
+
87
+ .line button
88
+ bg transparent
89
+ color $ink
90
+ border 1px solid $line
91
+
92
+ .cart-foot
93
+ font-size 1.1rem
94
+ margin .75rem 0
95
+
96
+ .receipt
97
+ border 1px solid $accent
98
+ radius 10px
99
+ padding 1rem
100
+ background #ecf6f1
@@ -0,0 +1,83 @@
1
+ ---
2
+ title: Shop — built with Darkmown
3
+ description: A storefront in Markdown — live search, a shared cart, and a checkout that posts to a serverless function.
4
+ transitions: true
5
+ ---
6
+
7
+ @include /nav.wd
8
+
9
+ <main>
10
+
11
+ ::: section #shop
12
+
13
+ :store cart = []
14
+ :state q = ""
15
+ :computed itemCount = count(cart)
16
+ :computed subtotal = sum(cart, price)
17
+
18
+ # Shop
19
+
20
+ ::: shop-search
21
+ :bind q placeholder="Search products…"
22
+ :::
23
+
24
+ ::: catalog
25
+ @loop /products.json into p where p.name contains q
26
+ ::: card .product
27
+ ::: emoji
28
+ { p.emoji }
29
+ :::
30
+ ::: pname
31
+ { p.name }
32
+ :::
33
+ ::: price
34
+ { p.price | money }
35
+ :::
36
+ :button "Add to cart" -> cart += p
37
+ :::
38
+ @empty
39
+ ::: card .empty
40
+ Nothing matches "**{ q }**".
41
+ :::
42
+ @endloop
43
+ :::
44
+
45
+ ## Your cart ({ itemCount })
46
+
47
+ @loop cart into item
48
+ ::: card .line
49
+ { item.emoji } **{ item.name }** — { item.price | money }
50
+ :button "Remove" -> cart remove item
51
+ :::
52
+ @empty
53
+ Your cart is empty — add something above.
54
+ @endloop
55
+
56
+ :if itemCount
57
+ ::: cart-foot
58
+ **Subtotal: { subtotal | money }**
59
+ :::
60
+
61
+ ### Checkout
62
+
63
+ This form posts to `api/checkout.js` — a plain serverless function that runs in
64
+ `darkmown dev` and on Vercel/Cloudflare alike. With JavaScript off it degrades to
65
+ a native POST.
66
+
67
+ :form action="/api/checkout" into receipt
68
+ :input name placeholder="Full name" required
69
+ :input email type=email placeholder="you@example.com" required
70
+ :submit "Place order"
71
+ :endform
72
+
73
+ :if receipt
74
+ ::: card .receipt
75
+ **Order placed ✓** — thanks { receipt.received.name }. A confirmation is on its way
76
+ to { receipt.received.email }. Order { receipt.orderId }.
77
+ :::
78
+ :endif
79
+ :endif
80
+
81
+ :::
82
+
83
+ </main>