odoro 1.0.2 → 1.0.4

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/README.md CHANGED
@@ -14,15 +14,15 @@ package is what it installs.
14
14
 
15
15
  | Command | What it does |
16
16
  | ---------------- | --------------------------------------------------------- |
17
- | `odoro dev` | Development server with hot module replacement. |
18
- | `odoro build` | Production build into `dist/`. |
19
- | `odoro preview` | Serves `dist/` the way a static host would. |
20
- | `odoro create` | Scaffolds a project — same thing as `npm create odoro`. |
21
- | `odoro init` | Writes `odoro.json` so `odoro add` knows where to write. |
22
- | `odoro add <id>` | Copies a registry component into your project. |
23
- | `odoro list` | Prints the registry catalogue. |
24
- | `odoro diff` | Compares what is installed with what the registry serves. |
25
- | `odoro doctor` | Checks that the project is in a fit state. |
17
+ | `odoro dev` | Development server with hot module replacement. |
18
+ | `odoro build` | Production build into `dist/`. |
19
+ | `odoro preview` | Serves `dist/` the way a static host would. |
20
+ | `odoro create` | Scaffolds a project — same thing as `npm create odoro`. |
21
+ | `odoro init` | Writes `odoro.json` so `odoro add` knows where to write. |
22
+ | `odoro add <id>` | Copies a registry component into your project. |
23
+ | `odoro list` | Prints the registry catalogue. |
24
+ | `odoro diff` | Compares what is installed with what the registry serves. |
25
+ | `odoro doctor` | Checks that the project is in a fit state. |
26
26
 
27
27
  Run `odoro --help` for the full list, including the database commands.
28
28
 
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ export { buildProject, reportBuild } from './chunk-FJYUQALD.js';
3
+ import './chunk-2EE5QUCW.js';
4
+ import './chunk-JMEHF3KN.js';
@@ -34,7 +34,9 @@ async function fournisseurDe(root) {
34
34
  // `generate` enumere les classes du palier courant. Absent d'un paquet
35
35
  // plus ancien : le champ reste alors indefini, et le developpement
36
36
  // retombe sur la feuille telle qu'elle est livree.
37
- ...typeof generate === "function" ? { classesConnues: () => new Set(generate("core").classNames) } : {}
37
+ ...typeof generate === "function" ? {
38
+ classesConnues: () => new Set(generate("core").classNames)
39
+ } : {}
38
40
  };
