@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.
- package/AGENTS.md +24 -26
- package/CHANGELOG.md +98 -0
- package/README.md +18 -45
- package/TODO.md +52 -48
- package/dist/src/component.d.ts +2 -1
- package/dist/src/component.js +5 -2
- package/dist/src/component.js.map +1 -1
- package/dist/src/each.d.ts +1 -1
- package/dist/src/each.js +1 -1
- package/dist/src/each.js.map +1 -1
- package/dist/src/html/template.js +10 -0
- package/dist/src/html/template.js.map +1 -1
- package/dist/src/index.d.ts +11 -6
- package/dist/src/index.js +5 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/lazy.d.ts +1 -1
- package/dist/src/lazy.js +1 -1
- package/dist/src/lazy.js.map +1 -1
- package/dist/src/page.d.ts +17 -21
- package/dist/src/page.js +7 -12
- package/dist/src/page.js.map +1 -1
- package/dist/src/router/manifest.d.ts +1 -1
- package/dist/src/router/manifest.js +21 -13
- package/dist/src/router/manifest.js.map +1 -1
- package/dist/src/router/match.d.ts +2 -2
- package/dist/src/router/match.js +3 -3
- package/dist/src/router/match.js.map +1 -1
- package/dist/src/router/navigation.js +1 -1
- package/dist/src/router/navigation.js.map +1 -1
- package/dist/src/vite/index.d.ts +10 -0
- package/dist/src/vite/index.js +33 -0
- package/dist/src/vite/index.js.map +1 -0
- package/docs/en/00-the-mado-way.md +25 -12
- package/docs/en/01-routing.md +90 -142
- package/docs/en/02-project-layout.md +59 -52
- package/docs/en/03-static-bake.md +5 -6
- package/docs/en/05-why-mado.md +6 -6
- package/docs/en/06-for-backenders.md +18 -22
- package/docs/en/08-llm-zero-history-test.md +9 -14
- package/docs/en/09-shadow-vs-light-dom.md +28 -36
- package/docs/en/10-app-architecture.md +158 -96
- package/docs/en/11-layouts.md +22 -24
- package/docs/en/12-auth-and-api.md +89 -182
- package/docs/en/13-deployment.md +25 -26
- package/docs/en/14-testing.md +4 -4
- package/docs/en/16-bake-cookbook.md +17 -10
- package/docs/en/18-api-freeze-map.md +6 -4
- package/docs/en/20-v1-stability.md +1 -1
- package/docs/fr/00-the-mado-way.md +55 -90
- package/docs/fr/01-routing.md +70 -152
- package/docs/fr/02-project-layout.md +74 -48
- package/docs/fr/03-static-bake.md +1 -1
- package/docs/fr/05-why-mado.md +6 -6
- package/docs/fr/06-for-backenders.md +7 -7
- package/docs/fr/08-llm-zero-history-test.md +21 -48
- package/docs/fr/09-shadow-vs-light-dom.md +43 -162
- package/docs/fr/10-app-architecture.md +110 -33
- package/docs/fr/11-layouts.md +24 -12
- package/docs/fr/12-auth-and-api.md +63 -22
- package/docs/fr/13-deployment.md +30 -12
- package/docs/fr/14-testing.md +1 -1
- package/docs/fr/16-bake-cookbook.md +57 -4
- package/docs/fr/18-api-freeze-map.md +1 -1
- package/docs/fr/20-v1-stability.md +1 -1
- package/docs/recipes/nginx/README.md +13 -0
- package/docs/ru/00-the-mado-way.md +53 -75
- package/docs/ru/01-routing.md +68 -143
- package/docs/ru/02-project-layout.md +75 -48
- package/docs/ru/03-static-bake.md +2 -2
- package/docs/ru/05-why-mado.md +6 -6
- package/docs/ru/06-for-backenders.md +7 -7
- package/docs/ru/08-llm-zero-history-test.md +9 -14
- package/docs/ru/09-shadow-vs-light-dom.md +43 -178
- package/docs/ru/10-app-architecture.md +115 -63
- package/docs/ru/11-layouts.md +24 -24
- package/docs/ru/12-auth-and-api.md +57 -35
- package/docs/ru/13-deployment.md +19 -13
- package/docs/ru/14-testing.md +1 -1
- package/docs/ru/16-bake-cookbook.md +48 -8
- package/docs/ru/18-api-freeze-map.md +5 -3
- package/docs/ru/20-v1-stability.md +1 -1
- package/docs/uk/00-the-mado-way.md +70 -44
- package/docs/uk/01-routing.md +41 -47
- package/docs/uk/02-project-layout.md +68 -41
- package/docs/uk/03-static-bake.md +1 -2
- package/docs/uk/06-for-backenders.md +3 -3
- package/docs/uk/08-llm-zero-history-test.md +22 -24
- package/docs/uk/09-shadow-vs-light-dom.md +37 -86
- package/docs/uk/10-app-architecture.md +72 -31
- package/docs/uk/11-layouts.md +25 -12
- package/docs/uk/12-auth-and-api.md +58 -22
- package/docs/uk/13-deployment.md +4 -3
- package/docs/uk/14-testing.md +1 -1
- package/docs/uk/18-api-freeze-map.md +1 -1
- package/docs/uk/20-v1-stability.md +1 -1
- package/llms.txt +14 -15
- package/package.json +18 -11
- package/scripts/_config.mjs +15 -161
- package/scripts/bake.mjs +71 -58
- package/scripts/cli/generate.mjs +348 -0
- package/scripts/cli/help.mjs +27 -0
- package/scripts/cli/index.mjs +79 -0
- package/scripts/cli/init.mjs +153 -0
- package/scripts/cli/release.mjs +152 -0
- package/scripts/cli/run.mjs +96 -0
- package/scripts/cli.mjs +2 -560
- package/scripts/package-smoke.mjs +4 -1
- package/scripts/preview.mjs +17 -61
- package/scripts/size-budget.mjs +5 -2
- package/scripts/vite.default.mjs +11 -0
- package/starters/default/.editorconfig +12 -0
- package/starters/default/README.md +74 -0
- package/starters/default/eslint.config.mjs +256 -0
- package/starters/default/index.html +13 -0
- package/starters/default/package.json +30 -0
- package/starters/default/public/favicon.svg +4 -0
- package/starters/default/src/app.routes.ts +39 -0
- package/starters/default/src/layouts/app-shell.layout.ts +35 -0
- package/starters/default/src/layouts/auth-shell.layout.ts +17 -0
- package/starters/default/src/main.ts +16 -0
- package/starters/default/src/modules/auth/_contracts/auth-api.types.ts +17 -0
- package/starters/default/src/modules/auth/auth.connector.ts +45 -0
- package/starters/default/src/modules/auth/auth.guard.ts +22 -0
- package/starters/default/src/modules/auth/auth.public.ts +9 -0
- package/starters/default/src/modules/auth/auth.routes.ts +8 -0
- package/starters/default/src/modules/auth/auth.service.ts +71 -0
- package/starters/default/src/modules/auth/auth.types.ts +15 -0
- package/starters/default/src/modules/auth/login.page.ts +62 -0
- package/starters/default/src/modules/billing/_contracts/stripe.types.ts +17 -0
- package/starters/default/src/modules/billing/api/stripe.connector.ts +71 -0
- package/starters/default/src/modules/billing/billing.public.ts +5 -0
- package/starters/default/src/modules/billing/billing.routes.ts +9 -0
- package/starters/default/src/modules/billing/billing.types.ts +15 -0
- package/starters/default/src/modules/billing/components/invoice-status-badge.component.ts +43 -0
- package/starters/default/src/modules/billing/data/invoices.resource.ts +35 -0
- package/starters/default/src/modules/billing/pages/invoice-detail.page.ts +70 -0
- package/starters/default/src/modules/billing/pages/invoices-list.page.ts +73 -0
- package/starters/default/src/modules/home/home.page.ts +34 -0
- package/starters/default/src/modules/home/not-found.page.ts +11 -0
- package/starters/default/src/shared/http/http-client.ts +86 -0
- package/starters/default/src/shared/http/http-error.ts +37 -0
- package/starters/default/src/shared/http/interceptors.ts +59 -0
- package/starters/default/src/shared/lib/format-date.ts +19 -0
- package/starters/default/src/shared/styles/content.css +70 -0
- package/starters/default/src/shared/styles/reset.css +32 -0
- package/starters/default/src/shared/styles/shell.css +57 -0
- package/starters/default/src/shared/styles/tokens.css +44 -0
- package/starters/default/src/shared/ui/x-button.component.ts +49 -0
- package/starters/default/src/shared/ui/x-spinner.component.ts +22 -0
- package/starters/default/src/styles.d.ts +1 -0
- package/starters/default/src/vite-env.d.ts +1 -0
- package/starters/default/tsconfig.json +24 -0
- package/starters/default/vite.config.ts +9 -0
- package/MADO_V1_PLAN.md +0 -179
- package/ROADMAP.md +0 -178
- package/dist/src/html.d.ts +0 -18
- package/dist/src/html.js +0 -17
- package/dist/src/html.js.map +0 -1
- package/dist/src/router.d.ts +0 -13
- package/dist/src/router.js +0 -13
- package/dist/src/router.js.map +0 -1
- package/scripts/bundle.mjs +0 -212
- package/scripts/llm-zero-history-smoke.mjs +0 -93
- package/scripts/new.mjs +0 -80
- package/scripts/showcase-regression.mjs +0 -392
- package/server/serve.mjs +0 -455
- package/starters/admin/README.md +0 -63
- package/starters/admin/index.html +0 -28
- package/starters/admin/mado.config.json +0 -22
- package/starters/admin/package.json +0 -24
- package/starters/admin/public/favicon.svg +0 -4
- package/starters/admin/src/components/x-button.ts +0 -82
- package/starters/admin/src/components/x-input.ts +0 -105
- package/starters/admin/src/layouts/app.ts +0 -101
- package/starters/admin/src/layouts/auth.ts +0 -41
- package/starters/admin/src/lib/api.ts +0 -184
- package/starters/admin/src/lib/auth.ts +0 -83
- package/starters/admin/src/main.ts +0 -15
- package/starters/admin/src/pages/admin/dashboard.ts +0 -48
- package/starters/admin/src/pages/admin/order-detail.ts +0 -80
- package/starters/admin/src/pages/admin/orders.ts +0 -117
- package/starters/admin/src/pages/home.ts +0 -34
- package/starters/admin/src/pages/login.ts +0 -70
- package/starters/admin/src/pages/not-found.ts +0 -12
- package/starters/admin/src/routes.ts +0 -40
- package/starters/admin/src/styles/global.ts +0 -86
- package/starters/admin/tsconfig.json +0 -15
- package/starters/crud/README.md +0 -33
- package/starters/crud/index.html +0 -28
- package/starters/crud/mado.config.json +0 -20
- package/starters/crud/package.json +0 -24
- package/starters/crud/src/components/app-shell.ts +0 -56
- package/starters/crud/src/components/ticket-detail.ts +0 -33
- package/starters/crud/src/components/ticket-form.ts +0 -69
- package/starters/crud/src/components/ticket-list.ts +0 -66
- package/starters/crud/src/lib/api.ts +0 -76
- package/starters/crud/src/main.ts +0 -9
- package/starters/crud/src/pages/home.ts +0 -34
- package/starters/crud/src/pages/not-found.ts +0 -12
- package/starters/crud/src/pages/ticket-detail.ts +0 -7
- package/starters/crud/src/pages/ticket-new.ts +0 -7
- package/starters/crud/src/pages/tickets.ts +0 -7
- package/starters/crud/src/routes.ts +0 -11
- package/starters/crud/src/styles/global.ts +0 -155
- package/starters/crud/tsconfig.json +0 -15
- package/starters/minimal/README.md +0 -21
- package/starters/minimal/index.html +0 -28
- package/starters/minimal/mado.config.json +0 -20
- package/starters/minimal/package.json +0 -24
- package/starters/minimal/src/components/app-counter.ts +0 -31
- package/starters/minimal/src/main.ts +0 -9
- package/starters/minimal/src/pages/home.ts +0 -35
- package/starters/minimal/src/pages/not-found.ts +0 -14
- package/starters/minimal/src/routes.ts +0 -8
- package/starters/minimal/src/styles/global.ts +0 -60
- package/starters/minimal/tsconfig.json +0 -15
- package/templates/page-detail.ts +0 -63
- package/templates/page-form.ts +0 -94
- package/templates/page-list.ts +0 -79
|
@@ -1,36 +1,34 @@
|
|
|
1
1
|
# LLM Zero-History Test
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Mado
|
|
3
|
+
This document defines a manual validation test: can a fresh LLM write idiomatic
|
|
4
|
+
Mado without falling back to React-shaped code?
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Allowed Context
|
|
7
7
|
|
|
8
8
|
- `AGENTS.md`
|
|
9
9
|
- `README.md`
|
|
10
|
-
- `docs/uk/07-llm-pitfalls.md`
|
|
11
|
-
- `examples
|
|
12
|
-
|
|
10
|
+
- `docs/uk/07-llm-pitfalls.md` or the English version
|
|
11
|
+
- files from the external `madojs-examples` workspace only when the agent asks
|
|
12
|
+
for a larger app pattern
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## Task
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
- Немає signal `.value`.
|
|
18
|
-
- Reactive child bindings з `count()` обгорнуті у `() =>`.
|
|
19
|
-
- Boolean attributes пишуться як `?disabled`, `?checked`.
|
|
20
|
-
- Динамічні списки використовують `each()`.
|
|
21
|
-
- Imports мають `.js`.
|
|
22
|
-
- `resource()` створюється в lifecycle-aware контексті.
|
|
16
|
+
Build a small ticket-admin SPA:
|
|
23
17
|
|
|
24
|
-
|
|
18
|
+
- routes: `/`, `/tickets`, `/tickets/new`, `/tickets/:id`, `*`;
|
|
19
|
+
- in-memory mock API with realistic async delays;
|
|
20
|
+
- list page with `resource()`, `queryParam()`, `computed()` and keyed `each()`;
|
|
21
|
+
- create/edit flows with `useForm()` + `mutation()` + `invalidates`;
|
|
22
|
+
- local UI state with `signal()`.
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
resources, mutations, invalidation, `queryParam`, `computed`, `signal` і
|
|
28
|
-
keyed lists.
|
|
24
|
+
## Failure Checklist
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
`
|
|
33
|
-
|
|
26
|
+
- JSX, `useState`, `useEffect`, `ref`, `$state`, class-style components;
|
|
27
|
+
- `${signal()}` where a reactive child thunk is required;
|
|
28
|
+
- `disabled=${...}` instead of `?disabled=${...}`;
|
|
29
|
+
- unkeyed `.map()` for dynamic lists;
|
|
30
|
+
- `resource()` created outside lifecycle-aware context;
|
|
31
|
+
- new runtime dependencies or new public APIs.
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
The historical tickets implementation lives in the external examples workspace.
|
|
34
|
+
The core repository no longer ships that artifact.
|
|
@@ -1,107 +1,58 @@
|
|
|
1
1
|
# Shadow DOM vs Light DOM
|
|
2
2
|
|
|
3
|
-
Mado
|
|
4
|
-
|
|
3
|
+
Mado components use Shadow DOM by default. This is good for self-contained
|
|
4
|
+
widgets, but app zones and pages usually stay as light DOM templates.
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## Rule
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
UI-дерева — app shell, sidebar, modal, table, page section — за замовчуванням
|
|
10
|
-
робіть Web Component через `component()`.
|
|
11
|
-
|
|
12
|
-
Звичайні функції залишайте для маленьких inline helpers:
|
|
13
|
-
|
|
14
|
-
```ts
|
|
15
|
-
const money = (value: number) => html`<span>${formatMoney(value)}</span>`;
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Не варто робити app shell функцією в public examples. Це працює, але ховає
|
|
19
|
-
browser model замість того, щоб її пояснювати.
|
|
20
|
-
|
|
21
|
-
Використовуйте **Shadow DOM** для leaf widgets:
|
|
22
|
-
|
|
23
|
-
- buttons, badges, cards, metrics;
|
|
24
|
-
- modals, toasts, small visual components;
|
|
25
|
-
- embedded widgets, які не мають випадково успадковувати app CSS;
|
|
26
|
-
- components, чиї styles належать самому component.
|
|
27
|
-
|
|
28
|
-
Використовуйте **Light DOM** (`{ shadow: false }`) для app structure, якій
|
|
29
|
-
потрібні global CSS utilities:
|
|
30
|
-
|
|
31
|
-
- route/page components;
|
|
32
|
-
- admin screens з dense table/form layouts;
|
|
33
|
-
- data-heavy screens з tables and forms;
|
|
34
|
-
- місця, де children мають залишатися normal document DOM.
|
|
35
|
-
|
|
36
|
-
Використовуйте **Shadow DOM** для slot-based layouts:
|
|
37
|
-
|
|
38
|
-
- app shells, які render `<slot>`;
|
|
39
|
-
- sidebar/content wrappers;
|
|
40
|
-
- reusable layout frames, які володіють своїм grid/header/sidebar CSS.
|
|
41
|
-
|
|
42
|
-
`<slot>` — це feature Shadow DOM. У component з `shadow: false` тег `<slot>` є
|
|
43
|
-
звичайним DOM element і не переносить children у це місце layout.
|
|
44
|
-
|
|
45
|
-
## Як працює import
|
|
8
|
+
Use route layouts for app zones:
|
|
46
9
|
|
|
47
10
|
```ts
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
11
|
+
export default page({
|
|
12
|
+
view: ({ child }) => html`<main class="app-main">${child}</main>`,
|
|
13
|
+
});
|
|
51
14
|
```
|
|
52
15
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
React-style component value, який передається як function.
|
|
56
|
-
|
|
57
|
-
## Routing and links
|
|
16
|
+
These files live in `src/layouts/` and are composed from `src/app.routes.ts`
|
|
17
|
+
with `layout()`. They are styled by `src/shared/styles/shell.css`.
|
|
58
18
|
|
|
59
|
-
|
|
60
|
-
`event.composedPath()`.
|
|
19
|
+
Use page files for screens:
|
|
61
20
|
|
|
62
21
|
```ts
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
22
|
+
export default page({
|
|
23
|
+
view: () => html`<section><h1>Users</h1></section>`,
|
|
24
|
+
});
|
|
66
25
|
```
|
|
67
26
|
|
|
68
|
-
|
|
27
|
+
Page-level tables, forms, prose and simple states are styled by
|
|
28
|
+
`src/shared/styles/content.css`.
|
|
69
29
|
|
|
70
|
-
|
|
30
|
+
Use Shadow DOM components for leaf widgets:
|
|
71
31
|
|
|
72
|
-
|
|
73
|
-
|
|
32
|
+
- buttons, badges, cards, metrics;
|
|
33
|
+
- spinners, modals, toasts;
|
|
34
|
+
- widgets that should own their CSS.
|
|
74
35
|
|
|
75
36
|
```ts
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
37
|
+
component("x-status-badge", ({ attr }) => {
|
|
38
|
+
const status = attr("status", "draft");
|
|
39
|
+
return () => html`<span>${status}</span>`;
|
|
40
|
+
}, {
|
|
41
|
+
styles: css`
|
|
42
|
+
:host { display: inline-block; }
|
|
43
|
+
span { color: var(--color-text-muted); }
|
|
44
|
+
`,
|
|
45
|
+
});
|
|
81
46
|
```
|
|
82
47
|
|
|
83
|
-
|
|
84
|
-
`<ticket-list>`. File має бути imported десь першим. Після import він викликає
|
|
85
|
-
`customElements.define(...)`, і tag стає відомим у поточному document.
|
|
86
|
-
|
|
87
|
-
Не робіть bulk-import усіх components у `main.ts` "just in case". Це працює в
|
|
88
|
-
tiny demos, але ховає ownership і ламає lazy route loading. Краще:
|
|
89
|
-
|
|
90
|
-
- global app shell/providers імпортувати в `main.ts`;
|
|
91
|
-
- components, якими володіє одна page, імпортувати в цій page;
|
|
92
|
-
- shared feature components імпортувати у feature entry page;
|
|
93
|
-
- truly global leaf components імпортувати в `main.ts` лише якщо вони реально
|
|
94
|
-
використовуються всюди.
|
|
95
|
-
|
|
96
|
-
## Showcase lesson
|
|
97
|
-
|
|
98
|
-
`examples/showcase` використовує цей split навмисно:
|
|
48
|
+
## Style Behavior
|
|
99
49
|
|
|
100
|
-
- `
|
|
101
|
-
- `
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
|
|
50
|
+
- `tokens.css` defines CSS custom properties; `var(...)` crosses Shadow DOM.
|
|
51
|
+
- `reset.css`, `shell.css`, `content.css` apply only to document/light DOM.
|
|
52
|
+
- Class selectors like `.data`, `.app-main`, `.error` do not cross Shadow DOM.
|
|
53
|
+
- Component-local styles live in ``css`...` `` inside `component()` options.
|
|
54
|
+
- If a Shadow component accepts children, use `<slot>` and style the frame in
|
|
55
|
+
component styles.
|
|
105
56
|
|
|
106
|
-
|
|
107
|
-
|
|
57
|
+
If a page looks unstyled, you probably used global classes inside a Shadow DOM
|
|
58
|
+
component. Move markup into a page/layout or move CSS into component styles.
|
|
@@ -1,56 +1,97 @@
|
|
|
1
1
|
# Архітектура застосунку
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Офіційний starter — канонічна production-форма Mado-застосунку. Це не
|
|
4
|
+
framework всередині framework: лише files, imports, Mado primitives та ESLint
|
|
5
|
+
boundaries.
|
|
6
6
|
|
|
7
7
|
```txt
|
|
8
8
|
src/
|
|
9
9
|
├── main.ts
|
|
10
|
-
├── routes.ts
|
|
10
|
+
├── app.routes.ts
|
|
11
11
|
├── layouts/
|
|
12
|
-
├──
|
|
13
|
-
|
|
14
|
-
├──
|
|
15
|
-
|
|
12
|
+
│ ├── app-shell.layout.ts
|
|
13
|
+
│ └── auth-shell.layout.ts
|
|
14
|
+
├── shared/
|
|
15
|
+
│ ├── http/
|
|
16
|
+
│ ├── lib/
|
|
17
|
+
│ ├── styles/
|
|
18
|
+
│ └── ui/
|
|
19
|
+
└── modules/
|
|
20
|
+
├── auth/
|
|
21
|
+
│ ├── auth.routes.ts
|
|
22
|
+
│ ├── auth.public.ts
|
|
23
|
+
│ ├── auth.service.ts
|
|
24
|
+
│ ├── auth.connector.ts
|
|
25
|
+
│ ├── auth.guard.ts
|
|
26
|
+
│ ├── login.page.ts
|
|
27
|
+
│ └── _contracts/
|
|
28
|
+
└── billing/
|
|
29
|
+
├── billing.routes.ts
|
|
30
|
+
├── billing.public.ts
|
|
31
|
+
├── billing.types.ts
|
|
32
|
+
├── api/
|
|
33
|
+
├── data/
|
|
34
|
+
├── pages/
|
|
35
|
+
├── components/
|
|
36
|
+
└── _contracts/
|
|
16
37
|
```
|
|
17
38
|
|
|
18
|
-
`
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
import { html, render } from "@madojs/mado";
|
|
23
|
-
import "./styles/global.js";
|
|
24
|
-
import routesApi from "./routes.js";
|
|
25
|
-
|
|
26
|
-
render(html`${routesApi.view}`, document.getElementById("app")!);
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Feature-компоненти імпортує сторінка, яка їх рендерить.
|
|
39
|
+
`src/app.routes.ts` is the app map. Modules export plain route maps; app routes
|
|
40
|
+
decide which shell and guard wrap each zone.
|
|
30
41
|
|
|
31
42
|
```ts
|
|
32
43
|
import { layout, routes } from "@madojs/mado";
|
|
33
|
-
import { requireAuth } from "./
|
|
44
|
+
import { requireAuth } from "./modules/auth/auth.public";
|
|
45
|
+
import { authRoutes } from "./modules/auth/auth.routes";
|
|
46
|
+
import { billingRoutes } from "./modules/billing/billing.routes";
|
|
34
47
|
|
|
35
48
|
export const manifest = {
|
|
36
|
-
"/": () => import("./
|
|
37
|
-
"/
|
|
38
|
-
layout: () => import("./layouts/
|
|
49
|
+
"/": () => import("./modules/home/home.page"),
|
|
50
|
+
"/login": layout({
|
|
51
|
+
layout: () => import("./layouts/auth-shell.layout"),
|
|
52
|
+
routes: authRoutes,
|
|
53
|
+
}),
|
|
54
|
+
"/billing": layout({
|
|
55
|
+
layout: () => import("./layouts/app-shell.layout"),
|
|
39
56
|
guard: requireAuth,
|
|
40
|
-
routes:
|
|
57
|
+
routes: billingRoutes,
|
|
41
58
|
}),
|
|
42
|
-
"*": () => import("./
|
|
59
|
+
"*": () => import("./modules/home/not-found.page"),
|
|
43
60
|
};
|
|
44
61
|
|
|
45
62
|
export default routes(manifest);
|
|
46
63
|
```
|
|
47
64
|
|
|
48
|
-
|
|
49
|
-
|
|
65
|
+
Page-local signals, resources and forms live inside `view()`. Module-wide state
|
|
66
|
+
lives in `*.service.ts`.
|
|
67
|
+
|
|
68
|
+
## Styles
|
|
69
|
+
|
|
70
|
+
| File | Role |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| `src/shared/styles/tokens.css` | design tokens as CSS custom properties |
|
|
73
|
+
| `src/shared/styles/reset.css` | document/light DOM reset |
|
|
74
|
+
| `src/shared/styles/shell.css` | app-zone layouts from `src/layouts/` |
|
|
75
|
+
| `src/shared/styles/content.css` | page-level forms, tables, prose and states |
|
|
76
|
+
|
|
77
|
+
Leaf components keep their own styles in ``css`...` `` inside `component()`
|
|
78
|
+
options and depend on tokens, not global classes.
|
|
79
|
+
|
|
80
|
+
`vite.config.ts` uses Vite's Lightning CSS transformer. Mado does not own
|
|
81
|
+
prefixing, CSS lowering or minification.
|
|
82
|
+
|
|
83
|
+
## CLI
|
|
50
84
|
|
|
51
85
|
```bash
|
|
52
|
-
mado
|
|
53
|
-
mado
|
|
86
|
+
mado new module billing
|
|
87
|
+
mado new page billing/pages/invoices-list
|
|
88
|
+
mado new connector billing/api/stripe
|
|
89
|
+
mado new resource billing/data/invoices
|
|
90
|
+
mado new service billing/cart
|
|
91
|
+
mado new form billing/invoice
|
|
92
|
+
mado new component billing/components/invoice-status-badge
|
|
93
|
+
mado new guard billing/billing
|
|
94
|
+
mado new layout app-shell
|
|
54
95
|
```
|
|
55
96
|
|
|
56
|
-
|
|
97
|
+
The generator writes files only and does not edit `app.routes.ts`.
|
package/docs/uk/11-layouts.md
CHANGED
|
@@ -1,34 +1,47 @@
|
|
|
1
1
|
# Layouts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The blessed layout recipe in Mado is a route group in `src/app.routes.ts`.
|
|
4
|
+
Do not put a single global shell in `main.ts` when the app has multiple zones:
|
|
5
|
+
public, auth, app, embed.
|
|
4
6
|
|
|
5
7
|
```ts
|
|
6
8
|
import { layout, routes } from "@madojs/mado";
|
|
7
|
-
import { requireAuth } from "./
|
|
9
|
+
import { requireAuth } from "./modules/auth/auth.public";
|
|
10
|
+
import { authRoutes } from "./modules/auth/auth.routes";
|
|
11
|
+
import { billingRoutes } from "./modules/billing/billing.routes";
|
|
8
12
|
|
|
9
13
|
export const manifest = {
|
|
10
|
-
"/": () => import("./
|
|
14
|
+
"/": () => import("./modules/home/home.page.js"),
|
|
11
15
|
"/login": layout({
|
|
12
|
-
layout: () => import("./layouts/auth.js"),
|
|
13
|
-
routes:
|
|
16
|
+
layout: () => import("./layouts/auth-shell.layout.js"),
|
|
17
|
+
routes: authRoutes,
|
|
14
18
|
}),
|
|
15
|
-
"/
|
|
16
|
-
layout: () => import("./layouts/app.js"),
|
|
19
|
+
"/billing": layout({
|
|
20
|
+
layout: () => import("./layouts/app-shell.layout.js"),
|
|
17
21
|
guard: requireAuth,
|
|
18
|
-
routes:
|
|
22
|
+
routes: billingRoutes,
|
|
19
23
|
}),
|
|
24
|
+
"*": () => import("./modules/home/not-found.page.js"),
|
|
20
25
|
};
|
|
21
26
|
|
|
22
27
|
export default routes(manifest);
|
|
23
28
|
```
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
A layout is a normal `page({ view })` that renders `child`:
|
|
26
31
|
|
|
27
32
|
```ts
|
|
28
33
|
export default page({
|
|
29
|
-
view: ({ child }) => html
|
|
34
|
+
view: ({ child }) => html`
|
|
35
|
+
<div class="layout layout--app">
|
|
36
|
+
<main class="app-main">${child}</main>
|
|
37
|
+
</div>
|
|
38
|
+
`,
|
|
30
39
|
});
|
|
31
40
|
```
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
Rules:
|
|
43
|
+
|
|
44
|
+
- one shell per route group, not per page;
|
|
45
|
+
- modules export plain route maps and do not call `layout()`;
|
|
46
|
+
- guard on a group protects the whole subtree;
|
|
47
|
+
- layout view stays stateless; page-local state lives in pages/components/resources.
|
|
@@ -1,34 +1,70 @@
|
|
|
1
|
-
# Auth
|
|
1
|
+
# Auth and API
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The default starter is the blessed recipe. HTTP mechanics live in
|
|
4
|
+
`src/shared/http/`, auth state lives in `src/modules/auth/`.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
```txt
|
|
7
|
+
src/shared/http/
|
|
8
|
+
http-client.ts
|
|
9
|
+
http-error.ts
|
|
10
|
+
interceptors.ts
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
src/modules/auth/
|
|
13
|
+
auth.connector.ts
|
|
14
|
+
auth.service.ts
|
|
15
|
+
auth.guard.ts
|
|
16
|
+
auth.routes.ts
|
|
17
|
+
auth.public.ts
|
|
18
|
+
_contracts/
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Business module flow:
|
|
22
|
+
|
|
23
|
+
```txt
|
|
24
|
+
connector -> resource/mutation -> page
|
|
25
|
+
```
|
|
10
26
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
27
|
+
Pages do not import DTOs and do not call `fetch()` directly. Connectors do not
|
|
28
|
+
import Mado reactivity or UI.
|
|
29
|
+
|
|
30
|
+
## Auth Service
|
|
15
31
|
|
|
16
32
|
```ts
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
33
|
+
const _user = signal<User | null>(null);
|
|
34
|
+
const _token = signal<string | null>(null);
|
|
35
|
+
|
|
36
|
+
export const user = () => _user();
|
|
37
|
+
export const isAuthed = computed(() => _user() !== null);
|
|
22
38
|
```
|
|
23
39
|
|
|
24
|
-
|
|
40
|
+
Expose only what other modules need through `auth.public.ts`.
|
|
25
41
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
42
|
+
## Guards
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
export function requireAuth(): boolean | string {
|
|
46
|
+
if (isAuthed()) return true;
|
|
47
|
+
return "/login";
|
|
31
48
|
}
|
|
32
49
|
```
|
|
33
50
|
|
|
34
|
-
|
|
51
|
+
Use in `src/app.routes.ts`:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
"/billing": layout({
|
|
55
|
+
layout: () => import("./layouts/app-shell.layout"),
|
|
56
|
+
guard: requireAuth,
|
|
57
|
+
routes: billingRoutes,
|
|
58
|
+
}),
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Dev Proxy
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
export default defineConfig({
|
|
65
|
+
plugins: [mado()],
|
|
66
|
+
server: {
|
|
67
|
+
proxy: { "/api": "http://localhost:3000" },
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
```
|
package/docs/uk/13-deployment.md
CHANGED
|
@@ -12,7 +12,8 @@ mado release
|
|
|
12
12
|
out/
|
|
13
13
|
├── index.html
|
|
14
14
|
├── assets/
|
|
15
|
-
├──
|
|
15
|
+
├── <route>/index.html
|
|
16
|
+
├── sitemap.xml
|
|
16
17
|
├── _redirects
|
|
17
18
|
└── _headers
|
|
18
19
|
```
|
|
@@ -35,5 +36,5 @@ mado release
|
|
|
35
36
|
rsync -avz --delete out/ user@server:/var/www/myapp/
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
HTML та fallback для deep links.
|
|
39
|
+
Опційний nginx recipe живе в `docs/recipes/nginx/`: immutable cache для
|
|
40
|
+
`/assets/*`, no-cache для HTML та fallback для deep links.
|
package/docs/uk/14-testing.md
CHANGED
|
@@ -20,7 +20,7 @@ const { window } = parseHTML("<!doctype html><html><body></body></html>");
|
|
|
20
20
|
globalThis.window = window;
|
|
21
21
|
globalThis.document = window.document;
|
|
22
22
|
|
|
23
|
-
const { html, render } = await import("../dist/src/html.js");
|
|
23
|
+
const { html, render } = await import("../dist/src/html/template.js");
|
|
24
24
|
|
|
25
25
|
test("renders", () => {
|
|
26
26
|
const root = document.createElement("div");
|
|
@@ -27,7 +27,7 @@ import "@madojs/mado/devtools.js";
|
|
|
27
27
|
- Templates і directives: `html`, `render`, `each`, `list`, `unsafeHTML`,
|
|
28
28
|
`ref`, `classMap`, `styleMap`.
|
|
29
29
|
- Components і CSS: `component`, `css`, `cssVars`.
|
|
30
|
-
- Routing і pages: `routes`, `router`, `page`, `layout`,
|
|
30
|
+
- Routing і pages: `routes`, `router`, `page`, `layout`,
|
|
31
31
|
`navigate`, `queryParam`, `prefetchPath`.
|
|
32
32
|
- Data: `resource`, `mutation`, `invalidate`, `jsonFetcher`, `HttpError`.
|
|
33
33
|
- Forms: `useForm`.
|
|
@@ -25,7 +25,7 @@ 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`, `bake`,
|
|
28
|
-
`
|
|
28
|
+
`preview`, `init`, `new`).
|
|
29
29
|
|
|
30
30
|
Ламати це можна тільки в major version.
|
|
31
31
|
|
package/llms.txt
CHANGED
|
@@ -79,7 +79,7 @@ import {
|
|
|
79
79
|
component,
|
|
80
80
|
css, cssVars,
|
|
81
81
|
routes, router, navigate, queryParam, prefetchPath,
|
|
82
|
-
page,
|
|
82
|
+
page, layout,
|
|
83
83
|
resource, mutation, invalidate, jsonFetcher,
|
|
84
84
|
useForm,
|
|
85
85
|
createContext, provide, inject,
|
|
@@ -147,8 +147,9 @@ Use `jsonFetcher()` for public endpoints, `apiFetcher()` for anything behind aut
|
|
|
147
147
|
|
|
148
148
|
## Layouts and bake
|
|
149
149
|
|
|
150
|
-
Use `layout()` in `routes.ts` for shared shells.
|
|
151
|
-
|
|
150
|
+
Use `layout()` in `src/app.routes.ts` for shared shells. Modules export plain
|
|
151
|
+
route maps; app routes decide which layout and guard wrap each zone. A layout
|
|
152
|
+
view should be a pure wrapper around `${child}` and shared chrome:
|
|
152
153
|
|
|
153
154
|
```ts
|
|
154
155
|
export default page({
|
|
@@ -169,17 +170,18 @@ relative `fetch`, and runtime directives like keyed `each()` during bake.
|
|
|
169
170
|
```ts
|
|
170
171
|
// src/main.ts
|
|
171
172
|
import { html, render } from "@madojs/mado";
|
|
172
|
-
import routesApi from "./routes.js";
|
|
173
|
+
import routesApi from "./app.routes.js";
|
|
173
174
|
render(html`${routesApi.view}`, document.getElementById("app")!);
|
|
174
175
|
|
|
175
|
-
// src/routes.ts
|
|
176
|
+
// src/app.routes.ts
|
|
176
177
|
import { routes } from "@madojs/mado";
|
|
177
|
-
export
|
|
178
|
-
"/": () => import("./
|
|
179
|
-
"*": () => import("./
|
|
180
|
-
}
|
|
178
|
+
export const manifest = {
|
|
179
|
+
"/": () => import("./modules/home/home.page.js"),
|
|
180
|
+
"*": () => import("./modules/home/not-found.page.js"),
|
|
181
|
+
};
|
|
182
|
+
export default routes(manifest);
|
|
181
183
|
|
|
182
|
-
// src/
|
|
184
|
+
// src/modules/home/home.page.ts
|
|
183
185
|
import { page, component, html, css, signal } from "@madojs/mado";
|
|
184
186
|
|
|
185
187
|
component("x-counter", () => {
|
|
@@ -254,10 +256,7 @@ export default page({
|
|
|
254
256
|
- docs/en/18-api-freeze-map.md — stable public API vs internal implementation details
|
|
255
257
|
- docs/en/19-reactivity-ordering.md — signal ordering, batching and teardown guarantees
|
|
256
258
|
- docs/en/20-v1-stability.md — v1 SemVer contract and what remains internal
|
|
257
|
-
-
|
|
258
|
-
- examples/tickets/ — LLM zero-history CRUD validation
|
|
259
|
-
- examples/showcase/ — flagship CRM pressure app (auth, nested routes, forms, mutations)
|
|
260
|
-
- examples/cloudflare/ — Edge prerender PoC on Cloudflare Workers
|
|
259
|
+
- starters/default/ — canonical generated app shape
|
|
261
260
|
|
|
262
261
|
## What Mado does NOT do (intentionally)
|
|
263
262
|
|
|
@@ -265,7 +264,7 @@ export default page({
|
|
|
265
264
|
- ❌ Virtual DOM → fine-grained signal updates
|
|
266
265
|
- ❌ SSR with hydration → `bake` static meta-shell or edge-prerender for SEO
|
|
267
266
|
- ❌ Hooks and rules of hooks → signals
|
|
268
|
-
- ❌
|
|
267
|
+
- ❌ Runtime framework dependencies → generated apps use Vite as dev/build tooling
|
|
269
268
|
- ❌ React-Router / TanStack → built-in 500-line `routes()`
|
|
270
269
|
- ❌ React-Query / SWR → built-in `resource()`
|
|
271
270
|
- ❌ Formik / RHF → built-in `useForm()` (HTML5 validation)
|