odoro 1.0.0 → 1.0.2

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 (33) hide show
  1. package/README.md +73 -0
  2. package/dist/cli.js +3 -3
  3. package/dist/{commands-PT3NS65O.js → commands-AHMXBWQQ.js} +25 -5
  4. package/dist/{create-IOFAPDBO.js → create-GD6O2TPL.js} +118 -70
  5. package/dist/{package-6ADADETZ.js → package-VMTZDORI.js} +1 -1
  6. package/dist/registry/index.d.ts +2 -2
  7. package/package.json +1 -1
  8. package/templates/react-ts/_variantes/avec-moteur/src/fond.tsx +118 -0
  9. package/templates/react-ts/_variantes/sans-libs/src/App.tsx +245 -45
  10. package/templates/react-ts/_variantes/sans-libs/src/fond.tsx +23 -0
  11. package/templates/react-ts/_variantes/sans-libs/src/styles.css +357 -42
  12. package/templates/react-ts/_variantes/sans-routeur/src/App.tsx +305 -62
  13. package/templates/react-ts/public/favicon.svg +2 -3
  14. package/templates/react-ts/src/App.tsx +443 -43
  15. package/templates/react-ts/src/fond.tsx +42 -0
  16. package/templates/react-ts/src/router.tsx +72 -0
  17. package/templates/react-ts/src/styles.css +4 -5
  18. package/templates/react-ts-server/_variantes/avec-moteur/client/src/fond.tsx +118 -0
  19. package/templates/react-ts-server/_variantes/sans-libs/client/src/App.tsx +245 -45
  20. package/templates/react-ts-server/_variantes/sans-libs/client/src/fond.tsx +23 -0
  21. package/templates/react-ts-server/_variantes/sans-libs/client/src/styles.css +357 -42
  22. package/templates/react-ts-server/_variantes/sans-routeur/client/src/App.tsx +305 -62
  23. package/templates/react-ts-server/client/public/favicon.svg +2 -3
  24. package/templates/react-ts-server/client/src/App.tsx +443 -43
  25. package/templates/react-ts-server/client/src/fond.tsx +42 -0
  26. package/templates/react-ts-server/client/src/router.tsx +72 -0
  27. package/templates/react-ts-server/client/src/styles.css +4 -5
  28. package/templates/react-ts/src/routes/About.tsx +0 -19
  29. package/templates/react-ts/src/routes/Home.tsx +0 -80
  30. package/templates/react-ts/src/routes/NotFound.tsx +0 -14
  31. package/templates/react-ts-server/client/src/routes/About.tsx +0 -19
  32. package/templates/react-ts-server/client/src/routes/Home.tsx +0 -148
  33. package/templates/react-ts-server/client/src/routes/NotFound.tsx +0 -14
@@ -1,92 +1,335 @@
1
- import { useState } from 'react'
1
+ /**
2
+ * Toute la page, en un fichier.
3
+ *
4
+ * ## Une seule page
5
+ *
6
+ * Le routeur n'a pas ete retenu a la creation : il n'y a donc ni `router.tsx`
7
+ * ni navigation entre pages, et les sections se suivent. Le dessin est le meme
8
+ * que dans la version routee.
9
+ *
10
+ * Pour en ajouter un plus tard, `@odoro-cli/libs/router` est deja installe : il
11
+ * vient avec les bibliotheques.
12
+ *
13
+ * ## La barre de navigation
14
+ *
15
+ * Elle ne peint pas de bandeau : ce sont des gelules posees sur ce qu'il y a
16
+ * derriere, avec un flou d'arriere-plan. Le fond decoratif continue donc de
17
+ * passer dessous, au lieu d'etre coupe par une bande opaque.
18
+ *
19
+ * @module
20
+ */
2
21
 
3
- import { Reveal, Stagger, useAnimate } from '@odoro-cli/libs/motion'
4
- import { Button } from '@odoro-cli/libs/ui'
22
+ import { Reveal, Stagger } from '@odoro-cli/libs/motion'
23
+ import { buttonClasses } from '@odoro-cli/libs/ui'
24
+ import { useState, type CSSProperties, type ReactElement } from 'react'
5
25
 