39
41
  } catch {
40
42
  return void 0;
@@ -720,6 +722,11 @@ async function applyReactRefresh(code, file) {
720
722
  // La carte de source produite par la compilation precedente est reprise et
721
723
  // fusionnee : sans cela, les numeros de ligne du debogueur designeraient le
722
724
  // code instrumente plutot que la source.
725
+ //
726
+ // `true` demande a Babel de lire la carte inline du code recu. Il l'accepte
727
+ // — verifie : la source reprise est bien le fichier d'origine — mais les
728
+ // types de la 7.x ne decrivent que la forme objet. L'annotation est
729
+ // incomplete, pas la valeur.
723
730
  inputSourceMap: true,
724
731
  sourceMaps: "inline",
725
732
  // `skipEnvCheck` leve un garde-fou destine aux configurations globales,
@@ -934,7 +941,9 @@ async function startDevServer(config) {
934
941
  const fournisseur = await fournisseurDe(config.root);
935
942
  const utilitaires = fournisseur?.classesConnues === void 0 ? void 0 : fournisseur.renderUtilitairesPour(fournisseur.classesConnues());
936
943
  if (utilitaires !== void 0) {
937
- info(`utilitaires de developpement : ${String(Math.round(utilitaires.length / 1024))} Ko`);
944
+ info(
945
+ `utilitaires de developpement : ${String(Math.round(utilitaires.length / 1024))} Ko`
946
+ );
938
947
  }
939
948
  const entries = extractEntries(await readFile(indexFile, "utf8"), config.root);
940
949
  const specifiers = await scanDependencies(config, entries);
@@ -1005,7 +1014,11 @@ async function startDevServer(config) {
1005
1014
  };
1006
1015
  const serveHtml = async (response) => {
1007
1016
  const html = await readFile(indexFile, "utf8");
1008
- send(response, injectClient(html, utilitaires !== void 0), MIME[".html"]);
1017
+ send(
1018
+ response,
1019
+ injectClient(html, utilitaires !== void 0),
1020
+ MIME[".html"]
1021
+ );
1009
1022
  };
1010
1023
  const forward = (incoming, response, target) => {
1011
1024
  const url2 = new URL(incoming.url ?? "/", target);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { extractEntries, applyAlias, isBareSpecifier, fournisseurDe } from './chunk-R6PMAMXA.js';
2
+ import { extractEntries, applyAlias, isBareSpecifier, fournisseurDe } from './chunk-2EE5QUCW.js';
3
3
  import { info, colors, size, success, duration } from './chunk-JMEHF3KN.js';
4
4
  import { existsSync } from 'fs';
5
5
  import { readFile, rm, mkdir, writeFile, cp, stat } from 'fs/promises';
package/dist/cli.js CHANGED
@@ -131,7 +131,7 @@ function rootFrom(flags, positional) {
131
131
  async function run(argv) {
132
132
  const { command, positional, flags } = parseArgs(argv);
133
133
  if (flags["version"] === true) {
134
- const manifest = await import('./package-VMTZDORI.js');
134
+ const manifest = await import('./package-5KU4PW5P.js');
135
135
  console.log(manifest.default.version);
136
136
  return 0;
137
137
  }
@@ -142,7 +142,7 @@ async function run(argv) {
142
142
  switch (command) {
143
143
  case "create":
144
144
  case "new": {
145
- const { createCommand } = await import('./create-GD6O2TPL.js');
145
+ const { createCommand } = await import('./create-LVNBZOGV.js');
146
146
  const options = {};
147
147
  if (positional[0] !== void 0) options.name = positional[0];
148
148
  if (typeof flags["template"] === "string") options.template = flags["template"];
@@ -156,13 +156,13 @@ async function run(argv) {
156
156
  return createCommand(options);
157
157
  }
158
158
  case "dev": {
159
- const { startDevServer } = await import('./server-ATGFRVSW.js');
159
+ const { startDevServer } = await import('./server-DXOQAPVX.js');
160
160
  const config = await loadConfig(rootFrom(flags, positional), overridesFrom(flags));
161
161
  await startDevServer(config);
162
162
  return new Promise(() => void 0);
163
163
  }
164
164
  case "build": {
165
- const { buildProject, reportBuild } = await import('./build-GIPMPYJ3.js');
165
+ const { buildProject, reportBuild } = await import('./build-KI7IEVRJ.js');
166
166
  const config = await loadConfig(rootFrom(flags, positional), overridesFrom(flags));
167
167
  const output = await buildProject(config);
168
168
  reportBuild(output, process.cwd());
@@ -142,6 +142,16 @@ function availableTemplates(root = templatesRoot()) {
142
142
  return readdirSync(root).filter((entry) => statSync(resolve(root, entry)).isDirectory()).sort();
143
143
  }
144
144
 
145
+ // src/scaffold/versions-famille.generated.ts
146
+ var VERSIONS_FAMILLE = {
147
+ "@odoro-cli/engine": "1.0.2",
148
+ "@odoro-cli/icons": "1.0.2",
149
+ "@odoro-cli/libs": "1.0.2",
150
+ "@odoro-cli/server": "1.0.2",
151
+ "create-odoro": "1.0.4",
152
+ "odoro": "1.0.4"
153
+ };
154
+
145
155
  // src/scaffold/scaffold.ts
146
156
  var DOSSIER_VARIANTES = "_variantes";
147
157
  var PAQUETS_OPTIONNELS = ["@odoro-cli/libs", "@odoro-cli/icons", "@odoro-cli/engine"];
@@ -173,6 +183,12 @@ async function copyDirectory(from, to, written, prefix = "") {
173
183
  function isOdoroPackage(name) {
174
184
  return name === "odoro" || name.startsWith("@odoro-cli/");
175
185
  }
186
+ function versionDemandee(nom, versionCli2) {
187
+ if (versionCli2 === "latest") return "latest";
188
+ if (nom === "odoro") return `^${versionCli2}`;
189
+ const relevee = VERSIONS_FAMILLE[nom];
190
+ return relevee === void 0 ? "latest" : `^${relevee}`;
191
+ }
176
192
  function alignOdoroVersions(manifest, version) {
177
193
  const aligned = { ...manifest };
178
194
  for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
@@ -180,7 +196,7 @@ function alignOdoroVersions(manifest, version) {
180
196
  if (typeof deps !== "object" || deps === null) continue;
181
197
  const next = {};
182
198
  for (const [name, range] of Object.entries(deps)) {
183
- next[name] = isOdoroPackage(name) ? version === "latest" ? "latest" : `^${version}` : range;
199
+ next[name] = isOdoroPackage(name) ? versionDemandee(name, version) : range;
184
200
  }
185
201
  aligned[field] = next;
186
202
  }
@@ -444,9 +460,7 @@ async function createCommand(options) {
444
460
  })
445
461
  ));
446
462
  if (!templates.includes(template)) {
447
- prompts.cancel(
448
- `Unknown template: "${template}". Available: ${templates.join(", ")}.`
449
- );
463
+ prompts.cancel(`Unknown template: "${template}". Available: ${templates.join(", ")}.`);
450
464
  return 1;
451
465
  }
452
466
  const modules = await askModules(options);
@@ -485,7 +499,9 @@ async function createCommand(options) {
485
499
  if (overwrite !== void 0) scaffoldOptions.overwrite = overwrite;
486
500
  scaffoldOptions.modules = modules;
487
501
  const { files } = await scaffold(scaffoldOptions);
488
- spinner2.stop(`${String(files.length)} files written to ${colors.cyan(basename(target))}`);
502
+ spinner2.stop(
503
+ `${String(files.length)} files written to ${colors.cyan(basename(target))}`
504
+ );
489
505
  if (withGit && !existsSync(resolve(target, ".git"))) {
490
506
  try {
491
507
  execSync("git init -q", { cwd: target, stdio: "ignore" });
package/dist/index.js CHANGED
@@ -2,6 +2,6 @@
2
2
  export { startPreviewServer } from './chunk-34ES2ICQ.js';
3
3
  export { defineConfig, loadConfig } from './chunk-DL3NPC4H.js';
4
4
  import './chunk-T6RLHSCW.js';
5
- export { buildProject, reportBuild } from './chunk-CJIUP7A3.js';
6
- export { ModuleGraph, depFileName, detectSelfAccepting, optimizeDeps, scanDependencies, startDevServer } from './chunk-R6PMAMXA.js';
5
+ export { buildProject, reportBuild } from './chunk-FJYUQALD.js';
6
+ export { ModuleGraph, depFileName, detectSelfAccepting, optimizeDeps, scanDependencies, startDevServer } from './chunk-2EE5QUCW.js';
7
7
  import './chunk-JMEHF3KN.js';
@@ -2,7 +2,7 @@
2
2
  // package.json
3
3
  var package_default = {
4
4
  name: "odoro",
5
- version: "1.0.2",
5
+ version: "1.0.4",
6
6
  type: "module",
7
7
  license: "UNLICENSED",
8
8
  author: "BouBouw",
@@ -37,20 +37,22 @@ var package_default = {
37
37
  }
38
38
  },
39
39
  scripts: {
40
- build: "tsup",
40
+ build: "node scripts/versions-famille.mjs && tsup",
41
41
  dev: "tsup --watch",
42
42
  test: "vitest run",
43
- typecheck: "tsc --noEmit",
44
- prepublishOnly: "pnpm run build"
43
+ typecheck: "node scripts/versions-famille.mjs && tsc --noEmit",
44
+ prepublishOnly: "pnpm run build",
45
+ "versions:famille": "node scripts/versions-famille.mjs"
45
46
  },
46
47
  dependencies: {
47
- "@babel/core": "^8.0.1",
48
+ "@babel/core": "^7.29.7",
48
49
  "@clack/prompts": "^0.11.0",
49
50
  esbuild: "^0.28.2",
50
51
  picocolors: "^1.1.1",
51
52
  "react-refresh": "^0.18.0"
52
53
  },
53
54
  devDependencies: {
55
+ "@types/babel__core": "^7.20.5",
54
56
  "@types/node": "^22.18.8",
55
57
  tsup: "^8.5.0",
56
58
  typescript: "^5.9.3",
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- export { extractEntries, injectClient, startDevServer } from './chunk-R6PMAMXA.js';
2
+ export { extractEntries, injectClient, startDevServer } from './chunk-2EE5QUCW.js';
3
3
  import './chunk-JMEHF3KN.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "odoro",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "author": "BouBouw",
@@ -35,13 +35,14 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@babel/core": "^8.0.1",
38
+ "@babel/core": "^7.29.7",
39
39
  "@clack/prompts": "^0.11.0",
40
40
  "esbuild": "^0.28.2",
41
41
  "picocolors": "^1.1.1",
42
42
  "react-refresh": "^0.18.0"
43
43
  },
44
44
  "devDependencies": {
45
+ "@types/babel__core": "^7.20.5",
45
46
  "@types/node": "^22.18.8",
46
47
  "tsup": "^8.5.0",
47
48
  "typescript": "^5.9.3",
@@ -58,9 +59,10 @@
58
59
  "url": "https://github.com/ODORO-CLI/OdoroKit/issues"
59
60
  },
60
61
  "scripts": {
61
- "build": "tsup",
62
+ "build": "node scripts/versions-famille.mjs && tsup",
62
63
  "dev": "tsup --watch",
63
64
  "test": "vitest run",
64
- "typecheck": "tsc --noEmit"
65
+ "typecheck": "node scripts/versions-famille.mjs && tsc --noEmit",
66
+ "versions:famille": "node scripts/versions-famille.mjs"
65
67
  }
66
68
  }
@@ -14,7 +14,7 @@
14
14
  * @module
15
15
  */
16
16
 
17
- import { useState, type ReactElement } from 'react'
17
+ import { useEffect, useState, type ReactElement } from 'react'
18
18
 
19
19
  import { Fond } from '@/fond'
20
20
 
@@ -57,19 +57,128 @@ function Barre(): ReactElement {
57
57
  <span className="marque-mot">ODORO</span>
58
58
  </span>
59
59
 
60
- <a
61
- href="https://odoro.dev"
62
- target="_blank"
63
- rel="noreferrer"
64
- className="gelule gelule-lien"
65
- >
66
- odoro.dev
67
- </a>
60
+ <div className="barre-fin">
61
+ <a
62
+ href="https://odoro.dev"
63
+ target="_blank"
64
+ rel="noreferrer"
65
+ className="gelule gelule-lien"
66
+ >
67
+ odoro.dev
68
+ </a>
69
+ <BasculeTheme />
70
+ </div>
68
71
  </div>
69
72
  </header>
70
73
  )
71
74
  }
72
75
 
76
+ /* -------------------------------------------------------------------------- */
77
+ /* Theme */
78
+ /* -------------------------------------------------------------------------- */
79
+
80
+ /** Les trois etats de la bascule. */
81
+ type Theme = 'systeme' | 'clair' | 'sombre'
82
+
83
+ /** Ou le choix est memorise. Le script de `index.html` lit la meme cle. */
84
+ const CLE_THEME = 'odoro-theme'
85
+
86
+ /** L'ordre du cycle, au clic. */
87
+ const CYCLE: readonly Theme[] = ['systeme', 'clair', 'sombre']
88
+
89
+ /**
90
+ * Pose le theme sur la racine du document.
91
+ *
92
+ * `systeme` retire l'attribut plutot que d'en poser un troisieme : la feuille
93
+ * de style ecoute `data-theme`, et son absence rend la main a la preference du
94
+ * navigateur.
95
+ */
96
+ function poserTheme(theme: Theme): void {
97
+ if (theme === 'systeme') delete document.documentElement.dataset.theme
98
+ else document.documentElement.dataset.theme = theme === 'clair' ? 'light' : 'dark'
99
+ }
100
+
101
+ /** Le theme memorise, ou `systeme`. */
102
+ function themeMemorise(): Theme {
103
+ try {
104
+ const valeur = localStorage.getItem(CLE_THEME)
105
+ if (valeur === 'light') return 'clair'
106
+ if (valeur === 'dark') return 'sombre'
107
+ return 'systeme'
108
+ } catch {
109
+ // Stockage refuse — fenetre privee, cookies bloques. Le theme du systeme
110
+ // reste une reponse valable.
111
+ return 'systeme'
112
+ }
113
+ }
114
+
115
+ /** Les trois pictogrammes, dessines dans le flux. */
116
+ function Pictogramme({ theme }: { readonly theme: Theme }): ReactElement {
117
+ const commun = {
118
+ viewBox: '0 0 24 24',
119
+ fill: 'none',
120
+ stroke: 'currentColor',
121
+ strokeWidth: 1.8,
122
+ strokeLinecap: 'round' as const,
123
+ strokeLinejoin: 'round' as const,
124
+ 'aria-hidden': true,
125
+ style: { width: '1.15rem', height: '1.15rem' },
126
+ }
127
+
128
+ if (theme === 'clair') {
129
+ return (
130
+ <svg {...commun}>
131
+ <circle cx="12" cy="12" r="4" />
132
+ <path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" />
133
+ </svg>
134
+ )
135
+ }
136
+
137
+ if (theme === 'sombre') {
138
+ return (
139
+ <svg {...commun}>
140
+ <path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8Z" />
141
+ </svg>
142
+ )
143
+ }
144
+
145
+ return (
146
+ <svg {...commun}>
147
+ <rect x="2" y="4" width="20" height="13" rx="2" />
148
+ <path d="M8 21h8M12 17v4" />
149
+ </svg>
150
+ )
151
+ }
152
+
153
+ /** La bascule de theme : systeme, clair, sombre. */
154
+ function BasculeTheme(): ReactElement {
155
+ const [theme, setTheme] = useState<Theme>(() => themeMemorise())
156
+
157
+ useEffect(() => {
158
+ poserTheme(theme)
159
+ try {
160
+ if (theme === 'systeme') localStorage.removeItem(CLE_THEME)
161
+ else localStorage.setItem(CLE_THEME, theme === 'clair' ? 'light' : 'dark')
162
+ } catch {
163
+ // Le theme reste applique pour la session, meme sans stockage.
164
+ }
165
+ }, [theme])
166
+
167
+ return (
168
+ <button
169
+ type="button"
170
+ aria-label={`Theme : ${theme}`}
171
+ title={`Theme : ${theme}`}
172
+ className="gelule bascule"
173
+ onClick={() => {
174
+ setTheme((actuel) => CYCLE[(CYCLE.indexOf(actuel) + 1) % CYCLE.length] ?? 'systeme')
175
+ }}
176
+ >
177
+ <Pictogramme theme={theme} />
178
+ </button>
179
+ )
180
+ }
181
+
73
182
  /* -------------------------------------------------------------------------- */
74
183
  /* Sections */
75
184
  /* -------------------------------------------------------------------------- */
@@ -249,10 +358,12 @@ function Cloture(): ReactElement {
249
358
  /** Racine de l'application. */
250
359
  export function App(): ReactElement {
251
360
  return (
252
- <div className="app-shell">
361
+ // Le fond est pose ici et non dans le contenu : ancre plus bas, il
362
+ // commencait sous la barre et laissait une bande plus sombre derriere elle.
363
+ <div className="app-shell app-shell-fond">
364
+ <Fond />
253
365
  <Barre />
254
366
  <main className="principal">
255
- <Fond />
256
367
  <Hero />
257
368
  <Piliers />
258
369
  <Cloture />
@@ -21,11 +21,14 @@
21
21
  color-scheme: light dark;
22
22
  }
23
23
 
24
- /* La preference du systeme, faute d'un selecteur de theme : c'est ce que les
25
- jetons apporteraient, et l'absence de bibliotheque ne doit pas se payer d'un
26
- fond blanc au milieu de la nuit. */
24
+ /* Les valeurs du theme sombre, ecrites une fois et reprises deux fois.
25
+
26
+ La bascule pose `data-theme` sur la racine ; sans attribut, la preference du
27
+ navigateur decide. Les deux regles sont donc necessaires : la seconde sans la
28
+ premiere ignorerait le choix du visiteur, la premiere sans la seconde
29
+ rendrait un fond blanc au milieu de la nuit. */
27
30
  @media (prefers-color-scheme: dark) {
28
- :root {
31
+ :root:not([data-theme='light']) {
29
32
  --fond: #09090b;
30
33
  --encre: #fafafa;
31
34
  --doux: #a1a1aa;
@@ -34,6 +37,25 @@
34
37
  }
35
38
  }
36
39
 
40
+ :root[data-theme='dark'] {
41
+ --fond: #09090b;
42
+ --encre: #fafafa;
43
+ --doux: #a1a1aa;
44
+ --filet: #27272a;
45
+ --surface: #18181b;
46
+ }
47
+
48
+ /* Le choix explicite est dit au navigateur : sans cela, `light-dark()`, les
49
+ controles natifs et les barres de defilement continuent de suivre un systeme
50
+ en nuit alors que le visiteur a demande le clair. */
51
+ :root[data-theme='light'] {
52
+ color-scheme: light;
53
+ }
54
+
55
+ :root[data-theme='dark'] {
56
+ color-scheme: dark;
57
+ }
58
+
37
59
  * {
38
60
  box-sizing: border-box;
39
61
  }
@@ -93,12 +115,30 @@ pre {
93
115
  text-decoration: none;
94
116
  }
95
117
 
96
- .gelule-lien {
118
+ .barre-fin {
97
119
  margin-left: auto;
120
+ display: flex;
121
+ align-items: center;
122
+ gap: 0.75rem;
123
+ }
124
+
125
+ .gelule-lien {
98
126
  color: var(--doux);
99
127
  font-size: 0.875rem;
100
128
  }
101
129
 
130
+ .bascule {
131
+ width: 3.5rem;
132
+ justify-content: center;
133
+ padding: 0;
134
+ color: var(--doux);
135
+ cursor: pointer;
136
+ }
137
+
138
+ .bascule:hover {
139
+ color: var(--encre);
140
+ }
141
+
102
142
  .gelule-lien:hover {
103
143
  color: var(--encre);
104
144
  }
@@ -125,6 +165,10 @@ pre {
125
165
 
126
166
  /* ----- Coquille ----------------------------------------------------------- */
127
167
 
168
+ .app-shell-fond {
169
+ position: relative;
170
+ }
171
+
128
172
  .principal {
129
173
  position: relative;
130
174
  }