@madojs/mado 0.10.0 → 0.11.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 (219) hide show
  1. package/AGENTS.md +24 -26
  2. package/CHANGELOG.md +98 -0
  3. package/README.md +18 -45
  4. package/TODO.md +52 -48
  5. package/dist/src/component.d.ts +2 -1
  6. package/dist/src/component.js +5 -2
  7. package/dist/src/component.js.map +1 -1
  8. package/dist/src/each.d.ts +1 -1
  9. package/dist/src/each.js +1 -1
  10. package/dist/src/each.js.map +1 -1
  11. package/dist/src/html/template.js +10 -0
  12. package/dist/src/html/template.js.map +1 -1
  13. package/dist/src/index.d.ts +11 -6
  14. package/dist/src/index.js +5 -3
  15. package/dist/src/index.js.map +1 -1
  16. package/dist/src/lazy.d.ts +1 -1
  17. package/dist/src/lazy.js +1 -1
  18. package/dist/src/lazy.js.map +1 -1
  19. package/dist/src/page.d.ts +17 -21
  20. package/dist/src/page.js +7 -12
  21. package/dist/src/page.js.map +1 -1
  22. package/dist/src/router/manifest.d.ts +1 -1
  23. package/dist/src/router/manifest.js +21 -13
  24. package/dist/src/router/manifest.js.map +1 -1
  25. package/dist/src/router/match.d.ts +2 -2
  26. package/dist/src/router/match.js +3 -3
  27. package/dist/src/router/match.js.map +1 -1
  28. package/dist/src/router/navigation.js +1 -1
  29. package/dist/src/router/navigation.js.map +1 -1
  30. package/dist/src/vite/index.d.ts +10 -0
  31. package/dist/src/vite/index.js +33 -0
  32. package/dist/src/vite/index.js.map +1 -0
  33. package/docs/en/00-the-mado-way.md +25 -12
  34. package/docs/en/01-routing.md +90 -142
  35. package/docs/en/02-project-layout.md +59 -52
  36. package/docs/en/03-static-bake.md +5 -6
  37. package/docs/en/05-why-mado.md +6 -6
  38. package/docs/en/06-for-backenders.md +18 -22
  39. package/docs/en/08-llm-zero-history-test.md +9 -14
  40. package/docs/en/09-shadow-vs-light-dom.md +28 -36
  41. package/docs/en/10-app-architecture.md +158 -96
  42. package/docs/en/11-layouts.md +22 -24
  43. package/docs/en/12-auth-and-api.md +89 -182
  44. package/docs/en/13-deployment.md +25 -26
  45. package/docs/en/14-testing.md +4 -4
  46. package/docs/en/16-bake-cookbook.md +17 -10
  47. package/docs/en/18-api-freeze-map.md +6 -4
  48. package/docs/en/20-v1-stability.md +1 -1
  49. package/docs/fr/00-the-mado-way.md +55 -90
  50. package/docs/fr/01-routing.md +70 -152
  51. package/docs/fr/02-project-layout.md +74 -48
  52. package/docs/fr/03-static-bake.md +1 -1
  53. package/docs/fr/05-why-mado.md +6 -6
  54. package/docs/fr/06-for-backenders.md +7 -7
  55. package/docs/fr/08-llm-zero-history-test.md +21 -48
  56. package/docs/fr/09-shadow-vs-light-dom.md +43 -162
  57. package/docs/fr/10-app-architecture.md +110 -33
  58. package/docs/fr/11-layouts.md +24 -12
  59. package/docs/fr/12-auth-and-api.md +63 -22
  60. package/docs/fr/13-deployment.md +30 -12
  61. package/docs/fr/14-testing.md +1 -1
  62. package/docs/fr/16-bake-cookbook.md +57 -4
  63. package/docs/fr/18-api-freeze-map.md +1 -1
  64. package/docs/fr/20-v1-stability.md +1 -1
  65. package/docs/recipes/nginx/README.md +13 -0
  66. package/docs/ru/00-the-mado-way.md +53 -75
  67. package/docs/ru/01-routing.md +68 -143
  68. package/docs/ru/02-project-layout.md +75 -48
  69. package/docs/ru/03-static-bake.md +2 -2
  70. package/docs/ru/05-why-mado.md +6 -6
  71. package/docs/ru/06-for-backenders.md +7 -7
  72. package/docs/ru/08-llm-zero-history-test.md +9 -14
  73. package/docs/ru/09-shadow-vs-light-dom.md +43 -178
  74. package/docs/ru/10-app-architecture.md +115 -63
  75. package/docs/ru/11-layouts.md +24 -24
  76. package/docs/ru/12-auth-and-api.md +57 -35
  77. package/docs/ru/13-deployment.md +19 -13
  78. package/docs/ru/14-testing.md +1 -1
  79. package/docs/ru/16-bake-cookbook.md +48 -8
  80. package/docs/ru/18-api-freeze-map.md +5 -3
  81. package/docs/ru/20-v1-stability.md +1 -1
  82. package/docs/uk/00-the-mado-way.md +70 -44
  83. package/docs/uk/01-routing.md +41 -47
  84. package/docs/uk/02-project-layout.md +68 -41
  85. package/docs/uk/03-static-bake.md +1 -2
  86. package/docs/uk/06-for-backenders.md +3 -3
  87. package/docs/uk/08-llm-zero-history-test.md +22 -24
  88. package/docs/uk/09-shadow-vs-light-dom.md +37 -86
  89. package/docs/uk/10-app-architecture.md +72 -31
  90. package/docs/uk/11-layouts.md +25 -12
  91. package/docs/uk/12-auth-and-api.md +58 -22
  92. package/docs/uk/13-deployment.md +4 -3
  93. package/docs/uk/14-testing.md +1 -1
  94. package/docs/uk/18-api-freeze-map.md +1 -1
  95. package/docs/uk/20-v1-stability.md +1 -1
  96. package/llms.txt +14 -15
  97. package/package.json +18 -11
  98. package/scripts/_config.mjs +15 -161
  99. package/scripts/bake.mjs +71 -58
  100. package/scripts/cli/generate.mjs +348 -0
  101. package/scripts/cli/help.mjs +27 -0
  102. package/scripts/cli/index.mjs +79 -0
  103. package/scripts/cli/init.mjs +153 -0
  104. package/scripts/cli/release.mjs +152 -0
  105. package/scripts/cli/run.mjs +96 -0
  106. package/scripts/cli.mjs +2 -560
  107. package/scripts/package-smoke.mjs +4 -1
  108. package/scripts/preview.mjs +17 -61
  109. package/scripts/size-budget.mjs +5 -2
  110. package/scripts/vite.default.mjs +11 -0
  111. package/starters/default/.editorconfig +12 -0
  112. package/starters/default/README.md +74 -0
  113. package/starters/default/eslint.config.mjs +256 -0
  114. package/starters/default/index.html +13 -0
  115. package/starters/default/package.json +30 -0
  116. package/starters/default/public/favicon.svg +4 -0
  117. package/starters/default/src/app.routes.ts +39 -0
  118. package/starters/default/src/layouts/app-shell.layout.ts +35 -0
  119. package/starters/default/src/layouts/auth-shell.layout.ts +17 -0
  120. package/starters/default/src/main.ts +16 -0
  121. package/starters/default/src/modules/auth/_contracts/auth-api.types.ts +17 -0
  122. package/starters/default/src/modules/auth/auth.connector.ts +45 -0
  123. package/starters/default/src/modules/auth/auth.guard.ts +22 -0
  124. package/starters/default/src/modules/auth/auth.public.ts +9 -0
  125. package/starters/default/src/modules/auth/auth.routes.ts +8 -0
  126. package/starters/default/src/modules/auth/auth.service.ts +71 -0
  127. package/starters/default/src/modules/auth/auth.types.ts +15 -0
  128. package/starters/default/src/modules/auth/login.page.ts +62 -0
  129. package/starters/default/src/modules/billing/_contracts/stripe.types.ts +17 -0
  130. package/starters/default/src/modules/billing/api/stripe.connector.ts +71 -0
  131. package/starters/default/src/modules/billing/billing.public.ts +5 -0
  132. package/starters/default/src/modules/billing/billing.routes.ts +9 -0
  133. package/starters/default/src/modules/billing/billing.types.ts +15 -0
  134. package/starters/default/src/modules/billing/components/invoice-status-badge.component.ts +43 -0
  135. package/starters/default/src/modules/billing/data/invoices.resource.ts +35 -0
  136. package/starters/default/src/modules/billing/pages/invoice-detail.page.ts +70 -0
  137. package/starters/default/src/modules/billing/pages/invoices-list.page.ts +73 -0
  138. package/starters/default/src/modules/home/home.page.ts +34 -0
  139. package/starters/default/src/modules/home/not-found.page.ts +11 -0
  140. package/starters/default/src/shared/http/http-client.ts +86 -0
  141. package/starters/default/src/shared/http/http-error.ts +37 -0
  142. package/starters/default/src/shared/http/interceptors.ts +59 -0
  143. package/starters/default/src/shared/lib/format-date.ts +19 -0
  144. package/starters/default/src/shared/styles/content.css +70 -0
  145. package/starters/default/src/shared/styles/reset.css +32 -0
  146. package/starters/default/src/shared/styles/shell.css +57 -0
  147. package/starters/default/src/shared/styles/tokens.css +44 -0
  148. package/starters/default/src/shared/ui/x-button.component.ts +49 -0
  149. package/starters/default/src/shared/ui/x-spinner.component.ts +22 -0
  150. package/starters/default/src/styles.d.ts +1 -0
  151. package/starters/default/src/vite-env.d.ts +1 -0
  152. package/starters/default/tsconfig.json +24 -0
  153. package/starters/default/vite.config.ts +9 -0
  154. package/MADO_V1_PLAN.md +0 -179
  155. package/ROADMAP.md +0 -178
  156. package/dist/src/html.d.ts +0 -18
  157. package/dist/src/html.js +0 -17
  158. package/dist/src/html.js.map +0 -1
  159. package/dist/src/router.d.ts +0 -13
  160. package/dist/src/router.js +0 -13
  161. package/dist/src/router.js.map +0 -1
  162. package/scripts/bundle.mjs +0 -212
  163. package/scripts/llm-zero-history-smoke.mjs +0 -93
  164. package/scripts/new.mjs +0 -80
  165. package/scripts/showcase-regression.mjs +0 -392
  166. package/server/serve.mjs +0 -455
  167. package/starters/admin/README.md +0 -63
  168. package/starters/admin/index.html +0 -28
  169. package/starters/admin/mado.config.json +0 -22
  170. package/starters/admin/package.json +0 -24
  171. package/starters/admin/public/favicon.svg +0 -4
  172. package/starters/admin/src/components/x-button.ts +0 -82
  173. package/starters/admin/src/components/x-input.ts +0 -105
  174. package/starters/admin/src/layouts/app.ts +0 -101
  175. package/starters/admin/src/layouts/auth.ts +0 -41
  176. package/starters/admin/src/lib/api.ts +0 -184
  177. package/starters/admin/src/lib/auth.ts +0 -83
  178. package/starters/admin/src/main.ts +0 -15
  179. package/starters/admin/src/pages/admin/dashboard.ts +0 -48
  180. package/starters/admin/src/pages/admin/order-detail.ts +0 -80
  181. package/starters/admin/src/pages/admin/orders.ts +0 -117
  182. package/starters/admin/src/pages/home.ts +0 -34
  183. package/starters/admin/src/pages/login.ts +0 -70
  184. package/starters/admin/src/pages/not-found.ts +0 -12
  185. package/starters/admin/src/routes.ts +0 -40
  186. package/starters/admin/src/styles/global.ts +0 -86
  187. package/starters/admin/tsconfig.json +0 -15
  188. package/starters/crud/README.md +0 -33
  189. package/starters/crud/index.html +0 -28
  190. package/starters/crud/mado.config.json +0 -20
  191. package/starters/crud/package.json +0 -24
  192. package/starters/crud/src/components/app-shell.ts +0 -56
  193. package/starters/crud/src/components/ticket-detail.ts +0 -33
  194. package/starters/crud/src/components/ticket-form.ts +0 -69
  195. package/starters/crud/src/components/ticket-list.ts +0 -66
  196. package/starters/crud/src/lib/api.ts +0 -76
  197. package/starters/crud/src/main.ts +0 -9
  198. package/starters/crud/src/pages/home.ts +0 -34
  199. package/starters/crud/src/pages/not-found.ts +0 -12
  200. package/starters/crud/src/pages/ticket-detail.ts +0 -7
  201. package/starters/crud/src/pages/ticket-new.ts +0 -7
  202. package/starters/crud/src/pages/tickets.ts +0 -7
  203. package/starters/crud/src/routes.ts +0 -11
  204. package/starters/crud/src/styles/global.ts +0 -155
  205. package/starters/crud/tsconfig.json +0 -15
  206. package/starters/minimal/README.md +0 -21
  207. package/starters/minimal/index.html +0 -28
  208. package/starters/minimal/mado.config.json +0 -20
  209. package/starters/minimal/package.json +0 -24
  210. package/starters/minimal/src/components/app-counter.ts +0 -31
  211. package/starters/minimal/src/main.ts +0 -9
  212. package/starters/minimal/src/pages/home.ts +0 -35
  213. package/starters/minimal/src/pages/not-found.ts +0 -14
  214. package/starters/minimal/src/routes.ts +0 -8
  215. package/starters/minimal/src/styles/global.ts +0 -60
  216. package/starters/minimal/tsconfig.json +0 -15
  217. package/templates/page-detail.ts +0 -63
  218. package/templates/page-form.ts +0 -94
  219. package/templates/page-list.ts +0 -79
