Update documentation
This commit is contained in:
parent
69e80af773
commit
5b9a0e6b34
3 changed files with 115 additions and 65 deletions
|
@ -9,8 +9,7 @@ An svg layout designer.
|
|||
|
||||
Requirements :
|
||||
- `node` >= 16.x (>= 17.x to run vitest tests)
|
||||
- `npm`
|
||||
- pnpm (optional) reduce `node_modules` folder size by using symlinks
|
||||
- `npm` (included with node)
|
||||
- [`git-lfs`](https://git-lfs.github.com/) (in order to clone the documentation)
|
||||
- `dotnet` (optional) used for api test
|
||||
|
||||
|
@ -18,10 +17,12 @@ Requirements :
|
|||
# Recommanded tools for developers
|
||||
|
||||
- [VSCode](https://code.visualstudio.com/)
|
||||
- [pnpm](https://pnpm.io/)
|
||||
- [React DevTools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi)
|
||||
- [Typescript React code snippets](https://marketplace.visualstudio.com/items?itemName=infeng.vscode-react-typescript)
|
||||
- [vscode-tailwindcss](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)
|
||||
- [vscode-eslint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
|
||||
- [vscode-drawio](https://marketplace.visualstudio.com/items?itemName=hediet.vscode-drawio)
|
||||
|
||||
|
||||
# Develop
|
||||
|
|
BIN
docs/#Project/Pages/ComponentStructure.drawio
(Stored with Git LFS)
BIN
docs/#Project/Pages/ComponentStructure.drawio
(Stored with Git LFS)
Binary file not shown.
|
@ -127,7 +127,6 @@ Allons donc dans le composant `MainMenu.tsx` et analysons le contenu du bouton `
|
|||
return (
|
||||
<div className='absolute bg-blue-50 p-12 rounded-lg drop-shadow-lg grid grid-cols-1 md:grid-cols-2 gap-8 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
|
||||
<button type="button" className='mainmenu-btn' onClick={() => {
|
||||
setWindowState(WindowState.Loading);
|
||||
props.newEditor();
|
||||
}}>Start from scratch</button>
|
||||
<button type="button" className='mainmenu-btn' onClick={() => setWindowState(WindowState.Load)}>Load a configuration file</button>
|
||||
|
@ -139,35 +138,42 @@ On trouve la fonction `onClick` suivante :
|
|||
|
||||
```tsx
|
||||
// MainMenu.tsx
|
||||
{
|
||||
setWindowState(WindowState.Loading);
|
||||
<button type="button" className='mainmenu-btn' onClick={() => {
|
||||
props.newEditor();
|
||||
}
|
||||
}}>
|
||||
```
|
||||
|
||||
Aha! On trouve une fonction qui change d'état. Cependant ! On découvre aussi qu'elle appelle une fonction `newEditor`.
|
||||
On trouve la
|
||||
|
||||
Instinctivement, vu que l'on cherche une fonction qui permet de changer d'état, on pourrait croire que c'est `setWindowState` qui gère mais on va vite comprendre que ce n'est pas elle.
|
||||
|
||||
Pour rappel `setWindowState` est un setteur d'état, et qu'elle est définie **dans** le composant. Autrement dit, elle ne gère pas l'état de l'application. De plus, un indice indique que le l'état du menu passe de `Main` à `Loading`. Elle ne fait donc que changer sa propre vue pour passer à celle d'une animation de loading que l'on peut voir plus haut dans le `switch`.
|
||||
|
||||
`newEditor` étant une fonction donnée par `props`, doit donc correspondre à la fonctionalité que l'on veut renveser.
|
||||
`newEditor` étant une fonction donnée par `props`, doit donc correspondre à la fonctionalité que l'on veut renverser.
|
||||
|
||||
Regardons donc le composant parent de `MainMenu`: `App`.
|
||||
|
||||
```tsx
|
||||
// App.tsx
|
||||
...
|
||||
<MainMenu
|
||||
newEditor={() => NewEditor(
|
||||
setEditorState, setLoaded
|
||||
)}
|
||||
loadEditor={(files: FileList | null) => LoadEditor(
|
||||
files,
|
||||
setEditorState,
|
||||
setLoaded
|
||||
)}
|
||||
/>
|
||||
return (
|
||||
<div
|
||||
ref={appRef}
|
||||
className='App mainmenu-bg'
|
||||
>
|
||||
<MainMenu
|
||||
newEditor={() => {
|
||||
setAppState(AppState.Loading);
|
||||
NewEditor(
|
||||
editorState,
|
||||
(newEditor) => setEditorState(newEditor),
|
||||
() => setAppState(AppState.Loaded)
|
||||
);
|
||||
}}
|
||||
loadEditor={(files: FileList | null) => LoadEditor(
|
||||
files,
|
||||
setEditorState,
|
||||
setAppState
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
...
|
||||
```
|
||||
|
||||
|
@ -175,9 +181,19 @@ Cette fonction `newEditor` appelle donc une autre fonction `NewEditor`.
|
|||
|
||||
```tsx
|
||||
export function NewEditor(
|
||||
setEditorState: Dispatch<SetStateAction<IEditorState>>,
|
||||
setLoaded: Dispatch<SetStateAction<boolean>>
|
||||
editorState: IEditorState,
|
||||
setEditorState: (newState: IEditorState) => void,
|
||||
enableLoaded: () => void
|
||||
): void {
|
||||
if (DISABLE_API) {
|
||||
enableLoaded();
|
||||
}
|
||||
|
||||
if (editorState.configuration.APIConfiguration !== undefined) {
|
||||
enableLoaded();
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the configuration from the API
|
||||
FetchConfiguration()
|
||||
.then((configuration: IConfiguration) => {
|
||||
|
@ -185,44 +201,77 @@ export function NewEditor(
|
|||
const editorState: IEditorState = GetDefaultEditorState(configuration);
|
||||
|
||||
setEditorState(editorState);
|
||||
setLoaded(true);
|
||||
enableLoaded();
|
||||
}, (error) => {
|
||||
console.debug('[NewEditor] Could not fetch resource from API. Using default.', error);
|
||||
setLoaded(true);
|
||||
enableLoaded();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Cette fonction à l'air assez compliquée, mais on sait qu'elle utilise `setEditorState` et `setLoaded`. Et c'est tout ce qui nous intéresse.
|
||||
Cette fonction à l'air assez compliquée, mais on sait qu'elle utilise `setEditorState` et `enableLoaded()`. Et c'est tout ce qui nous intéresse. On observe dans `App.tsx` que `setEditorState` sert à changer l'état de `editorState` et que `enableLoaded` est appelle `setAppState` qui lui sert à changer l'état de `appState`.
|
||||
|
||||
Donc pour renverser l'état de `App` il faut appeler soit `setEditorState` ou soit `setLoaded`. En analysant un peu plus près `App.tsx`, on remarque l'évidante condition permettant d'afficher ou non le menu principal :
|
||||
En analysant un peu plus près `App.tsx`, on remarque l'évidante condition permettant d'afficher ou non le menu principal :
|
||||
|
||||
```tsx
|
||||
// App.tsx
|
||||
...
|
||||
if (isLoaded) {
|
||||
return (
|
||||
<div>
|
||||
<Editor
|
||||
(...)
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
switch (appState) {
|
||||
case AppState.Loaded:
|
||||
return (
|
||||
<div
|
||||
ref={appRef}
|
||||
className='App'
|
||||
>
|
||||
<Editor
|
||||
root={props.root}
|
||||
configuration={editorState.configuration}
|
||||
history={editorState.history}
|
||||
historyCurrentStep={editorState.historyCurrentStep}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
case AppState.Loading:
|
||||
return (
|
||||
<div
|
||||
ref={appRef}
|
||||
className='App mainmenu-bg'
|
||||
>
|
||||
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
|
||||
<Loader />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<div
|
||||
ref={appRef}
|
||||
className='App mainmenu-bg'
|
||||
>
|
||||
<MainMenu
|
||||
newEditor={() => {
|
||||
setAppState(AppState.Loading);
|
||||
NewEditor(
|
||||
editorState,
|
||||
(newEditor) => setEditorState(newEditor),
|
||||
() => setAppState(AppState.Loaded)
|
||||
);
|
||||
}}
|
||||
loadEditor={(files: FileList | null) => LoadEditor(
|
||||
files,
|
||||
setEditorState,
|
||||
setAppState
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='mainmenu-bg'>
|
||||
<MainMenu
|
||||
(...)
|
||||
/>
|
||||
</div>
|
||||
```
|
||||
|
||||
Ainsi, on sait qu'il faut juste appeler `setLoaded` le setteur d'état de `isLoaded`:
|
||||
Ainsi, on sait qu'il faut appeler `setAppState` le setteur d'état de `appState`:
|
||||
|
||||
```tsx
|
||||
// App.tsx
|
||||
const [isLoaded, setLoaded] = useState<boolean>(false);
|
||||
const [appState, setAppState] = useState<AppState>(FAST_BOOT);
|
||||
```
|
||||
|
||||
Cependant comment appeler cette fonction depuis `Home` ? Et bien nous allons utiliser les `props` pour passer la fonction en dessous.
|
||||
|
@ -247,7 +296,7 @@ export function Home({ goHome }: IHomeProps): JSX.Element {
|
|||
}
|
||||
```
|
||||
|
||||
Note: vous pouvez utiliser `Home(props: IHomeProps)` et appeler `props.goHome` comme tout le reste du projet, mais le destructuring d'objet est autorisé.
|
||||
Note: vous pouvez utiliser `Home(props: IHomeProps)` et appeler `props.goHome` comme tout le reste du projet au lieu de le destructurer en `{ goHome }`, mais le destructuring d'objet est autorisé (et dans certains cas, c'est mieux avec).
|
||||
|
||||
Home est utilisé dans les composants Bar, UI, et Editor avant d'être appelé dans App. Il faut faire la même chose, ajouter la fonction dans les props et l'appeler dans le composant :
|
||||
|
||||
|
@ -270,25 +319,25 @@ export function Bar(props: IBarProps): JSX.Element {
|
|||
```
|
||||
*Faites la même chose pour UI et Editor.*
|
||||
|
||||
Enfin dans `App.tsx`, créez la fonction permettant de changer `isLoaded` vers `false`:
|
||||
Enfin dans `App.tsx`, créez la fonction permettant de changer `appState` vers `AppState.MainMenu`:
|
||||
|
||||
```tsx
|
||||
...
|
||||
if (isLoaded) {
|
||||
return (
|
||||
<div>
|
||||
<Editor
|
||||
root={props.root}
|
||||
configuration={editorState.configuration}
|
||||
history={editorState.history}
|
||||
historyCurrentStep={editorState.historyCurrentStep}
|
||||
goHome={() => {
|
||||
setLoaded(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
case AppState.Loaded:
|
||||
return (
|
||||
<div
|
||||
ref={appRef}
|
||||
className='App'
|
||||
>
|
||||
<Editor
|
||||
root={props.root}
|
||||
configuration={editorState.configuration}
|
||||
history={editorState.history}
|
||||
historyCurrentStep={editorState.historyCurrentStep}
|
||||
goHome={() => setAppState(AppState.MainMenu)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
...
|
||||
```
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue