odoro 1.0.1 → 1.0.3
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 +73 -0
- package/dist/build-KI7IEVRJ.js +4 -0
- package/dist/{chunk-R6PMAMXA.js → chunk-2EE5QUCW.js} +16 -3
- package/dist/{chunk-CJIUP7A3.js → chunk-FJYUQALD.js} +1 -1
- package/dist/cli.js +4 -4
- package/dist/{create-LTT3SAWT.js → create-VUSKHXBN.js} +109 -65
- package/dist/index.js +2 -2
- package/dist/{package-LK46RV2I.js → package-2JOBLFXE.js} +3 -2
- package/dist/registry/index.d.ts +2 -2
- package/dist/{server-ATGFRVSW.js → server-DXOQAPVX.js} +1 -1
- package/package.json +3 -2
- package/templates/react-ts/_variantes/avec-moteur/src/{sections/Fond.tsx → fond.tsx} +13 -13
- package/templates/react-ts/_variantes/sans-libs/src/App.tsx +363 -23
- package/templates/{react-ts-server/_variantes/sans-libs/client/src/sections/Fond.tsx → react-ts/_variantes/sans-libs/src/fond.tsx} +1 -1
- package/templates/react-ts/_variantes/sans-libs/src/styles.css +115 -38
- package/templates/react-ts/_variantes/sans-routeur/src/App.tsx +427 -22
- package/templates/react-ts/index.html +11 -0
- package/templates/react-ts/public/favicon.svg +2 -3
- package/templates/react-ts/src/App.tsx +585 -57
- package/templates/{react-ts-server/client/src/sections/Fond.tsx → react-ts/src/fond.tsx} +9 -9
- package/templates/react-ts/src/router.tsx +72 -0
- package/templates/react-ts-server/_variantes/avec-moteur/client/src/{sections/Fond.tsx → fond.tsx} +13 -13
- package/templates/react-ts-server/_variantes/sans-libs/client/src/App.tsx +363 -23
- package/templates/{react-ts/_variantes/sans-libs/src/sections/Fond.tsx → react-ts-server/_variantes/sans-libs/client/src/fond.tsx} +1 -1
- package/templates/react-ts-server/_variantes/sans-libs/client/src/styles.css +115 -38
- package/templates/react-ts-server/_variantes/sans-routeur/client/src/App.tsx +427 -22
- package/templates/react-ts-server/client/index.html +11 -0
- package/templates/react-ts-server/client/public/favicon.svg +2 -3
- package/templates/react-ts-server/client/src/App.tsx +585 -57
- package/templates/{react-ts/src/sections/Fond.tsx → react-ts-server/client/src/fond.tsx} +9 -9
- package/templates/react-ts-server/client/src/router.tsx +72 -0
- package/dist/build-GIPMPYJ3.js +0 -4
- package/templates/react-ts/_variantes/sans-libs/src/composants/Marque.tsx +0 -37
- package/templates/react-ts/_variantes/sans-libs/src/sections/Cloture.tsx +0 -60
- package/templates/react-ts/_variantes/sans-libs/src/sections/Hero.tsx +0 -92
- package/templates/react-ts/_variantes/sans-libs/src/sections/Piliers.tsx +0 -44
- package/templates/react-ts/src/composants/Marque.tsx +0 -50
- package/templates/react-ts/src/routes/About.tsx +0 -43
- package/templates/react-ts/src/routes/Home.tsx +0 -28
- package/templates/react-ts/src/routes/NotFound.tsx +0 -14
- package/templates/react-ts/src/sections/Cloture.tsx +0 -69
- package/templates/react-ts/src/sections/Hero.tsx +0 -119
- package/templates/react-ts/src/sections/Piliers.tsx +0 -68
- package/templates/react-ts-server/_variantes/sans-libs/client/src/composants/Marque.tsx +0 -37
- package/templates/react-ts-server/_variantes/sans-libs/client/src/sections/Cloture.tsx +0 -60
- package/templates/react-ts-server/_variantes/sans-libs/client/src/sections/Hero.tsx +0 -92
- package/templates/react-ts-server/_variantes/sans-libs/client/src/sections/Piliers.tsx +0 -44
- package/templates/react-ts-server/client/src/composants/Marque.tsx +0 -50
- package/templates/react-ts-server/client/src/routes/About.tsx +0 -43
- package/templates/react-ts-server/client/src/routes/Home.tsx +0 -28
- package/templates/react-ts-server/client/src/routes/NotFound.tsx +0 -14
- package/templates/react-ts-server/client/src/sections/Cloture.tsx +0 -69
- package/templates/react-ts-server/client/src/sections/Hero.tsx +0 -119
- package/templates/react-ts-server/client/src/sections/Piliers.tsx +0 -68
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Le fond decoratif, en surface WebGL.
|
|
3
3
|
*
|
|
4
|
-
* Cette version remplace le
|
|
4
|
+
* Cette version remplace le degrade statique parce que le moteur a ete retenu a
|
|
5
5
|
* la creation. Le reste de la page est inchange : elle place `<Fond />` et ne
|
|
6
6
|
* sait pas ce qu'il y a derriere.
|
|
7
7
|
*
|
|
@@ -12,20 +12,20 @@
|
|
|
12
12
|
* ouverts, ou si l'appareil ne suivrait pas. Le refus est une valeur, pas une
|
|
13
13
|
* exception : on affiche alors le degrade, et la page tient.
|
|
14
14
|
*
|
|
15
|
-
* **Le mouvement reduit.** Sous cette preference, rien n'est monte
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* **Le mouvement reduit.** Sous cette preference, rien n'est monte : le fond
|
|
16
|
+
* n'apportait que son mouvement, et la carte graphique n'a pas a s'allumer pour
|
|
17
|
+
* un visiteur qui a demande le calme.
|
|
18
18
|
*
|
|
19
|
-
* **Les couleurs du theme.** Les teintes sont lues dans les jetons, pas
|
|
20
|
-
*
|
|
19
|
+
* **Les couleurs du theme.** Les teintes sont lues dans les jetons, pas ecrites
|
|
20
|
+
* dans le nuanceur. Une bascule clair / sombre les relit, et changer
|
|
21
21
|
* `--o-palette-brand-500` repeint le fond sans toucher a ce fichier.
|
|
22
22
|
*
|
|
23
23
|
* ## Pourquoi des styles en ligne
|
|
24
24
|
*
|
|
25
25
|
* Ce fichier est pose quel que soit le reste : un projet qui a decoche les
|
|
26
|
-
* bibliotheques n'a pas les classes `o-*`, et une classe absente ne peint
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* bibliotheques n'a pas les classes `o-*`, et une classe absente ne peint rien
|
|
27
|
+
* — le fond aurait alors une hauteur nulle, sans que rien ne le signale. Les
|
|
28
|
+
* quelques regles de placement sont donc ecrites ou elles sont sures.
|
|
29
29
|
*
|
|
30
30
|
* @module
|
|
31
31
|
*/
|
|
@@ -52,7 +52,7 @@ function Degrade(): ReactElement {
|
|
|
52
52
|
opacity: 0.28,
|
|
53
53
|
filter: 'blur(64px)',
|
|
54
54
|
background:
|
|
55
|
-
'radial-gradient(60% 60% at 50% 0%, var(--o-palette-brand-500, #
|
|
55
|
+
'radial-gradient(60% 60% at 50% 0%, var(--o-palette-brand-500, #3b82f6), transparent)',
|
|
56
56
|
}}
|
|
57
57
|
/>
|
|
58
58
|
)
|
|
@@ -76,7 +76,7 @@ export function Fond(): ReactElement {
|
|
|
76
76
|
if (a === undefined || b === undefined || c === undefined) return undefined
|
|
77
77
|
// Le fond du theme domine, la marque n'est qu'un reflet : ces trois
|
|
78
78
|
// couleurs vont dans un melange, et deux teintes de marque sur trois
|
|
79
|
-
// donneraient une nappe
|
|
79
|
+
// donneraient une nappe pleine page plutot qu'un halo.
|
|
80
80
|
return { uColorA: c, uColorB: c, uColorC: a, uSpeed: 0.1, uScale: 1.4, uOctaves: 3 }
|
|
81
81
|
}, [teintes])
|
|
82
82
|
|
|
@@ -106,8 +106,8 @@ export function Fond(): ReactElement {
|
|
|
106
106
|
// pleine intensite la nappe passe devant le titre qu'elle est censee
|
|
107
107
|
// porter ; a un cinquieme, elle le souligne.
|
|
108
108
|
opacity: 0.2,
|
|
109
|
-
// Le bas se dissout dans la page : une surface qui s'arrete net
|
|
110
|
-
//
|
|
109
|
+
// Le bas se dissout dans la page : une surface qui s'arrete net dessine
|
|
110
|
+
// une ligne horizontale que rien ne justifie.
|
|
111
111
|
maskImage: 'linear-gradient(to bottom, black 45%, transparent)',
|
|
112
112
|
WebkitMaskImage: 'linear-gradient(to bottom, black 45%, transparent)',
|
|
113
113
|
}}
|
|
@@ -1,40 +1,380 @@
|
|
|
1
|
-
import type { ReactElement } from 'react'
|
|
2
|
-
|
|
3
|
-
import { Marque } from '@/composants/Marque'
|
|
4
|
-
import { Cloture } from '@/sections/Cloture'
|
|
5
|
-
import { Fond } from '@/sections/Fond'
|
|
6
|
-
import { Hero } from '@/sections/Hero'
|
|
7
|
-
import { Piliers } from '@/sections/Piliers'
|
|
8
|
-
|
|
9
1
|
/**
|
|
10
|
-
*
|
|
2
|
+
* Toute la page, en un fichier.
|
|
3
|
+
*
|
|
4
|
+
* ## Sans les bibliotheques
|
|
11
5
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
6
|
+
* Elles n'ont pas ete retenues a la creation : pas de classes `o-*`, pas de
|
|
7
|
+
* jetons, pas de routeur. Le dessin est celui de la version complete — meme
|
|
8
|
+
* barre en gelules, meme titre, memes cartes — porte par `styles.css` en CSS
|
|
9
|
+
* ordinaire.
|
|
15
10
|
*
|
|
16
11
|
* Pour les ajouter plus tard : `npm i @odoro-cli/libs`, puis importer
|
|
17
|
-
* `@odoro-cli/libs/styles.css` dans `main.tsx
|
|
12
|
+
* `@odoro-cli/libs/styles.css` dans `main.tsx` avant cette feuille.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
18
15
|
*/
|
|
19
|
-
|
|
16
|
+
|
|
17
|
+
import { useEffect, useState, type ReactElement } from 'react'
|
|
18
|
+
|
|
19
|
+
import { Fond } from '@/fond'
|
|
20
|
+
|
|
21
|
+
/* -------------------------------------------------------------------------- */
|
|
22
|
+
/* Marque */
|
|
23
|
+
/* -------------------------------------------------------------------------- */
|
|
24
|
+
|
|
25
|
+
/** Le signe de la marque, a la taille demandee. */
|
|
26
|
+
function Signe({ taille = '1.75rem' }: { readonly taille?: string }): ReactElement {
|
|
27
|
+
return (
|
|
28
|
+
<svg
|
|
29
|
+
viewBox="0 0 100 100"
|
|
30
|
+
fill="none"
|
|
31
|
+
aria-hidden="true"
|
|
32
|
+
style={{ width: taille, height: taille, flexShrink: 0 }}
|
|
33
|
+
>
|
|
34
|
+
<path
|
|
35
|
+
d="M20.25 20.25H50a29.75 29.75 0 1 1-29.75 29.75Z"
|
|
36
|
+
stroke="currentColor"
|
|
37
|
+
strokeWidth="10.5"
|
|
38
|
+
strokeLinejoin="miter"
|
|
39
|
+
/>
|
|
40
|
+
</svg>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* -------------------------------------------------------------------------- */
|
|
45
|
+
/* Barre de navigation */
|
|
46
|
+
/* -------------------------------------------------------------------------- */
|
|
47
|
+
|
|
48
|
+
/** La barre : la marque en gelule, et le lien vers le site. */
|
|
49
|
+
function Barre(): ReactElement {
|
|
50
|
+
return (
|
|
51
|
+
<header className="barre">
|
|
52
|
+
<div className="barre-contenu">
|
|
53
|
+
<span className="gelule marque">
|
|
54
|
+
<span className="marque-signe">
|
|
55
|
+
<Signe />
|
|
56
|
+
</span>
|
|
57
|
+
<span className="marque-mot">ODORO</span>
|
|
58
|
+
</span>
|
|
59
|
+
|
|
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>
|
|
71
|
+
</div>
|
|
72
|
+
</header>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
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
|
+
|
|
20
167
|
return (
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
+
|
|
182
|
+
/* -------------------------------------------------------------------------- */
|
|
183
|
+
/* Sections */
|
|
184
|
+
/* -------------------------------------------------------------------------- */
|
|
185
|
+
|
|
186
|
+
/** Trois faits, pas trois slogans. */
|
|
187
|
+
const FAITS = ['Zero configuration', 'TypeScript strict', 'Rechargement a chaud']
|
|
188
|
+
|
|
189
|
+
/** Ce que la fenetre du produit montre. */
|
|
190
|
+
const EXTRAIT = `export function App() {
|
|
191
|
+
return (
|
|
192
|
+
<h1 className="hero-titre">
|
|
193
|
+
Votre premiere page.
|
|
194
|
+
</h1>
|
|
195
|
+
)
|
|
196
|
+
}`
|
|
197
|
+
|
|
198
|
+
/** Une fenetre de navigateur miniature. */
|
|
199
|
+
function Fenetre(): ReactElement {
|
|
200
|
+
return (
|
|
201
|
+
<div className="fenetre">
|
|
202
|
+
<div className="fenetre-barre">
|
|
203
|
+
<span className="fenetre-pastilles" aria-hidden="true">
|
|
204
|
+
<span />
|
|
205
|
+
<span />
|
|
206
|
+
<span />
|
|
207
|
+
</span>
|
|
208
|
+
<span className="fenetre-chemin">src/App.tsx</span>
|
|
209
|
+
</div>
|
|
210
|
+
<pre className="fenetre-code">{EXTRAIT}</pre>
|
|
211
|
+
</div>
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Le hero : la promesse, les actions, et la fenetre du produit. */
|
|
216
|
+
function Hero(): ReactElement {
|
|
217
|
+
return (
|
|
218
|
+
<section className="hero">
|
|
219
|
+
<div className="contenu">
|
|
220
|
+
<span className="pastille-marque">
|
|
221
|
+
<Signe taille="0.9rem" />
|
|
222
|
+
Genere par odoro create
|
|
223
|
+
</span>
|
|
224
|
+
|
|
225
|
+
<h1 className="hero-titre">
|
|
226
|
+
Votre premiere page, <span className="accent">deja vivante</span>.
|
|
227
|
+
</h1>
|
|
228
|
+
|
|
229
|
+
<p className="hero-chapeau">
|
|
230
|
+
Le serveur de developpement, la compilation et le rechargement a chaud
|
|
231
|
+
viennent de <code>odoro</code>. Le systeme de style est le votre.
|
|
232
|
+
</p>
|
|
233
|
+
|
|
234
|
+
<div className="hero-actions">
|
|
235
|
+
<a href="#piliers" className="bouton bouton-primaire">
|
|
236
|
+
Voir ce qui est inclus
|
|
237
|
+
</a>
|
|
238
|
+
<a
|
|
239
|
+
href="https://odoro.dev/docs"
|
|
240
|
+
target="_blank"
|
|
241
|
+
rel="noreferrer"
|
|
242
|
+
className="bouton bouton-secondaire"
|
|
243
|
+
>
|
|
244
|
+
Documentation
|
|
245
|
+
</a>
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
<div className="faits">
|
|
249
|
+
{FAITS.map((fait) => (
|
|
250
|
+
<span key={fait} className="fait">
|
|
251
|
+
{fait}
|
|
252
|
+
</span>
|
|
253
|
+
))}
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
<div className="hero-fenetre">
|
|
257
|
+
<Fenetre />
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
</section>
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Ce que le projet a deja sous la main. */
|
|
265
|
+
const PILIERS = [
|
|
266
|
+
{
|
|
267
|
+
titre: 'Compilation',
|
|
268
|
+
texte:
|
|
269
|
+
'Un serveur de developpement a rechargement a chaud, et une compilation de production.',
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
titre: 'TypeScript',
|
|
273
|
+
texte: 'Types stricts, alias de chemins, et verification sans emission.',
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
titre: 'A vous de jouer',
|
|
277
|
+
texte: 'Aucun systeme de style impose : le votre prend toute la place.',
|
|
278
|
+
},
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
/** La section des piliers. */
|
|
282
|
+
function Piliers(): ReactElement {
|
|
283
|
+
return (
|
|
284
|
+
<section id="piliers" className="section">
|
|
285
|
+
<div className="contenu">
|
|
286
|
+
<h2 className="sur-titre">Ce qui est deja la</h2>
|
|
287
|
+
<div className="grille">
|
|
288
|
+
{PILIERS.map((pilier, index) => (
|
|
289
|
+
<article key={pilier.titre} className="carte">
|
|
290
|
+
<span className="carte-numero">{String(index + 1).padStart(2, '0')}</span>
|
|
291
|
+
<h3>{pilier.titre}</h3>
|
|
292
|
+
<p>{pilier.texte}</p>
|
|
293
|
+
</article>
|
|
294
|
+
))}
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
</section>
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** La commande que l'on copie le plus souvent. */
|
|
302
|
+
const COMMANDE = 'npm i @odoro-cli/libs'
|
|
303
|
+
|
|
304
|
+
/** La cloture : une commande, et la porte vers la documentation. */
|
|
305
|
+
function Cloture(): ReactElement {
|
|
306
|
+
const [copie, setCopie] = useState(false)
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
<section className="section section-centre">
|
|
310
|
+
<div className="contenu-etroit">
|
|
311
|
+
<h2 className="cloture-titre">Ajoutez le systeme de style quand vous voudrez.</h2>
|
|
312
|
+
<p className="cloture-chapeau">
|
|
313
|
+
Les jetons, les utilitaires et les composants vivent dans un paquet a part. Ce
|
|
314
|
+
projet tourne sans eux, et les accueille sans rien casser.
|
|
315
|
+
</p>
|
|
316
|
+
|
|
317
|
+
<div className="commande">
|
|
318
|
+
<code>{COMMANDE}</code>
|
|
319
|
+
<button
|
|
320
|
+
type="button"
|
|
321
|
+
className="bouton bouton-fantome"
|
|
322
|
+
onClick={() => {
|
|
323
|
+
// Le presse-papiers peut etre refuse — hors contexte sur, ou
|
|
324
|
+
// permission retiree. L'echec ne casse pas la page : le libelle
|
|
325
|
+
// ne change simplement pas.
|
|
326
|
+
void navigator.clipboard
|
|
327
|
+
?.writeText(COMMANDE)
|
|
328
|
+
.then(() => {
|
|
329
|
+
setCopie(true)
|
|
330
|
+
setTimeout(() => {
|
|
331
|
+
setCopie(false)
|
|
332
|
+
}, 1600)
|
|
333
|
+
})
|
|
334
|
+
.catch(() => undefined)
|
|
335
|
+
}}
|
|
336
|
+
>
|
|
337
|
+
{copie ? 'Copie' : 'Copier'}
|
|
338
|
+
</button>
|
|
339
|
+
</div>
|
|
340
|
+
|
|
341
|
+
<a
|
|
342
|
+
href="https://odoro.dev/docs/installation"
|
|
343
|
+
target="_blank"
|
|
344
|
+
rel="noreferrer"
|
|
345
|
+
className="lien-discret"
|
|
346
|
+
>
|
|
347
|
+
Lire la marche a suivre
|
|
26
348
|
</a>
|
|
27
|
-
</
|
|
349
|
+
</div>
|
|
350
|
+
</section>
|
|
351
|
+
)
|
|
352
|
+
}
|
|
28
353
|
|
|
354
|
+
/* -------------------------------------------------------------------------- */
|
|
355
|
+
/* Racine */
|
|
356
|
+
/* -------------------------------------------------------------------------- */
|
|
357
|
+
|
|
358
|
+
/** Racine de l'application. */
|
|
359
|
+
export function App(): ReactElement {
|
|
360
|
+
return (
|
|
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 />
|
|
365
|
+
<Barre />
|
|
29
366
|
<main className="principal">
|
|
30
|
-
<Fond />
|
|
31
367
|
<Hero />
|
|
32
368
|
<Piliers />
|
|
33
369
|
<Cloture />
|
|
34
370
|
</main>
|
|
35
|
-
|
|
36
371
|
<footer className="pied">
|
|
37
|
-
<
|
|
372
|
+
<span className="marque">
|
|
373
|
+
<span className="marque-signe">
|
|
374
|
+
<Signe taille="1.1rem" />
|
|
375
|
+
</span>
|
|
376
|
+
<span className="marque-mot">ODORO</span>
|
|
377
|
+
</span>
|
|
38
378
|
<span>Construit avec Odoro.</span>
|
|
39
379
|
</footer>
|
|
40
380
|
</div>
|