@@ -1,6 +1,6 @@
1
1
  # Deployment
2
2
 
3
- Один command, один artifact:
3
+ Одна команда, один deploy artifact:
4
4
 
5
5
  ```bash
6
6
  mado release
@@ -10,15 +10,18 @@ mado release
10
10
 
11
11
  ```txt
12
12
  out/
13
- ├── index.html
14
- ├── assets/
15
- ├── baked/
16
- ├── _redirects
17
- └── _headers
13
+ ├── index.html ← SPA shell или baked HTML для /
14
+ ├── assets/ ← Vite hashed assets
15
+ ├── *.gz ← precompressed gzip
16
+ │ └── *.br ← precompressed brotli
17
+ ├── <route>/index.html ← baked HTML для static hosts
18
+ ├── sitemap.xml ← sitemap в root сайта
19
+ ├── _redirects ← Cloudflare Pages / Netlify SPA fallback
20
+ └── _headers ← cache rules
18
21
  ```
19
22
 
20
23
  `out/` можно деплоить на nginx, Cloudflare Pages, Netlify, S3/CloudFront или
21
- GitHub Pages.
24
+ GitHub Pages. Деплоится только `out/`.
22
25
 
23
26
  ## Preview
24
27
 
@@ -27,8 +30,9 @@ mado release
27
30
  mado preview
28
31
  ```