6
- /** Trois arguments mis en avant. */
7
- const FEATURES = [
8
- {
9
- title: 'Animations',
10
- body: "Une couche mince sur le moteur du navigateur. Les animations reduites sont respectees d'office.",
11
- },
12
- {
13
- title: 'Styles',
14
- body: 'Des tokens en source de verite, une feuille statique, aucun scan a l execution.',
15
- },
16
- {
17
- title: 'Interface',
18
- body: 'Des composants qui lisent les memes tokens que votre code : les rethemer suffit.',
19
- },
20
- ]
26
+ import { Fond } from '@/fond'
27
+
28
+ /* -------------------------------------------------------------------------- */
29
+ /* Marque */
30
+ /* -------------------------------------------------------------------------- */
21
31
 
22
32
  /**
23
- * Racine de l'application.
33
+ * Le signe de la marque.
24
34
  *
25
- * Une seule page : le routeur n'a pas ete retenu a la creation. Pour en
26
- * ajouter un plus tard, `@odoro-cli/libs/router` est deja installe il vient
27
- * avec les bibliotheques.
35
+ * La taille est en style et non en classe : une classe utilitaire a valeur
36
+ * arbitraire n'est emise que si le compilateur l'a vue passer, et une classe
37
+ * absente ne peint rien — le signe serait sans dimensions, donc invisible.
28
38
  */
