@madojs/mado 0.10.1 → 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 +68 -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/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 -53
- 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 +18 -22
- package/docs/en/14-testing.md +4 -4
- package/docs/en/16-bake-cookbook.md +11 -12
- 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 +61 -42
- 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 +7 -10
- package/docs/fr/14-testing.md +1 -1
- package/docs/fr/16-bake-cookbook.md +2 -2
- 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 +61 -41
- 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 +7 -11
- package/docs/ru/14-testing.md +1 -1
- package/docs/ru/16-bake-cookbook.md +12 -6
- 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 +67 -57
- 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 -621
- package/scripts/package-smoke.mjs +4 -1
- package/scripts/preview.mjs +13 -37
- 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
|
@@ -13,7 +13,7 @@ Mado est structuré **comme un serveur HTTP**. Sérieusement :
|
|
|
13
13
|
|---|---|
|
|
14
14
|
| Routeur HTTP (chi, axum, mux) | `routes()` — manifeste de chemins |
|
|
15
15
|
| Handler `func(req, resp)` | `page({ view: (ctx) => html\`...\` })` |
|
|
16
|
-
| Middleware |
|
|
16
|
+
| Middleware | route group via `layout()` (enveloppe le handler) |
|
|
17
17
|
| Moteur de template (Jinja, Handlebars) | tagged template `html\`\`` |
|
|
18
18
|
| Client HTTP avec cache | `resource()` — fetch + cache + invalidation |
|
|
19
19
|
| Variable réactive / atom | `signal()` — getter réactif |
|
|
@@ -360,17 +360,17 @@ export default page({
|
|
|
360
360
|
```
|
|
361
361
|
|
|
362
362
|
```ts
|
|
363
|
-
// src/routes.ts
|
|
364
|
-
import {
|
|
363
|
+
// src/app.routes.ts
|
|
364
|
+
import { layout, routes } from "@madojs/mado";
|
|
365
365
|
|
|
366
366
|
export default routes({
|
|
367
367
|
"/login": () => import("./pages/login.js"),
|
|
368
368
|
|
|
369
|
-
"/app
|
|
369
|
+
"/app": layout({
|
|
370
370
|
layout: () => import("./layouts/auth-layout.js"),
|
|
371
371
|
routes: {
|
|
372
|
-
"dashboard": () => import("./pages/dashboard.js"),
|
|
373
|
-
"users": () => import("./pages/users.js"),
|
|
372
|
+
"/dashboard": () => import("./pages/dashboard.js"),
|
|
373
|
+
"/users": () => import("./pages/users.js"),
|
|
374
374
|
},
|
|
375
375
|
}),
|
|
376
376
|
});
|
|
@@ -433,6 +433,6 @@ Tout le reste — navigateur standard + TypeScript.
|
|
|
433
433
|
- **[`01-routing.md`](./01-routing.md)** — le router en détail.
|
|
434
434
|
- **[`02-project-layout.md`](./02-project-layout.md)** — structure du projet.
|
|
435
435
|
- **[`03-static-bake.md`](./03-static-bake.md)** — SEO sans SSR.
|
|
436
|
-
- **[`
|
|
436
|
+
- **[`10-app-architecture.md`](./10-app-architecture.md)** — forme canonique du starter.
|
|
437
437
|
|
|
438
438
|
Si quelque chose n'est pas clair — ouvrez une issue, ou ouvrez simplement le source. Il est vraiment lisible en une soirée.
|
|
@@ -1,65 +1,38 @@
|
|
|
1
1
|
# Test LLM sans historique
|
|
2
2
|
|
|
3
|
-
Ce document définit un test
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
un LLM fraîchement initialisé peut-il écrire du Mado idiomatique sans retomber dans du code
|
|
7
|
-
de forme React ?
|
|
3
|
+
Ce document définit un test manuel pour vérifier qu'un LLM fraîchement
|
|
4
|
+
initialisé écrit du Mado idiomatique au lieu de reproduire React dans des
|
|
5
|
+
tagged templates.
|
|
8
6
|
|
|
9
7
|
## Contexte autorisé
|
|
10
8
|
|
|
11
|
-
Pour le premier passage, donnez à l'agent uniquement :
|
|
12
|
-
|
|
13
9
|
- `AGENTS.md`
|
|
14
10
|
- `README.md`
|
|
15
|
-
- `docs/
|
|
16
|
-
- `examples
|
|
17
|
-
|
|
18
|
-
d'application plus grande
|
|
19
|
-
|
|
20
|
-
L'agent peut rechercher des API ciblées dans `src/` quand il est bloqué, mais ne doit pas
|
|
21
|
-
charger tout le framework dans le context.
|
|
11
|
+
- `docs/fr/07-llm-pitfalls.md` ou la version anglaise
|
|
12
|
+
- fichiers de l'espace externe `madojs-examples` seulement si l'agent demande
|
|
13
|
+
un pattern d'application plus large
|
|
22
14
|
|
|
23
15
|
## Tâche
|
|
24
16
|
|
|
25
|
-
Construire
|
|
26
|
-
solo/backend.
|
|
27
|
-
|
|
28
|
-
Comportement requis :
|
|
17
|
+
Construire une petite SPA ticket-admin :
|
|
29
18
|
|
|
30
19
|
- routes : `/`, `/tickets`, `/tickets/new`, `/tickets/:id`, `*` ;
|
|
31
|
-
- API
|
|
32
|
-
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
- état UI local avec `signal()` ;
|
|
36
|
-
- composants shell, metric et badge avec slot pour une UI admin plus réaliste ;
|
|
37
|
-
- test de smoke important le build de l'exemple.
|
|
20
|
+
- mock API en mémoire avec délais async réalistes ;
|
|
21
|
+
- liste avec `resource()`, `queryParam()`, `computed()` et `each()` keyed ;
|
|
22
|
+
- create/edit avec `useForm()` + `mutation()` + `invalidates` ;
|
|
23
|
+
- état UI local avec `signal()`.
|
|
38
24
|
|
|
39
|
-
##
|
|
25
|
+
## Checklist d'échec
|
|
40
26
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- JSX, `useState`, `useEffect`, `ref`, `$state`, ou composants de style classe ;
|
|
44
|
-
- `${signal()}` ou `${signal() + 1}` là où un thunk enfant réactif est requis ;
|
|
27
|
+
- JSX, `useState`, `useEffect`, `ref`, `$state`, classes custom elements ;
|
|
28
|
+
- `${signal()}` là où un child thunk réactif est nécessaire ;
|
|
45
29
|
- `disabled=${...}` au lieu de `?disabled=${...}` ;
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
- nouvelles dépendances runtime ou nouvelles API publiques du framework.
|
|
50
|
-
|
|
51
|
-
## Notes de résultats
|
|
52
|
-
|
|
53
|
-
L'implémentation actuelle de `examples/tickets` n'a pas nécessité de nouvelles API publiques ni
|
|
54
|
-
de dépendances runtime.
|
|
30
|
+
- `.map()` non-keyed pour des listes dynamiques ;
|
|
31
|
+
- `resource()` créé hors contexte lifecycle-aware ;
|
|
32
|
+
- nouvelles dépendances runtime ou nouvelles API publiques.
|
|
55
33
|
|
|
56
|
-
|
|
57
|
-
il vérifie que `llms.txt` contient toujours les règles clés, compare l'artefact
|
|
58
|
-
commité `examples/tickets` à la surface API Mado requise et aux failure
|
|
59
|
-
patterns, puis build le projet et lance `test/tickets-smoke.test.mjs`.
|
|
34
|
+
## Notes
|
|
60
35
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
que les resources sont enregistrées à l'intérieur du setup du composant et se nettoient avec
|
|
65
|
-
le composant.
|
|
36
|
+
L'implémentation historique tickets vit dans l'espace externe d'exemples. Le
|
|
37
|
+
core repository ne livre plus cet artefact ; utilisez cette page comme script
|
|
38
|
+
d'évaluation manuel quand vous mettez à jour les règles LLM.
|
|
@@ -1,184 +1,65 @@
|
|
|
1
1
|
# Shadow DOM vs Light DOM
|
|
2
2
|
|
|
3
|
-
Les composants Mado utilisent Shadow DOM par défaut. C'est un bon défaut pour
|
|
4
|
-
autonomes, mais
|
|
3
|
+
Les composants Mado utilisent Shadow DOM par défaut. C'est un bon défaut pour
|
|
4
|
+
les widgets autonomes, mais les zones d'application et les pages restent
|
|
5
|
+
généralement de simples templates light DOM.
|
|
5
6
|
|
|
6
|
-
## Règle
|
|
7
|
+
## Règle
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
visible et réutilisable de l'arbre UI — app shell, sidebar, modal, table,
|
|
10
|
-
section de page — préférez un Web Component déclaré avec `component()`.
|
|
11
|
-
|
|
12
|
-
Gardez les fonctions simples pour de petits helpers inline :
|
|
9
|
+
Utilisez les route layouts pour les zones d'application :
|
|
13
10
|
|
|
14
11
|
```ts
|
|
15
|
-
|
|
12
|
+
export default page({
|
|
13
|
+
view: ({ child }) => html`<main class="app-main">${child}</main>`,
|
|
14
|
+
});
|
|
16
15
|
```
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Utilisez **Shadow DOM** pour les widgets feuilles :
|
|
22
|
-
|
|
23
|
-
- boutons, badges, cartes, métriques ;
|
|
24
|
-
- modals, toasts, petits composants visuels ;
|
|
25
|
-
- widgets d'intégration qui ne devraient pas hériter du CSS de l'app accidentellement ;
|
|
26
|
-
- composants dont le stylage doit appartenir au composant lui-même.
|
|
27
|
-
|
|
28
|
-
Utilisez **Light DOM** (`{ shadow: false }`) pour la structure de l'app qui veut partager
|
|
29
|
-
les utilitaires CSS globaux :
|
|
30
|
-
|
|
31
|
-
- composants route/page ;
|
|
32
|
-
- écrans admin avec des layouts denses de tableau/formulaire ;
|
|
33
|
-
- écrans riches en données avec des tableaux et des formulaires ;
|
|
34
|
-
- composants qui partagent intentionnellement les utilitaires globaux de layout, formulaire et
|
|
35
|
-
tableau ;
|
|
36
|
-
- endroits où les enfants doivent simplement rester dans le DOM normal du document.
|
|
17
|
+
Ces fichiers vivent dans `src/layouts/` et sont composés depuis
|
|
18
|
+
`src/app.routes.ts` avec `layout()`. Ils sont stylés par
|
|
19
|
+
`src/shared/styles/shell.css`.
|
|
37
20
|
|
|
38
|
-
Utilisez
|
|
39
|
-
|
|
40
|
-
- app shells qui rendent `<slot>` ;
|
|
41
|
-
- wrappers sidebar/contenu ;
|
|
42
|
-
- frames de layout réutilisables qui possèdent leur propre CSS grid/header/sidebar.
|
|
43
|
-
|
|
44
|
-
`<slot>` est une fonctionnalité Shadow DOM. Dans un composant `shadow: false`,
|
|
45
|
-
`<slot>` est juste un élément DOM normal et ne déplace pas les enfants à cet
|
|
46
|
-
endroit du layout.
|
|
47
|
-
|
|
48
|
-
## Le piège
|
|
49
|
-
|
|
50
|
-
Le CSS global ne franchit pas une frontière Shadow DOM.
|
|
21
|
+
Utilisez les page files pour les écrans :
|
|
51
22
|
|
|
52
23
|
```ts
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
.metric-grid { display: grid; grid-template-columns: repeat(4, 1fr); }
|
|
57
|
-
`;
|
|
58
|
-
|
|
59
|
-
// ❌ .page-head et .metric-grid ne s'appliqueront pas à l'intérieur du shadowRoot de x-dashboard
|
|
60
|
-
component("x-dashboard", () => () => html`
|
|
61
|
-
<header class="page-head">...</header>
|
|
62
|
-
<div class="metric-grid">...</div>
|
|
63
|
-
`);
|
|
24
|
+
export default page({
|
|
25
|
+
view: () => html`<section><h1>Users</h1></section>`,
|
|
26
|
+
});
|
|
64
27
|
```
|
|
65
28
|
|
|
66
|
-
|
|
29
|
+
Les tables, forms, prose et états simples de page sont stylés par
|
|
30
|
+
`src/shared/styles/content.css`.
|
|
31
|
+
|
|
32
|
+
Utilisez Shadow DOM components pour les widgets feuilles :
|
|
33
|
+
|
|
34
|
+
- buttons, badges, cards, metrics ;
|
|
35
|
+
- spinners, modals, toasts ;
|
|
36
|
+
- widgets qui doivent posséder leur CSS.
|
|
67
37
|
|
|
68
38
|
```ts
|
|
69
|
-
component("x-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
shadow: false,
|
|
39
|
+
component("x-status-badge", ({ attr }) => {
|
|
40
|
+
const status = attr("status", "draft");
|
|
41
|
+
return () => html`<span>${status}</span>`;
|
|
42
|
+
}, {
|
|
74
43
|
styles: css`
|
|
75
|
-
|
|
76
|
-
|
|
44
|
+
:host { display: inline-block; }
|
|
45
|
+
span { color: var(--color-text-muted); }
|
|
77
46
|
`,
|
|
78
47
|
});
|
|
79
48
|
```
|
|
80
49
|
|
|
81
|
-
Maintenant les utilitaires globaux et les styles locaux scopés fonctionnent tous les deux.
|
|
82
|
-
|
|
83
50
|
## Comment les styles se comportent
|
|
84
51
|
|
|
85
|
-
- `
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// racine et pages : Light DOM
|
|
100
|
-
component("x-app", setup, { shadow: false });
|
|
101
|
-
component("x-users-page", setup, { shadow: false });
|
|
102
|
-
|
|
103
|
-
// layout basé sur slot : Shadow DOM par défaut, car il possède la grille du shell
|
|
104
|
-
component("x-app-layout", setup);
|
|
105
|
-
|
|
106
|
-
// widgets feuilles : Shadow DOM par défaut
|
|
107
|
-
component("x-status-badge", setup);
|
|
108
|
-
component("x-stat-card", setup);
|
|
109
|
-
component("x-toast-stack", setup);
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
Cela donne aux écrans d'admin backend un CSS prévisible tout en préservant l'encapsulation
|
|
113
|
-
pour les widgets réutilisables et les shells basés sur slot.
|
|
114
|
-
|
|
115
|
-
Le modèle d'import est volontairement natif au navigateur :
|
|
116
|
-
|
|
117
|
-
```ts
|
|
118
|
-
import "./components/app-layout.js";
|
|
119
|
-
|
|
120
|
-
render(html`<x-app-layout>${router.view}</x-app-layout>`, app);
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
L'import enregistre le custom element avec `customElements.define()`. Le template
|
|
124
|
-
crée un élément `<x-app-layout>`. Le navigateur relie les deux. Il n'y a pas de
|
|
125
|
-
valeur de composant à la React que l'on passe comme fonction.
|
|
126
|
-
|
|
127
|
-
Si un layout n'a pas besoin de projection slot et doit être entièrement stylé par du CSS
|
|
128
|
-
global, `shadow: false` peut rester un bon choix. S'il contient `<slot>`, gardez Shadow DOM
|
|
129
|
-
et mettez les styles du shell dans `styles: css\`\``.
|
|
130
|
-
|
|
131
|
-
## Routage et liens
|
|
132
|
-
|
|
133
|
-
`data-link` fonctionne à l'intérieur de Shadow DOM. Le router utilise `event.composedPath()`,
|
|
134
|
-
donc l'interception de clic et le hover-prefetch peuvent voir les liens depuis les shadow roots
|
|
135
|
-
ouverts.
|
|
136
|
-
|
|
137
|
-
```ts
|
|
138
|
-
component("x-card-link", () => () => html`
|
|
139
|
-
<a href="/app/accounts" data-link>Comptes</a>
|
|
140
|
-
`);
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
Le lien peut être en Shadow DOM ; la navigation reste SPA.
|
|
144
|
-
|
|
145
|
-
## Où importer les composants
|
|
146
|
-
|
|
147
|
-
Les custom elements sont globaux après leur enregistrement, mais cet
|
|
148
|
-
enregistrement reste un import JavaScript explicite.
|
|
149
|
-
|
|
150
|
-
```ts
|
|
151
|
-
// main.ts : frame global de l'app
|
|
152
|
-
import "./components/app-shell.js";
|
|
153
|
-
|
|
154
|
-
// pages/tickets.ts : composant possédé par cette page
|
|
155
|
-
import "../components/ticket-list.js";
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
Le navigateur ne télécharge **pas** `ticket-list.js` simplement parce qu'il voit
|
|
159
|
-
`<ticket-list>`. Le fichier doit d'abord être importé quelque part. Une fois
|
|
160
|
-
importé, il appelle `customElements.define(...)`, et le tag devient connu dans
|
|
161
|
-
le document courant.
|
|
162
|
-
|
|
163
|
-
N'importez pas tous les composants en masse dans `main.ts` "au cas où". Cela
|
|
164
|
-
fonctionne pour de petites démos, mais cache l'ownership et casse le chargement
|
|
165
|
-
paresseux des routes. Préférez :
|
|
166
|
-
|
|
167
|
-
- app shell/providers globaux dans `main.ts` ;
|
|
168
|
-
- composants utilisés par une seule page dans ce fichier page ;
|
|
169
|
-
- composants partagés d'une feature dans la page d'entrée de cette feature ;
|
|
170
|
-
- petits leaf components vraiment globaux dans `main.ts` seulement s'ils sont
|
|
171
|
-
utilisés partout.
|
|
172
|
-
|
|
173
|
-
## Leçon du Showcase
|
|
174
|
-
|
|
175
|
-
`examples/showcase` utilise cette séparation délibérément :
|
|
176
|
-
|
|
177
|
-
- `x-app` et les pages de route CRM sont Light DOM ;
|
|
178
|
-
- `x-app-layout` garde Shadow DOM car il possède un shell sidebar/contenu basé sur slot ;
|
|
179
|
-
- les utilitaires de tableau/formulaire/page vivent dans `styles/global.ts` ;
|
|
180
|
-
- les composants feuilles comme `x-stat-card`, `x-status-badge`, `x-modal` et `x-toast-stack`
|
|
181
|
-
gardent Shadow DOM.
|
|
182
|
-
|
|
183
|
-
Si une page a soudainement l'air sans style, vérifiez si elle utilise des classes globales
|
|
184
|
-
à l'intérieur d'un composant Shadow DOM. C'est généralement le problème.
|
|
52
|
+
- `tokens.css` définit des CSS custom properties ; `var(...)` traverse Shadow
|
|
53
|
+
DOM.
|
|
54
|
+
- `reset.css`, `shell.css`, `content.css` s'appliquent seulement au document /
|
|
55
|
+
light DOM.
|
|
56
|
+
- Les sélecteurs de classe comme `.data`, `.app-main`, `.error` ne traversent
|
|
57
|
+
pas Shadow DOM.
|
|
58
|
+
- Les styles locaux des composants vivent dans ``css`...` `` dans les options de
|
|
59
|
+
`component()`.
|
|
60
|
+
- Si un Shadow component accepte des enfants, utilisez `<slot>` et stylisez le
|
|
61
|
+
frame dans les styles du composant.
|
|
62
|
+
|
|
63
|
+
Si une page semble sans style, vous avez probablement utilisé des classes
|
|
64
|
+
globales dans un Shadow DOM component. Déplacez le markup dans une page/layout
|
|
65
|
+
ou déplacez le CSS dans les styles du composant.
|
|
@@ -1,61 +1,138 @@
|
|
|
1
1
|
# Architecture d'application
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Le starter officiel est la forme canonique d'une application Mado en
|
|
4
|
+
production. Ce n'est pas un framework dans le framework : seulement des
|
|
5
|
+
fichiers, des imports, les primitives Mado et des limites ESLint.
|
|
6
6
|
|
|
7
7
|
## Structure
|
|
8
8
|
|
|
9
9
|
```txt
|
|
10
10
|
src/
|
|
11
11
|
├── main.ts
|
|
12
|
-
├── routes.ts
|
|
12
|
+
├── app.routes.ts
|
|
13
13
|
├── layouts/
|
|
14
|
-
├──
|
|
15
|
-
|
|
16
|
-
├──
|
|
17
|
-
|
|
14
|
+
│ ├── app-shell.layout.ts
|
|
15
|
+
│ └── auth-shell.layout.ts
|
|
16
|
+
├── shared/
|
|
17
|
+
│ ├── http/
|
|
18
|
+
│ ├── lib/
|
|
19
|
+
│ ├── styles/
|
|
20
|
+
│ └── ui/
|
|
21
|
+
└── modules/
|
|
22
|
+
├── auth/
|
|
23
|
+
│ ├── auth.routes.ts
|
|
24
|
+
│ ├── auth.public.ts
|
|
25
|
+
│ ├── auth.service.ts
|
|
26
|
+
│ ├── auth.connector.ts
|
|
27
|
+
│ ├── auth.guard.ts
|
|
28
|
+
│ ├── login.page.ts
|
|
29
|
+
│ └── _contracts/
|
|
30
|
+
└── billing/
|
|
31
|
+
├── billing.routes.ts
|
|
32
|
+
├── billing.public.ts
|
|
33
|
+
├── billing.types.ts
|
|
34
|
+
├── api/
|
|
35
|
+
├── data/
|
|
36
|
+
├── pages/
|
|
37
|
+
├── components/
|
|
38
|
+
└── _contracts/
|
|
18
39
|
```
|
|
19
40
|
|
|
20
|
-
|
|
21
|
-
`components/` contient les tags réutilisables, et `pages/` contient un fichier
|
|
22
|
-
par page.
|
|
41
|
+
## App Map
|
|
23
42
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
import routesApi from "./routes.js";
|
|
28
|
-
|
|
29
|
-
render(html`${routesApi.view}`, document.getElementById("app")!);
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
N'importe pas tous les composants dans `main.ts`. Une page importe les
|
|
33
|
-
composants qu'elle rend.
|
|
43
|
+
`src/app.routes.ts` est la carte de toute l'application. Les modules exportent
|
|
44
|
+
des route maps simples ; les app routes décident quel shell et quel guard
|
|
45
|
+
enveloppent chaque zone.
|
|
34
46
|
|
|
35
47
|
```ts
|
|
36
48
|
import { layout, routes } from "@madojs/mado";
|
|
37
|
-
import { requireAuth } from "./
|
|
49
|
+
import { requireAuth } from "./modules/auth/auth.public";
|
|
50
|
+
import { authRoutes } from "./modules/auth/auth.routes";
|
|
51
|
+
import { billingRoutes } from "./modules/billing/billing.routes";
|
|
38
52
|
|
|
39
53
|
export const manifest = {
|
|
40
|
-
"/": () => import("./
|
|
41
|
-
"/
|
|
42
|
-
layout: () => import("./layouts/
|
|
54
|
+
"/": () => import("./modules/home/home.page"),
|
|
55
|
+
"/login": layout({
|
|
56
|
+
layout: () => import("./layouts/auth-shell.layout"),
|
|
57
|
+
routes: authRoutes,
|
|
58
|
+
}),
|
|
59
|
+
"/billing": layout({
|
|
60
|
+
layout: () => import("./layouts/app-shell.layout"),
|
|
43
61
|
guard: requireAuth,
|
|
44
|
-
routes:
|
|
62
|
+
routes: billingRoutes,
|
|
45
63
|
}),
|
|
46
|
-
"*": () => import("./
|
|
64
|
+
"*": () => import("./modules/home/not-found.page"),
|
|
47
65
|
};
|
|
48
66
|
|
|
49
67
|
export default routes(manifest);
|
|
50
68
|
```
|
|
51
69
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
70
|
+
Rules:
|
|
71
|
+
|
|
72
|
+
- Export `manifest` pour `mado bake`.
|
|
73
|
+
- Les modules n'appellent jamais `layout()`.
|
|
74
|
+
- Les layouts décrivent des zones d'application, pas des domaines.
|
|
75
|
+
- Ne cachez pas le router dans un custom element ou un second shell dans
|
|
76
|
+
`main.ts`.
|
|
77
|
+
|
|
78
|
+
## File Forms
|
|
79
|
+
|
|
80
|
+
| Suffix | Role |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `*.page.ts` | route page, default `page({...})` |
|
|
83
|
+
| `*.layout.ts` | app-zone wrapper, default `page(...)` |
|
|
84
|
+
| `*.connector.ts` | one external API system |
|
|
85
|
+
| `*.resource.ts` | `resource()` and `mutation()` layer |
|
|
86
|
+
| `*.service.ts` | module singleton state |
|
|
87
|
+
| `*.guard.ts` | route guard |
|
|
88
|
+
| `*.routes.ts` | module-local route map |
|
|
89
|
+
| `*.public.ts` | only public module surface |
|
|
90
|
+
| `*.types.ts` | domain types |
|
|
91
|
+
| `*.component.ts` | Web Component registration |
|
|
92
|
+
|
|
93
|
+
Les signals, resources et forms locaux à une page vivent dans `view()`. L'état
|
|
94
|
+
partagé par un module vit dans `*.service.ts`.
|
|
95
|
+
|
|
96
|
+
## Data Flow
|
|
97
|
+
|
|
98
|
+
```txt
|
|
99
|
+
shared/http/http-client.ts
|
|
100
|
+
▲
|
|
101
|
+
modules/<x>/api/*.connector.ts DTO -> domain mapping
|
|
102
|
+
▲
|
|
103
|
+
modules/<x>/data/*.resource.ts cache keys + mutations
|
|
104
|
+
▲
|
|
105
|
+
modules/<x>/pages/*.page.ts UI consumes domain types
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Styles
|
|
109
|
+
|
|
110
|
+
| File | Role |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| `src/shared/styles/tokens.css` | design tokens as CSS custom properties |
|
|
113
|
+
| `src/shared/styles/reset.css` | document/light DOM reset |
|
|
114
|
+
| `src/shared/styles/shell.css` | app-zone layouts from `src/layouts/` |
|
|
115
|
+
| `src/shared/styles/content.css` | page-level forms, tables, prose and states |
|
|
116
|
+
|
|
117
|
+
Les composants feuilles gardent leurs styles dans ``css`...` `` dans les
|
|
118
|
+
options de `component()` et dépendent des tokens, pas de classes globales.
|
|
119
|
+
|
|
120
|
+
`vite.config.ts` active le transformer Lightning CSS de Vite. Mado ne possède
|
|
121
|
+
pas le prefixing, le lowering CSS ou la minification.
|
|
122
|
+
|
|
123
|
+
## CLI
|
|
55
124
|
|
|
56
125
|
```bash
|
|
57
|
-
mado
|
|
58
|
-
mado
|
|
126
|
+
mado new module billing
|
|
127
|
+
mado new page billing/pages/invoices-list
|
|
128
|
+
mado new connector billing/api/stripe
|
|
129
|
+
mado new resource billing/data/invoices
|
|
130
|
+
mado new service billing/cart
|
|
131
|
+
mado new form billing/invoice
|
|
132
|
+
mado new component billing/components/invoice-status-badge
|
|
133
|
+
mado new guard billing/billing
|
|
134
|
+
mado new layout app-shell
|
|
59
135
|
```
|
|
60
136
|
|
|
61
|
-
Le
|
|
137
|
+
Le générateur écrit seulement de nouveaux fichiers. Il ne modifie pas
|
|
138
|
+
`app.routes.ts`.
|
package/docs/fr/11-layouts.md
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
# Layouts
|
|
2
2
|
|
|
3
|
-
Le chemin recommandé pour les layouts Mado est un
|
|
4
|
-
dans `
|
|
3
|
+
Le chemin recommandé pour les layouts Mado est un route group dans
|
|
4
|
+
`src/app.routes.ts`. Ne mettez pas un shell global dans `main.ts` si l'app a
|
|
5
|
+
plusieurs zones : public, auth, app, embed.
|
|
5
6
|
|
|
6
7
|
```ts
|
|
7
8
|
import { layout, routes } from "@madojs/mado";
|
|
8
|
-
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";
|
|
9
12
|
|
|
10
13
|
export const manifest = {
|
|
11
|
-
"/": () => import("./
|
|
14
|
+
"/": () => import("./modules/home/home.page.js"),
|
|
12
15
|
"/login": layout({
|
|
13
|
-
layout: () => import("./layouts/auth.js"),
|
|
14
|
-
routes:
|
|
16
|
+
layout: () => import("./layouts/auth-shell.layout.js"),
|
|
17
|
+
routes: authRoutes,
|
|
15
18
|
}),
|
|
16
|
-
"/
|
|
17
|
-
layout: () => import("./layouts/app.js"),
|
|
19
|
+
"/billing": layout({
|
|
20
|
+
layout: () => import("./layouts/app-shell.layout.js"),
|
|
18
21
|
guard: requireAuth,
|
|
19
|
-
routes:
|
|
22
|
+
routes: billingRoutes,
|
|
20
23
|
}),
|
|
24
|
+
"*": () => import("./modules/home/not-found.page.js"),
|
|
21
25
|
};
|
|
22
26
|
|
|
23
27
|
export default routes(manifest);
|
|
@@ -27,9 +31,17 @@ Un layout est une `page({ view })` qui rend `child` :
|
|
|
27
31
|
|
|
28
32
|
```ts
|
|
29
33
|
export default page({
|
|
30
|
-
view: ({ child }) => html
|
|
34
|
+
view: ({ child }) => html`
|
|
35
|
+
<div class="layout layout--app">
|
|
36
|
+
<main class="app-main">${child}</main>
|
|
37
|
+
</div>
|
|
38
|
+
`,
|
|
31
39
|
});
|
|
32
40
|
```
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
Rules:
|
|
43
|
+
|
|
44
|
+
- one shell per route group, not per page;
|
|
45
|
+
- modules export plain route maps and do not call `layout()`;
|
|
46
|
+
- a guard on the group protects the whole subtree;
|
|
47
|
+
- layout view stays stateless; page-local state lives in pages/components/resources.
|