29
32
 
30
- `mado preview` сервит `out/` как статический хост: baked HTML имеет приоритет,
31
- а неизвестные пути падают в SPA fallback.
33
+ `mado preview` сервит финальный `out/` как обычный static host: сначала реальные
34
+ файлы (`/<route>/index.html`, если route был baked), потом SPA fallback в
35
+ `index.html`. Preview проверяет ровно то, что будет загружено на хостинг.
32
36
 
33
37
  ## VPS + nginx
34
38
 
@@ -37,8 +41,8 @@ mado release
37
41
  rsync -avz --delete out/ user@server:/var/www/myapp/
38
42
  ```
39
43
 
40
- В репозитории есть production `nginx.conf`: hashed bundles кешируются
41
- immutably, HTML идет с `no-cache`, deep links работают через SPA fallback.
44
+ Опциональный nginx-рецепт лежит в `docs/recipes/nginx/`: assets кешируются
45
+ immutable, HTML идет с `no-cache`, deep links работают через SPA fallback.
42
46
 
43
47
  ## Cloudflare / Netlify
44
48
 
@@ -47,9 +51,11 @@ mado release
47
51
  npx wrangler pages deploy out --project-name=myapp
48
52
  ```
49
53
 
50
- `_redirects` и `_headers` генерируются автоматически.
54
+ `_redirects` и `_headers` генерируются автоматически, если ты не положил свои.
55
+ Baked routes промотируются в реальные файлы (`out/<route>/index.html`), поэтому
56
+ static host отдаст их до SPA fallback.
51
57
 