29
- export function App() {
30
- const [ref, controls] = useAnimate<HTMLSpanElement>()
31
- const [count, setCount] = useState(0)
39
+ function Signe({ taille = '1.75rem' }: { readonly taille?: string }): ReactElement {
40
+ return (
41
+ <svg
42
+ viewBox="0 0 100 100"
43
+ fill="none"
44
+ aria-hidden="true"
45
+ style={{ width: taille, height: taille, flexShrink: 0 }}
46
+ >
47
+ <path
48
+ d="M20.25 20.25H50a29.75 29.75 0 1 1-29.75 29.75Z"
49
+ stroke="currentColor"
50
+ strokeWidth="10.5"
51
+ strokeLinejoin="miter"
52
+ />
53
+ </svg>
54
+ )
55
+ }
56
+
57
+ /* -------------------------------------------------------------------------- */
58
+ /* Barre de navigation */
59
+ /* -------------------------------------------------------------------------- */
32
60
 
61
+ /**
62
+ * La surface d'une gelule.
63
+ *
64
+ * Le systeme decline les echelles de noir et de blanc, mais pas leurs variantes
65
+ * sombres en alpha. Le melange se fait donc en style, ou il est exact et suit
66
+ * le theme sans qu'on ait a redire chaque couleur.
67
+ */
68
+ const GELULE: CSSProperties = {
69
+ backgroundColor: 'color-mix(in oklab, var(--o-theme-bg) 72%, transparent)',
70
+ borderColor: 'color-mix(in oklab, var(--o-theme-fg) 12%, transparent)',
71
+ }
72
+
73
+ /** La barre : la marque, et le lien vers le site. */
74
+ function Barre(): ReactElement {
33
75
  return (
34
- <div className="app-shell">
35
- <nav className="o-flex o-items-center o-gap-4 o-px-6 o-py-4 o-border-b o-border-zinc-200 dark:o-border-zinc-800">
36
- <span className="o-font-semibold o-text-brand-600 dark:o-text-brand-400">
37
- Odoro
76
+ <header className="o-sticky o-top-0 o-z-20 o-px-5 md:o-px-8">
77
+ <div className="o-mx-auto o-flex o-h-20 o-w-full o-max-w-5xl o-items-center o-gap-3">
78
+ <span
79
+ className="o-inline-flex o-h-14 o-shrink-0 o-items-center o-gap-2.5 o-rounded-full o-border-w-1 o-pl-5 o-pr-6 o-backdrop-blur-xl"
80
+ style={GELULE}
81
+ >
82
+ <span className="o-text-brand-500">
83
+ <Signe />
84
+ </span>
85
+ <span className="o-text-lg o-font-bold o-tracking-wide o-text-zinc-950 dark:o-text-white">
86
+ ODORO
87
+ </span>
88
+ </span>
89
+
90
+ <a
91
+ href="https://odoro.dev"
92
+ target="_blank"
93
+ rel="noreferrer"
94
+ className="o-ml-auto o-inline-flex o-h-14 o-shrink-0 o-items-center o-rounded-full o-border-w-1 o-px-5 o-text-sm o-no-underline o-backdrop-blur-xl o-text-zinc-600 dark:o-text-zinc-300 hover:o-text-zinc-950 dark:hover:o-text-white"
95
+ style={GELULE}
96
+ >
97
+ odoro.dev
98
+ </a>
99
+ </div>
100
+ </header>
101
+ )
102
+ }
103
+
104
+ /* -------------------------------------------------------------------------- */
105
+ /* Sections */
106
+ /* -------------------------------------------------------------------------- */
107
+
108
+ /** Trois faits, pas trois slogans. */
109
+ const FAITS = ['Zero configuration', 'Theme clair et sombre', 'Mouvement reduit respecte']
110
+
111
+ /** Ce que la fenetre du produit montre. */
112
+ const EXTRAIT = `export function App() {
113
+ return (
114
+ <Reveal>
115
+ <h1 className="o-text-6xl o-font-bold">
116
+ Votre premiere page.
117
+ </h1>
118
+ </Reveal>
119
+ )
120
+ }`
121
+
122
+ /** Une fenetre de navigateur miniature. */
123
+ function Fenetre(): ReactElement {
124
+ return (
125
+ <div className="o-overflow-hidden o-rounded-2xl o-border-w-1 o-border-zinc-200 dark:o-border-zinc-800 o-bg-zinc-50 dark:o-bg-zinc-900 o-shadow-2xl">
126
+ <div className="o-flex o-items-center o-gap-2 o-border-b o-border-zinc-200 dark:o-border-zinc-800 o-px-4 o-py-2.5">
127
+ <span className="o-flex o-gap-1.5" aria-hidden="true">
128
+ <span className="o-size-2.5 o-rounded-full o-bg-zinc-300 dark:o-bg-zinc-700" />
129
+ <span className="o-size-2.5 o-rounded-full o-bg-zinc-300 dark:o-bg-zinc-700" />
130
+ <span className="o-size-2.5 o-rounded-full o-bg-zinc-300 dark:o-bg-zinc-700" />
38
131
  </span>
39
- </nav>
132
+ <span className="o-ml-2 o-font-mono o-text-xs o-text-zinc-400">src/App.tsx</span>
133
+ </div>
134
+ <pre className="o-m-0 o-overflow-x-auto o-p-5 o-font-mono o-text-xs o-leading-relaxed o-text-zinc-600 dark:o-text-zinc-300">
135
+ {EXTRAIT}
136
+ </pre>
137
+ </div>
138
+ )
139
+ }
40
140
 
41
- <main className="o-mx-auto o-w-full o-max-w-3xl o-px-6 o-py-12 o-flex o-flex-col o-gap-12">
141
+ /** Le hero : la promesse, les actions, et la fenetre du produit. */
142
+ function Hero(): ReactElement {
143
+ return (
144
+ <section className="o-relative o-px-6 o-pb-20 o-pt-16 md:o-pt-24">
145
+ <div className="o-mx-auto o-w-full o-max-w-5xl">
42
146
  <Reveal>
43
- <h1 className="o-text-4xl o-font-bold o-tracking-tight">
44
- Un point de depart maitrise.
147
+ <span className="o-inline-flex o-items-center o-gap-2 o-whitespace-nowrap o-rounded-full o-border-w-1 o-border-brand-500/30 o-bg-brand-500/10 o-px-3 o-py-1 o-text-xs o-font-medium o-text-brand-600 dark:o-text-brand-400">
148
+ <Signe taille="0.9rem" />
149
+ Genere par odoro create
150
+ </span>
151
+
152
+ <h1 className="o-mt-6 o-max-w-3xl o-text-5xl o-font-bold o-tracking-tight md:o-text-6xl">
153
+ Votre premiere page, <span className="o-text-brand-500">deja vivante</span>.
45
154
  </h1>
46
- <p className="o-mt-4 o-text-lg o-text-zinc-500 dark:o-text-zinc-400 o-max-w-prose">
47
- Ce projet a ete genere par <code className="o-font-mono">odoro create</code>.
155
+
156
+ <p className="o-mt-5 o-max-w-xl o-text-lg o-text-zinc-500 dark:o-text-zinc-400">
48
157
  Le moteur d animation et le systeme de style viennent de la meme librairie.
158
+ Modifiez cette page : elle se recharge sans perdre son etat.
49
159
  </p>
50
160
  </Reveal>
51
161
 
52
- <Stagger step={80} className="o-grid o-grid-cols-1 md:o-grid-cols-3 o-gap-4">
53
- {FEATURES.map((feature) => (
162
+ <Stagger step={70} className="o-mt-8 o-flex o-flex-wrap o-items-center o-gap-3">
163
+ <a
164
+ href="#piliers"
165
+ className={`o-no-underline ${buttonClasses({ tone: 'primary' })}`}
166
+ >
167
+ Voir ce qui est inclus
168
+ </a>
169
+ <a
170
+ href="https://odoro.dev/docs"
171
+ target="_blank"
172
+ rel="noreferrer"
173
+ className={`o-no-underline ${buttonClasses({ tone: 'secondary' })}`}
174
+ >
175
+ Documentation
176
+ </a>
177
+ </Stagger>
178
+
179
+ <Stagger step={60} className="o-mt-6 o-flex o-flex-wrap o-gap-2">
180
+ {FAITS.map((fait) => (
181
+ <span
182
+ key={fait}
183
+ className="o-rounded-full o-border-w-1 o-border-zinc-200 dark:o-border-zinc-800 o-px-3 o-py-1 o-text-xs o-text-zinc-500 dark:o-text-zinc-400"
184
+ >
185
+ {fait}
186
+ </span>
187
+ ))}
188
+ </Stagger>
189
+
190
+ <Reveal>
191
+ <div className="o-mt-14">
192
+ <Fenetre />
193
+ </div>
194
+ </Reveal>
195
+ </div>
196
+ </section>
197
+ )
198
+ }
199
+
200
+ /** Ce que le projet a deja sous la main. */
201
+ const PILIERS = [
202
+ {
203
+ titre: 'Animations',
204
+ texte:
205
+ "Une couche mince sur le moteur du navigateur. Le mouvement reduit est respecte d'office.",
206
+ },
207
+ {
208
+ titre: 'Styles',
209
+ texte: 'Des jetons en source de verite, une feuille statique, aucun scan a l execution.',
210
+ },
211
+ {
212
+ titre: 'Interface',
213
+ texte: 'Des composants qui lisent les memes jetons que votre code : les rethemer suffit.',
214
+ },
215
+ ]
216
+
217
+ /** La section des piliers. */
218
+ function Piliers(): ReactElement {
219
+ return (
220
+ <section
221
+ id="piliers"
222
+ className="o-border-t o-border-zinc-200 dark:o-border-zinc-800 o-px-6 o-py-20"
223
+ >
224
+ <div className="o-mx-auto o-w-full o-max-w-5xl">
225
+ <h2 className="o-text-sm o-font-semibold o-uppercase o-tracking-widest o-text-zinc-400">
226
+ Ce qui est deja la
227
+ </h2>
228
+
229
+ <Stagger step={90} className="o-mt-8 o-grid o-gap-4 md:o-grid-cols-3">
230
+ {PILIERS.map((pilier, index) => (
54
231
  <article
55
- key={feature.title}
56
- className="o-rounded-lg o-border-w-1 o-border-zinc-200 dark:o-border-zinc-800 o-bg-white dark:o-bg-zinc-900 o-p-5"
232
+ key={pilier.titre}
233
+ className="o-rounded-xl o-border-w-1 o-border-zinc-200 dark:o-border-zinc-800 o-bg-white dark:o-bg-zinc-900 o-p-6"
57
234
  >
58
- <h2 className="o-font-semibold">{feature.title}</h2>
235
+ <span className="o-font-mono o-text-xs o-text-brand-500">
236
+ {String(index + 1).padStart(2, '0')}
237
+ </span>
238
+ <h3 className="o-mt-3 o-text-lg o-font-semibold o-tracking-tight">
239
+ {pilier.titre}
240
+ </h3>
59
241
  <p className="o-mt-2 o-text-sm o-text-zinc-500 dark:o-text-zinc-400">
60
- {feature.body}
242
+ {pilier.texte}
61
243
  </p>
62
244
  </article>
63
245
  ))}
64
246
  </Stagger>
247
+ </div>
248
+ </section>
249
+ )
250
+ }
251
+
252
+ /** La commande que l'on copie le plus souvent. */
253
+ const COMMANDE = 'odoro add text/count-up'
254
+
255
+ /** La cloture : une commande, et la porte vers le catalogue. */
256
+ function Cloture(): ReactElement {
257
+ const [copie, setCopie] = useState(false)
258
+
259
+ return (
260
+ <section className="o-border-t o-border-zinc-200 dark:o-border-zinc-800 o-px-6 o-py-24">
261
+ <div className="o-mx-auto o-w-full o-max-w-3xl o-text-center">
262
+ <Reveal>
263
+ <h2 className="o-text-3xl o-font-bold o-tracking-tight md:o-text-4xl">
264
+ Ajoutez un composant, sans quitter le terminal.
265
+ </h2>
266
+ <p className="o-mx-auto o-mt-4 o-max-w-prose o-text-zinc-500 dark:o-text-zinc-400">
267
+ Le registre copie le code dans votre projet. Il vous appartient : on le lit,
268
+ on le modifie, il ne se met pas a jour dans votre dos.
269
+ </p>
270
+
271
+ <div className="o-mx-auto o-mt-8 o-flex o-max-w-md o-items-center o-gap-2 o-rounded-xl o-border-w-1 o-border-zinc-200 dark:o-border-zinc-800 o-bg-zinc-50 dark:o-bg-zinc-900 o-p-2 o-pl-4">
272
+ <code className="o-flex-1 o-text-left o-font-mono o-text-sm">{COMMANDE}</code>
273
+ <button
274
+ type="button"
275
+ className={buttonClasses({ tone: 'ghost', size: 'sm' })}
276
+ onClick={() => {
277
+ // Le presse-papiers peut etre refuse — hors contexte sur, ou
278
+ // permission retiree. L'echec ne casse pas la page.
279
+ void navigator.clipboard
280
+ ?.writeText(COMMANDE)
281
+ .then(() => {
282
+ setCopie(true)
283
+ setTimeout(() => {
284
+ setCopie(false)
285
+ }, 1600)
286
+ })
287
+ .catch(() => undefined)
288
+ }}
289
+ >
290
+ {copie ? 'Copie' : 'Copier'}
291
+ </button>
292
+ </div>
65
293
 
66
- <div className="o-flex o-items-center o-gap-4">
67
- <Button
68
- onClick={() => {
69
- setCount((value) => value + 1)
70
- void controls.play(
71
- [
72
- { transform: 'translateY(0)' },
73
- { transform: 'translateY(-0.4rem)' },
74
- { transform: 'translateY(0)' },
75
- ],
76
- { duration: 'fast', easing: 'emphasized' },
77
- )
78
- }}
294
+ <a
295
+ href="https://odoro.dev/docs/registry"
296
+ target="_blank"
297
+ rel="noreferrer"
298
+ className="o-mt-6 o-inline-block o-text-sm o-text-zinc-500 dark:o-text-zinc-400 o-no-underline hover:o-text-brand-500"
79
299
  >
80
- Compter
81
- </Button>
82
- <span ref={ref} className="o-inline-block o-text-lg o-tabular-nums">
83
- {count}
300
+ Parcourir le catalogue
301
+ </a>
302
+ </Reveal>
303
+ </div>
304
+ </section>
305
+ )
306
+ }
307
+
308
+ /* -------------------------------------------------------------------------- */
309
+ /* Racine */
310
+ /* -------------------------------------------------------------------------- */
311
+
312
+ /** Racine de l'application. */
313
+ export function App(): ReactElement {
314
+ return (
315
+ <div className="app-shell">
316
+ <Barre />
317
+ <main className="o-relative">
318
+ <Fond />
319
+ <Hero />
320
+ <Piliers />
321
+ <Cloture />
322
+ </main>
323
+ <footer className="o-border-t o-border-zinc-200 dark:o-border-zinc-800 o-px-6 o-py-8">
324
+ <div className="o-mx-auto o-flex o-w-full o-max-w-5xl o-items-center o-justify-between o-gap-4 o-text-sm o-text-zinc-500 dark:o-text-zinc-400">
325
+ <span className="o-inline-flex o-items-center o-gap-2">
326
+ <span className="o-text-brand-500">
327
+ <Signe taille="1.1rem" />
328
+ </span>
329
+ <span className="o-font-semibold o-tracking-wide">ODORO</span>
84
330
  </span>
331
+ <span>Construit avec Odoro.</span>
85
332
  </div>
86
- </main>
87
-
88
- <footer className="o-px-6 o-py-6 o-text-sm o-text-zinc-500 dark:o-text-zinc-400 o-border-t o-border-zinc-200 dark:o-border-zinc-800">
89
- Construit avec Odoro.
90
333
  </footer>
91
334
  </div>
92
335
  )
@@ -1,4 +1,3 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
2
- <rect width="32" height="32" rx="8" fill="#5b62f4" />
3
- <circle cx="16" cy="16" r="7" fill="none" stroke="#fff" stroke-width="3" />
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="none">
2
+ <path d="M20.25 20.25H50a29.75 29.75 0 1 1-29.75 29.75Z" stroke="#3b82f6" stroke-width="10.5" stroke-linejoin="miter"/>
4
3
  </svg>