52
- ## Cache rules
58
+ ## Cache Rules
53
59
 
54
60
  | Path | Cache-Control |
55
61
  |---|---|
@@ -26,7 +26,7 @@ globalThis.document = window.document;
26
26
  globalThis.Node = window.Node;
27
27
  globalThis.HTMLElement = window.HTMLElement;
28
28
 
29
- const { html, render } = await import("../dist/src/html.js");
29
+ const { html, render } = await import("../dist/src/html/template.js");
30
30
 
31
31
  test("renders a value", () => {
32
32
  const root = document.createElement("div");
@@ -1,9 +1,9 @@
1
- # Bake cookbook
1
+ # Bake Cookbook
2
2
 
3
3
  `mado bake` рендерит выбранные роуты в статический HTML. Это для SEO и быстрого
4
4
  первого ответа, не SSR с hydration.
5
5
 
6
- ## Минимальная страница
6
+ ## Минимальная Страница
7
7
 
8
8
  ```ts
9
9
  export default page({
@@ -23,9 +23,9 @@ export default page({
23
23
  ```
24
24
 
25
25
  В baked views лучше использовать обычные массивы (`items.map(...)`). Runtime
26
- директивы вроде `each()` нужны браузеру.
26
+ директивы вроде keyed `each()` нужны браузеру.
27
27
 
28
- ## Dynamic routes
28
+ ## Dynamic Routes
29
29
 
30
30
  ```ts
31
31
  export default page<{ slug: string }>({
@@ -40,16 +40,56 @@ export default page<{ slug: string }>({
40
40
 
41
41
  `unsafeHTML()` используй только для доверенного или заранее очищенного HTML.
42
42
 
43
- ## Manifest и output
43
+ ## Route Manifest
44
+
45
+ `mado bake` нужен source manifest:
44
46
 
45
47
  ```ts
46
48
  export const manifest = {
47
49
  "/": () => import("./pages/home.js"),
48
50
  "/blog/:slug": () => import("./pages/blog-post.js"),
49
51
  };
52
+
50
53
  export default routes(manifest);
51
54
  ```
52
55
 
53
- `mado release` создает deploy artifact в `out/`. Если bake ругается на
54
- unsupported value, значит в статическую страницу попало runtime-only значение:
55
- замени `each()` на `items.map(...)` или вынеси интерактивный кусок в клиент.
56
+ ## Output
57
+
58
+ Standalone `mado bake` по умолчанию пишет baked pages прямо в `out/`.
59
+ `mado release` сначала запускает Vite build, затем bake заменяет route HTML
60
+ на месте и пишет sitemap в `out/sitemap.xml`.
61
+
62
+ ```bash
63
+ mado release
64
+ tree out
65
+ ```
66
+
67
+ Deployable folder — `out/`, не `dist/`.
68
+
69
+ `mado release --keep-bake-dir` оставляет дополнительную копию `out/baked/`
70
+ только для debugging/inspection.
71
+
72
+ ## Client Boot
73
+
74
+ Baked HTML помечает `#app` атрибутом `data-mado-baked`. Это не hydration:
75
+ клиентский `render()` заменяет baked DOM живыми bindings при старте приложения.
76
+ Так первый ответ содержит SEO/first-paint HTML, а SPA после загрузки работает
77
+ как обычно.
78
+
79
+ ## Unsupported Values
80
+
81
+ Bake намеренно падает громко вместо записи `[object Object]`. Если baked view
82
+ ругается на unsupported directive:
83
+
84
+ - замени `each()` на `items.map(...)` в baked markup;
85
+ - интерактивные виджеты оставь в client-only routes;
86
+ - убедись, что все значения сериализуются в статический HTML.
87
+
88
+ ## Canonical Links
89
+
90
+ Передай `--base-url`, чтобы canonical links и sitemap указывали на production.
91
+
92
+ ```bash
93
+ mado bake --base-url https://example.com
94
+ mado release --base-url https://example.com
95
+ ```
@@ -9,10 +9,11 @@
9
9
  import { component, html, resource, routes, signal } from "@madojs/mado";
10
10
  ```
11
11
 
12
- Единственный публичный subpath — side-effect модуль devtools:
12
+ Публичные subpaths — side-effect модуль devtools и Vite integration:
13
13
 
14
14
  ```ts
15
15
  import "@madojs/mado/devtools.js";
16
+ import { mado } from "@madojs/mado/vite";
16
17
  ```
17
18
 
18
19
  Все остальное под `dist/src/` — деталь реализации, даже если файл виден в
@@ -27,7 +28,7 @@ import "@madojs/mado/devtools.js";
27
28
  - Templates и directives: `html`, `render`, `each`, `list`, `unsafeHTML`,
28
29
  `ref`, `classMap`, `styleMap`.
29
30
  - Components и CSS: `component`, `css`, `cssVars`.
30
- - Routing и pages: `routes`, `router`, `page`, `layout`, `nested`,
31
+ - Routing и pages: `routes`, `router`, `page`, `layout`,
31
32
  `navigate`, `queryParam`, `prefetchPath`.
32
33
  - Data: `resource`, `mutation`, `invalidate`, `jsonFetcher`, `HttpError`.
33
34
  - Forms: `useForm`.
@@ -41,7 +42,8 @@ import "@madojs/mado/devtools.js";
41
42
 
42
43
  Это не публичный API:
43
44
 
44
- - Package subpaths кроме `@madojs/mado` и `@madojs/mado/devtools.js`.
45
+ - Package subpaths кроме `@madojs/mado`, `@madojs/mado/devtools.js` и
46
+ `@madojs/mado/vite`.
45
47
  - Internals парсера/биндингов: `html/parser.js`, `html/bindings.js`,
46
48
  `ChildState`, `EachEntry`.
47
49
  - Internals роутера: `router/match.js`, `router/navigation.js`,
@@ -25,7 +25,7 @@ byte, starter copy или diagnostic string заморожены навсегд
25
25
  deferred teardown для same-tick moves, cleanup через `ctx.onDispose`.
26
26
  - Router/page/resource/form contracts, описанные в English docs.
27
27
  - Имена CLI commands и широкий смысл команд (`build`, `dev`, `release`,
28
- `bake`, `bundle`, `preview`, `init`, `new`).
28
+ `bake`, `preview`, `init`, `new`).
29
29
 
30
30
  Ломать это можно только в major version.
31
31
 
@@ -2,55 +2,81 @@
2
2
 
3
3
  > Один зрозумілий шлях. Жорсткі контракти. Мінімум магії.
4
4
 
5
- Mado — фреймворк для команд, що будують адмін-панелі, внутрішні інструменти
6
- та бізнес-SPA застосунки, які мають бути простими у розробці та нудними в
7
- підтримці. Для цього він задає **набір домовленостей**. Якщо їх дотримуватись,
8
- проєкт залишається читабельним навіть тоді, коли в ньому десятки сторінок і
9
- кілька розробників.
10
-
11
- ## Принципи
12
-
13
- 1. **Один спосіб.** Для типової задачі має бути один канонічний шлях, а не п’ять
14
- рівноправних стилів.
15
- 2. **Явність замість магії.** Немає сканерів файлів, прихованих глобалів і
16
- неочевидних side effects.
17
- 3. **Платформа спочатку.** Якщо браузер уже має потрібну можливість, Mado дає
18
- тонку обгортку, а не переписує платформу.
19
- 4. **Суворий TypeScript.** `tsc --strict` — базовий контракт.
20
- 5. **Нуль runtime-залежностей.** Кожна залежність — це довгострокове
21
- зобов’язання.
22
-
23
- ## Базова структура
24
-
25
- ```text
5
+ Mado — framework для команд, що будують admin panels, internal tools і
6
+ business SPA. Такі apps мають бути простими у розробці та нудними в підтримці,
7
+ тому Mado обирає чіткі conventions замість п'яти рівноправних стилів.
8
+
9
+ ## Principles
10
+
11
+ 1. **One way.** If code feels unusual, first check whether a canonical helper/API
12
+ already exists.
13
+ 2. **Explicit over magic.** No file-system scanners, implicit globals or hidden
14
+ side effects.
15
+ 3. **Platform first.** Web Components, History API, `<form>`, `fetch` and Shadow
16
+ DOM stay visible.
17
+ 4. **Strict types.** `tsc --strict --noUncheckedIndexedAccess` always.
18
+ 5. **No runtime dependencies.** Dev/build tooling is fine; Mado runtime stays
19
+ native.
20
+
21
+ ## Project Structure
22
+
23
+ ```txt
26
24
  src/
27
- ├── routes.ts
28
- ├── main.ts
29
- ├── pages/
30
- ├── components/
31
- ├── layouts/
32
- ├── lib/
33
- └── styles/
25
+ ├── main.ts ← boot: global CSS/providers + render router
26
+ ├── app.routes.ts ← readable app map, exports `manifest` + default routes()
27
+ ├── layouts/ ← app-zone wrappers (`page({ view: ({ child }) => ... })`)
28
+ ├── shared/ ← UI bricks, http client, pure lib, global CSS
29
+ └── modules/ ← bounded contexts
30
+ └── billing/
31
+ ├── billing.routes.ts
32
+ ├── billing.public.ts
33
+ ├── billing.types.ts
34
+ ├── pages/
35
+ ├── data/
36
+ ├── api/
37
+ └── _contracts/
38
+ ```
39
+
40
+ The default starter is the canonical version of this shape.
41
+
42
+ ## One Component = One File
43
+
44
+ ```ts
45
+ import { component, css, html } from "@madojs/mado";
46
+
47
+ component("x-user-card", () => () => html`<div class="card"><slot></slot></div>`, {
48
+ styles: css`
49
+ .card { padding: 1rem; }
50
+ `,
51
+ });
34
52
  ```
35
53
 
36
- Кожна сторінка живе в окремому файлі та експортує `page({...})`.
37
- Компоненти реєструються через `component()`. Дані читаються через `resource()`,
38
- зміни виконуються через `mutation()`, списки рендеряться через `each()`.
54
+ Importing the component file registers the element. Import it where the tag is
55
+ used.
39
56
 
40
- ## Імена компонентів
57
+ ## One Way To Describe A Page
58
+
59
+ ```ts
60
+ import { html, page, resource, jsonFetcher } from "@madojs/mado";
61
+
62
+ export default page({
63
+ title: ({ id }) => `User #${id}`,
64
+ view: ({ params }) => {
65
+ const user = resource(() => `/api/users/${params.id}`, jsonFetcher());
66
+ return html`...`;
67
+ },
68
+ });
69
+ ```
41
70
 
42
- Єдине правило браузера: ім’я custom element має містити дефіс. `x-*` у прикладах
43
- Mado це демо-конвенція, а не вимога фреймворку. У production краще брати
44
- префікс домену: `app-*`, `crm-*`, `ticket-*`, `admin-*`.
71
+ Page-local signals, resources and forms live inside `view()`. Module-wide state
72
+ lives in `*.service.ts`.
45
73
 
46
- ## Чого не робимо
74
+ ## What We Do Not Do
47
75
 
48
- - Не пишемо JSX або Vue-шаблони.
49
- - Не читаємо сигнал через `.value`; сигнал читається як функція: `count()`.
50
- - Не використовуємо `disabled=${...}` для булевих атрибутів; треба
51
- `?disabled=${...}`.
52
- - Не рендеримо динамічні списки через `.map()` там, де потрібне збереження DOM
53
- стану; використовуємо `each()`.
54
- - Не додаємо runtime-залежності без дуже вагомої причини.
76
+ - No JSX/Vue/Svelte syntax.
77
+ - No custom elements without a hyphen.
78
+ - No signal `.value`; a signal is a function.
79
+ - No direct `innerHTML`.
80
+ - No runtime packages without discussion.
55
81
 
56
- Коли є сумнів, краще додати рецепт у документацію, ніж новий primitive в core.
82
+ When in doubt, document one clear recipe instead of adding a new core primitive.
@@ -1,76 +1,70 @@
1
- # Маршрутизація
1
+ # Routing
2
2
 
3
- Mado використовує явний route manifest: один файл показує весь URL-граф
4
- застосунку.
3
+ > One app map. No folder scanners. No magic path syntax.
4
+
5
+ Mado uses an explicit route manifest. Route composition should be readable in
6
+ one place: `src/app.routes.ts`.
5
7
 
6
8
  ```ts
7
- import { routes } from "@madojs/mado";
9
+ import { layout, routes } from "@madojs/mado";
10
+ import { requireAuth } from "./modules/auth/auth.public";
11
+ import { authRoutes } from "./modules/auth/auth.routes";
12
+ import { billingRoutes } from "./modules/billing/billing.routes";
8
13
 
9
14
  export const manifest = {
10
- "/": () => import("./pages/home.js"),
11
- "/users/:id": () => import("./pages/user-detail.js"),
12
- "*": () => import("./pages/not-found.js"),
15
+ "/": () => import("./modules/home/home.page.js"),
16
+ "/login": layout({
17
+ layout: () => import("./layouts/auth-shell.layout.js"),
18
+ routes: authRoutes,
19
+ }),
20
+ "/billing": layout({
21
+ layout: () => import("./layouts/app-shell.layout.js"),
22
+ guard: requireAuth,
23
+ routes: billingRoutes,
24
+ }),
25
+ "*": () => import("./modules/home/not-found.page.js"),
13
26
  };
14
27
 
15
28
  export default routes(manifest);
16
29
  ```
17
30
 
18
- ## Сторінка
19
-
20
- ```ts
21
- import { page, html } from "@madojs/mado";
22
-
23
- export default page<{ id: string }>({
24
- title: ({ id }) => `User ${id}`,
25
- view: ({ params }) => html`<x-user data-id=${params.id}></x-user>`,
26
- });
27
- ```
31
+ Export `manifest` so `mado bake` can read it.
28
32
 
29
- Сторінка може мати `title`, `head`, `load`, `view`, `errorView` і `bake`.
30
- Маршрут може бути lazy import або готовим `page({...})`.
33
+ ## Module Routes
31
34
 
32
- ## Nested routes
35
+ Modules export plain route maps. They do not call `layout()`.
33
36
 
34
37
  ```ts
35
- import { nested, routes } from "@madojs/mado";
36
-
37
- export const manifest = {
38
- "/": () => import("./pages/home.js"),
39
- "/app": nested({
40
- layout: () => import("./layouts/app-layout.js"),
41
- routes: {
42
- "/dashboard": () => import("./pages/dashboard.js"),
43
- "/settings": () => import("./pages/settings.js"),
44
- },
45
- }),
38
+ export const billingRoutes = {
39
+ "/invoices": () => import("./pages/invoices-list.page.js"),
40
+ "/invoices/:id": () => import("./pages/invoice-detail.page.js"),
46
41
  };
47
-
48
- export default routes(manifest);
49
42
  ```
50
43
 
51
- Layout отримує дочірній view і може рендерити shell: nav, sidebar, toolbar,
52
- notifications.
44
+ The prefix is applied by `src/app.routes.ts`.
53
45
 
54
- ## Навігація
46
+ ## Page
55
47
 
56
- Посилання з `data-link` перехоплюються роутером:
48
+ ```ts
49
+ import { html, page } from "@madojs/mado";
57
50
 
58
- ```html
59
- <a href="/users/42" data-link>Open</a>
51
+ export default page<{ id: string }>({
52
+ title: ({ id }) => `User ${id}`,
53
+ view: ({ params }) => html`<h1>${params.id}</h1>`,
54
+ });
60
55
  ```
61
56
 
62
- Програмна навігація:
57
+ ## Navigation
63
58
 
64
59
  ```ts
65
- import { navigate } from "@madojs/mado";
60
+ import appRoutes from "./app.routes.js";
66
61
 
67
- navigate("/users/42");
62
+ appRoutes.navigate("/billing/invoices");
63
+ appRoutes.navigate("/billing/invoices?page=2");
64
+ appRoutes.navigate("/login", { replace: true });
68
65
  ```
69
66
 
70
- Router підтримує hover-prefetch, stale async guard, scroll-to-top для нової
71
- навігації та `dispose()` для тестів/dev overlay.
72
-
73
- ## Query params
67
+ ## Query Params
74
68
 
75
69
  ```ts
76
70
  import { queryParam } from "@madojs/mado";
@@ -79,4 +73,4 @@ const search = queryParam("q", "");
79
73
  search.set("mado");
80
74
  ```
81
75
 
82
- `queryParam()` повертає signal-like API і синхронізує стан із URL.
76
+ `queryParam()` returns a signal-like API and syncs state with the URL.
@@ -1,46 +1,73 @@
1
1
  # Структура проєкту
2
2
 
3
- Рекомендована структура Mado-застосунку:
4
-
5
- ```text
6
- src/
7
- ├── main.ts
8
- ├── routes.ts
9
- ├── pages/
10
- ├── components/
11
- ├── layouts/
12
- ├── lib/
13
- └── styles/
3
+ Кожен Mado-застосунок використовує одну канонічну форму. Це потрібно, щоб люди
4
+ й AI-асистенти однаково розуміли, де живе код.
5
+
6
+ ```txt
7
+ my-app/
8
+ ├── package.json # runtime dep: @madojs/mado
9
+ ├── tsconfig.json # strict TS, ES2022, Bundler resolution
10
+ ├── vite.config.ts # mado() from @madojs/mado/vite
11
+ ├── index.html # Vite entry + SPA shell
12
+ ├── public/ # static assets: favicon, images, robots.txt
13
+ └── src/
14
+ ├── main.ts # imports CSS and mounts router into #app
15
+ ├── app.routes.ts # app map: manifest + default routes(...)
16
+ ├── layouts/ # app-zone layouts
17
+ ├── shared/ # ui, http, lib, styles
18
+ └── modules/ # bounded contexts
19
+ └── billing/
20
+ ├── billing.routes.ts
21
+ ├── billing.public.ts
22
+ ├── billing.types.ts
23
+ ├── pages/
24
+ ├── data/
25
+ ├── api/
26
+ └── _contracts/
14
27
  ```
15
28
 
16
- ## `main.ts`
17
-
18
- Точка входу: встановлює глобальні стилі, провайдери контексту та монтує кореневий
19
- компонент у `#app`.
20
-
21
- ## `routes.ts`
22
-
23
- Єдиний manifest маршрутів. Немає file-system routing, груп у назвах папок або
24
- прихованих conventions.
25
-
26
- ## `pages/`
27
-
28
- Одна сторінка — один файл — `export default page({...})`.
29
-
30
- ## `components/`
31
-
32
- Повторно використовувані Web Components. Імпорт файлу реєструє компонент як side
33
- effect.
34
-
35
- ## `layouts/`
36
-
37
- Shell для nested routes: admin layout, marketing layout, authenticated area.
38
-
39
- ## `lib/`
40
-
41
- API-клієнти, contexts, чиста бізнес-логіка без UI.
42
-
43
- ## `styles/`
29
+ ## Artifact States
30
+
31
+ | Folder | Що це | Хто пише | Deploy? |
32
+ | --- | --- | --- | --- |
33
+ | `src/` | TypeScript sources | ви | no |
34
+ | `public/` | static assets copied as-is | ви | via `out/` |
35
+ | `out/` | deploy artifact: SPA shell + assets + baked HTML | `mado release` | yes |
36
+
37
+ `mado release` = `typecheck` + Vite build (`out/index.html`, `out/assets/`,
38
+ `public/*`) + `bake` directly into route paths + `sitemap.xml` + precompression.
39
+
40
+ ## Where To Put Files
41
+
42
+ | What | Where |
43
+ | --- | --- |
44
+ | Page for a new URL | `src/modules/<module>/pages/<name>.page.ts` + module routes |
45
+ | Module route map | `src/modules/<module>/<module>.routes.ts` |
46
+ | App shell/layout | `src/layouts/<zone>.layout.ts` |
47
+ | Shared UI widget | `src/shared/ui/<x-name>.component.ts` |
48
+ | Module-only UI widget | `src/modules/<module>/components/<name>.component.ts` |
49
+ | API connector | `src/modules/<module>/api/<provider>.connector.ts` |
50
+ | Data resource/mutation | `src/modules/<module>/data/<name>.resource.ts` |
51
+ | Auth/session | `src/modules/auth/` |
52
+ | Public module surface | `src/modules/<module>/<module>.public.ts` |
53
+ | Pure function without UI | `src/shared/lib/<name>.ts` |
54
+ | Static image / favicon | `public/<file>` |
55
+ | App-zone shell CSS | `src/shared/styles/shell.css` |
56
+ | Page-level CSS | `src/shared/styles/content.css` |
57
+
58
+ ## Vite Config
59
+
60
+ ```ts
61
+ import { defineConfig } from "vite";
62
+ import { mado } from "@madojs/mado/vite";
63
+
64
+ export default defineConfig({
65
+ plugins: [mado()],
66
+ css: {
67
+ transformer: "lightningcss",
68
+ },
69
+ });
70
+ ```
44
71
 
45
- Глобальні tokens або shared CSS через `css```. Для app-shell часто зручно
46
- використовувати Light DOM, для leaf-компонентів — Shadow DOM.
72
+ Starter uses Vite's Lightning CSS transformer. Mado does not own prefixing, CSS
73
+ lowering or minification.
@@ -42,8 +42,7 @@ export default page<{ slug: string }, Product>({
42
42
  ## Edge prerender
43
43
 
44
44
  Для великих наборів сторінок можна робити той самий підхід на edge: Cloudflare
45
- Worker генерує HTML на cache miss, кладе в KV і віддає з TTL. Приклад лежить в
46
- `examples/cloudflare`.
45
+ Worker генерує HTML на cache miss, кладе в KV і віддає з TTL.
47
46
 
48
47
  Це не hydration. Клієнтський Mado-застосунок все одно стартує нормально і
49
48
  перерендерює сторінку після завантаження.
@@ -7,7 +7,7 @@
7
7
  |---|---|
8
8
  | router | `routes()` |
9
9
  | handler | `page().view` |
10
- | middleware/layout | `nested()` + layout |
10
+ | middleware/layout | `layout()` route group |
11
11
  | cache get-or-set | `resource()` |
12
12
  | POST/PUT/DELETE | `mutation()` |
13
13
  | cache invalidation | `invalidates` / `invalidate()` |
@@ -44,8 +44,8 @@ Mado використовує schema-based validation, близьку до HTML
44
44
 
45
45
  ## Auth
46
46
 
47
- Auth зазвичай живе в `lib/auth.ts` як signal/context. Protected area зручно
48
- робити через nested layout, який перевіряє session і показує dashboard або
47
+ Auth зазвичай живе в `modules/auth` як signal/context. Protected area зручно
48
+ робити через `layout()` group, який перевіряє session і показує dashboard або
49
49
  redirect/login.
50
50
 
51
51
  ## Правило