i18n - docs translations (#15720)
Created by Github action <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds a full French documentation set covering developers (API, webhooks, backend/frontend, self‑hosting) and user guide (CRM essentials, data model, workflows, settings, integrations, pricing, reporting). > > - **Docs (FR i18n)**: > - **Developers**: Add `API`, `Webhooks`, backend (best practices, custom objects, feature flags, architecture, commands, Zapier), frontend (best practices, architecture, commands, hotkeys, style guide, Storybook, Figma), self‑hosting (Docker Compose, upgrade guide, cloud providers), introduction. > - **User Guide**: Add getting started (what is Twenty, create/configure workspace, migration, import/export), CRM essentials (contacts/accounts, pipelines, views), data model (objects, fields, relations, table views), collaboration (emails/calendars, notes, tasks), integrations API (overview, integrations), workflows (getting started, features, credits, internal automations, services), settings (profile, permissions, members, domains, releases, email/calendar setup), pricing (billing/FAQ), reporting overview, resources (GitHub, glossary), introduction. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 9ba8c2457156e8d25bf41c055731acface4b5277. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: github-actions <github-actions@twenty.com> Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
committed by
GitHub
parent
0fc538ac09
commit
154fb4665e
@@ -0,0 +1,333 @@
|
||||
---
|
||||
title: Meilleures pratiques
|
||||
image: /images/user-guide/tips/light-bulb.png
|
||||
---
|
||||
|
||||
<Frame>
|
||||
<img src="/images/user-guide/tips/light-bulb.png" alt="Header" />
|
||||
</Frame>
|
||||
|
||||
Ce document décrit les meilleures pratiques à suivre lors de votre travail sur l'interface frontend.
|
||||
|
||||
## Gestion de l'état
|
||||
|
||||
React et Recoil gèrent la gestion de l'état dans la base de code.
|
||||
|
||||
### Utilisez `useRecoilState` pour stocker l'état
|
||||
|
||||
C'est une bonne pratique de créer autant d'atomes que nécessaire pour stocker votre état.
|
||||
|
||||
<Warning>
|
||||
|
||||
Il vaut mieux utiliser des atomes supplémentaires plutôt que d'essayer d'être trop concis en perçant les propriétés.
|
||||
|
||||
</Warning>
|
||||
|
||||
```tsx
|
||||
export const myAtomState = atom({
|
||||
key: 'myAtomState',
|
||||
default: 'default value',
|
||||
});
|
||||
|
||||
export const MyComponent = () => {
|
||||
const [myAtom, setMyAtom] = useRecoilState(myAtomState);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input
|
||||
value={myAtom}
|
||||
onChange={(e) => setMyAtom(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Ne pas utiliser `useRef` pour stocker l'état
|
||||
|
||||
Évitez d'utiliser `useRef` pour stocker l'état.
|
||||
|
||||
Si vous souhaitez stocker un état, vous devez utiliser `useState` ou `useRecoilState`.
|
||||
|
||||
Consultez [comment gérer les re-rendus](#managing-re-renders) si vous avez l'impression d'avoir besoin de `useRef` pour empêcher certains re-rendus.
|
||||
|
||||
## Gestion des re-rendus
|
||||
|
||||
Les re-rendus peuvent être difficiles à gérer dans React.
|
||||
|
||||
Voici quelques règles à suivre pour éviter les re-rendus inutiles.
|
||||
|
||||
Gardez à l'esprit que vous pouvez **toujours** éviter les re-rendus en comprenant leur cause.
|
||||
|
||||
### Travaillez au niveau racine
|
||||
|
||||
Éviter les re-rendus dans les nouvelles fonctionnalités est désormais facile en les éliminant au niveau racine.
|
||||
|
||||
Le composant secondaire `PageChangeEffect` contient seulement un `useEffect` qui retient toute la logique à exécuter lors d'un changement de page.
|
||||
|
||||
De cette manière, vous savez qu'il n'y a qu'un seul endroit qui peut déclencher un re-rendu.
|
||||
|
||||
### Toujours réfléchir à deux fois avant d'ajouter `useEffect` dans votre code.
|
||||
|
||||
Les re-rendus sont souvent causés par des `useEffect` inutiles.
|
||||
|
||||
Vous devriez réfléchir si vous avez besoin de `useEffect`, ou si vous pouvez déplacer la logique dans une fonction de gestion d'événements.
|
||||
|
||||
Vous trouverez généralement facile de déplacer la logique dans une fonction `handleClick` ou `handleChange`.
|
||||
|
||||
Vous pouvez également les trouver dans des bibliothèques comme Apollo : `onCompleted`, `onError`, etc.
|
||||
|
||||
### Utilisez un composant frère pour extraire `useEffect` ou la logique de récupération des données
|
||||
|
||||
Si vous pensez devoir ajouter un `useEffect` dans votre composant racine, vous devriez envisager de l'extraire dans un composant secondaire.
|
||||
|
||||
Vous pouvez appliquer la même chose à la logique de récupération de données, avec les hooks Apollo.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad, will cause re-renders even if data is not changing,
|
||||
// because useEffect needs to be re-evaluated
|
||||
export const PageComponent = () => {
|
||||
const [data, setData] = useRecoilState(dataState);
|
||||
const [someDependency] = useRecoilState(someDependencyState);
|
||||
|
||||
useEffect(() => {
|
||||
if(someDependency !== data) {
|
||||
setData(someDependency);
|
||||
}
|
||||
}, [someDependency]);
|
||||
|
||||
return <div>{data}</div>;
|
||||
};
|
||||
|
||||
export const App = () => (
|
||||
<RecoilRoot>
|
||||
<PageComponent />
|
||||
</RecoilRoot>
|
||||
);
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ✅ Good, will not cause re-renders if data is not changing,
|
||||
// because useEffect is re-evaluated in another sibling component
|
||||
export const PageComponent = () => {
|
||||
const [data, setData] = useRecoilState(dataState);
|
||||
|
||||
return <div>{data}</div>;
|
||||
};
|
||||
|
||||
export const PageData = () => {
|
||||
const [data, setData] = useRecoilState(dataState);
|
||||
const [someDependency] = useRecoilState(someDependencyState);
|
||||
|
||||
useEffect(() => {
|
||||
if(someDependency !== data) {
|
||||
setData(someDependency);
|
||||
}
|
||||
}, [someDependency]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export const App = () => (
|
||||
<RecoilRoot>
|
||||
<PageData />
|
||||
<PageComponent />
|
||||
</RecoilRoot>
|
||||
);
|
||||
```
|
||||
|
||||
### Utilisez les états de famille de recoil et les sélecteurs de famille de recoil
|
||||
|
||||
Les états et sélecteurs de famille recoil sont un excellent moyen d'éviter les re-rendus.
|
||||
|
||||
Ils sont utiles lorsque vous devez stocker une liste d'articles.
|
||||
|
||||
### Vous ne devriez pas utiliser `React.memo(MyComponent)`
|
||||
|
||||
Évitez d'utiliser `React.memo()` car cela ne résout pas la cause du re-rendu, mais brise plutôt la chaîne de re-rendu, ce qui peut entraîner un comportement inattendu et rendre le code très difficile à refactoriser.
|
||||
|
||||
### Limitez l'utilisation de `useCallback` ou `useMemo`
|
||||
|
||||
Ils ne sont souvent pas nécessaires et rendront le code plus difficile à lire et à maintenir pour un gain de performance imperceptible.
|
||||
|
||||
## Console.logs
|
||||
|
||||
Les déclarations `console.log` sont précieuses pendant le développement, offrant des insights en temps réel sur les valeurs de variables et le flux de code. Mais, les laisser dans le code de production peut entraîner plusieurs problèmes :
|
||||
|
||||
1. **Performance** : Un journalisation excessive peut affecter les performances d'exécution, notamment sur les applications côté client.
|
||||
|
||||
2. **Sécurité** : La journalisation de données sensibles peut exposer des informations critiques à toute personne qui inspecte la console du navigateur.
|
||||
|
||||
3. **Propreté** : Remplir la console de logs peut masquer les avertissements ou erreurs importants que les développeurs ou outils doivent voir.
|
||||
|
||||
4. **Professionnalisme** : Les utilisateurs finaux ou clients vérifiant la console et voyant une myriade de déclarations de log pourraient remettre en question la qualité et la finition du code.
|
||||
|
||||
Assurez-vous de supprimer tous les `console.logs` avant de pousser le code en production.
|
||||
|
||||
## Nomination
|
||||
|
||||
### Nom des variables
|
||||
|
||||
Les noms de variables doivent décrire précisément l'objectif ou la fonction de la variable.
|
||||
|
||||
#### Le problème avec les noms génériques
|
||||
|
||||
Les noms génériques en programmation ne sont pas idéaux car ils manquent de spécificité, ce qui conduit à une ambiguïté et réduit la lisibilité du code. De tels noms ne parviennent pas à transmettre l'objectif de la variable ou de la fonction, rendant difficile pour les développeurs de comprendre l'intention du code sans une enquête plus approfondie. Cela peut entraîner un temps de débogage accru, une plus grande vulnérabilité aux erreurs et des difficultés de maintenance et de collaboration. Pendant ce temps, des noms descriptifs rendent le code explicite et plus facile à naviguer, améliorant la qualité du code et la productivité des développeurs.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad, uses a generic name that doesn't communicate its
|
||||
// purpose or content clearly
|
||||
const [value, setValue] = useState('');
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ✅ Good, uses a descriptive name
|
||||
const [email, setEmail] = useState('');
|
||||
```
|
||||
|
||||
#### Certains mots à éviter dans les noms de variables
|
||||
|
||||
- factice
|
||||
|
||||
### Gestionnaires d'événements
|
||||
|
||||
Les noms des gestionnaires d'événements doivent commencer par `handle`, tandis que `on` est un préfixe utilisé pour nommer les événements dans les propriétés des composants.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
const onEmailChange = (val: string) => {
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ✅ Good
|
||||
const handleEmailChange = (val: string) => {
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
## Props optionnels
|
||||
|
||||
Évitez de passer la valeur par défaut pour un prop optionnel.
|
||||
|
||||
**EXEMPLE**
|
||||
|
||||
Prenez le composant`EmailField` défini ci-dessous :
|
||||
|
||||
```tsx
|
||||
type EmailFieldProps = {
|
||||
value: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const EmailField = ({ value, disabled = false }: EmailFieldProps) => (
|
||||
<TextInput value={value} disabled={disabled} fullWidth />
|
||||
);
|
||||
```
|
||||
|
||||
**Utilisation**
|
||||
|
||||
```tsx
|
||||
// ❌ Bad, passing in the same value as the default value adds no value
|
||||
const Form = () => <EmailField value="username@email.com" disabled={false} />;
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ✅ Good, assumes the default value
|
||||
const Form = () => <EmailField value="username@email.com" />;
|
||||
```
|
||||
|
||||
## Composant en tant que props
|
||||
|
||||
Essayez autant que possible de transmettre des composants non instanciés comme props, afin que les enfants puissent décider eux-mêmes des props qu'ils ont besoin de passer.
|
||||
|
||||
L'exemple le plus courant pour cela est les composants icône :
|
||||
|
||||
```tsx
|
||||
const SomeParentComponent = () => <MyComponent Icon={MyIcon} />;
|
||||
|
||||
// In MyComponent
|
||||
const MyComponent = ({ MyIcon }: { MyIcon: IconComponent }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<MyIcon size={theme.icon.size.md}>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
```
|
||||
|
||||
Pour que React comprenne qu'un composant est un composant, vous devez utiliser PascalCase, pour l'instancier plus tard avec `<MyIcon>`
|
||||
|
||||
## Forage de Props : Gardez-le Minimal
|
||||
|
||||
Le forage de props, dans le contexte de React, fait référence à la pratique consistant à passer des variables d'état et leurs setters à travers de nombreuses couches de composants, même si les composants intermédiaires ne les utilisent pas. Bien que parfois nécessaire, un forage de props excessif peut entraîner :
|
||||
|
||||
1. **Lisibilité Réduite** : Retrouver l'origine d'un prop ou l'endroit où il est utilisé peut devenir complexe dans une structure de composants profondément imbriquée.
|
||||
|
||||
2. **Défis de Maintenance** : Des modifications dans la structure des props d'un composant peuvent nécessiter des ajustements dans plusieurs composants, même s'ils n'utilisent pas directement le prop.
|
||||
|
||||
3. **Réutilisabilité Réduite du Composant** : Un composant recevant beaucoup de props uniquement pour les transmettre devient moins polyvalent et plus difficile à réutiliser dans différents contextes.
|
||||
|
||||
Si vous sentez que vous utilisez un forage de props excessif, voir [les meilleures pratiques de gestion d'état](#state-management).
|
||||
|
||||
## Imports
|
||||
|
||||
Lors de l'importation, optez pour les alias désignés plutôt que de spécifier des chemins complets ou relatifs.
|
||||
|
||||
**Les Alias**
|
||||
|
||||
```js
|
||||
{
|
||||
alias: {
|
||||
"~": path.resolve(__dirname, "src"),
|
||||
"@": path.resolve(__dirname, "src/modules"),
|
||||
"@testing": path.resolve(__dirname, "src/testing"),
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**Utilisation**
|
||||
|
||||
```tsx
|
||||
// ❌ Bad, specifies the entire relative path
|
||||
import {
|
||||
CatalogDecorator
|
||||
} from '../../../../../testing/decorators/CatalogDecorator';
|
||||
import {
|
||||
ComponentDecorator
|
||||
} from '../../../../../testing/decorators/ComponentDecorator';
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ✅ Good, utilises the designated aliases
|
||||
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
|
||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||
```
|
||||
|
||||
## Validation de Schéma
|
||||
|
||||
[Zod](https://github.com/colinhacks/zod) est le validateur de schéma pour les objets non typés :
|
||||
|
||||
```js
|
||||
const validationSchema = z
|
||||
.object({
|
||||
exist: z.boolean(),
|
||||
email: z
|
||||
.string()
|
||||
.email('Email must be a valid email'),
|
||||
password: z
|
||||
.string()
|
||||
.regex(PASSWORD_REGEX, 'Password must contain at least 8 characters'),
|
||||
})
|
||||
.required();
|
||||
|
||||
type Form = z.infer<typeof validationSchema>;
|
||||
```
|
||||
|
||||
## Changements Radicaux
|
||||
|
||||
Effectuez toujours des tests manuels approfondis avant de continuer pour garantir que les modifications n'ont pas causé de perturbations ailleurs, étant donné que les tests n'ont pas encore été intégrés de manière extensive.
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
---
|
||||
title: Architecture des Dossiers
|
||||
info: Un aperçu détaillé de notre architecture de dossiers
|
||||
image: /images/user-guide/fields/field.png
|
||||
---
|
||||
|
||||
<Frame>
|
||||
<img src="/images/user-guide/fields/field.png" alt="Header" />
|
||||
</Frame>
|
||||
|
||||
Dans ce guide, vous explorerez les détails de la structure du répertoire de projet et comment elle contribue à l'organisation et à la maintenabilité de Twenty.
|
||||
|
||||
En suivant cette convention d'architecture de dossiers, il est plus facile de trouver les fichiers liés à des fonctionnalités spécifiques et de s'assurer que l'application est évolutive et maintenable.
|
||||
|
||||
```
|
||||
front
|
||||
└───modules
|
||||
│ └───module1
|
||||
│ │ └───submodule1
|
||||
│ └───module2
|
||||
│ └───ui
|
||||
│ │ └───display
|
||||
│ │ └───inputs
|
||||
│ │ │ └───buttons
|
||||
│ │ └───...
|
||||
└───pages
|
||||
└───...
|
||||
```
|
||||
|
||||
## Pages
|
||||
|
||||
Comprend les composants de haut niveau définis par les routes de l'application. Ils importent des composants plus bas niveau du dossier des modules (plus de détails ci-dessous).
|
||||
|
||||
## Modules
|
||||
|
||||
Chaque module représente une fonctionnalité ou un groupe de fonctionnalités, comprenant ses composants spécifiques, ses états, et sa logique opérationnelle.
|
||||
Ils doivent tous suivre la structure ci-dessous. Vous pouvez imbriquer des modules dans des modules (appelés sous-modules) et les mêmes règles s'appliqueront.
|
||||
|
||||
```
|
||||
module1
|
||||
└───components
|
||||
│ └───component1
|
||||
│ └───component2
|
||||
└───constants
|
||||
└───contexts
|
||||
└───graphql
|
||||
│ └───fragments
|
||||
│ └───queries
|
||||
│ └───mutations
|
||||
└───hooks
|
||||
│ └───internal
|
||||
└───states
|
||||
│ └───selectors
|
||||
└───types
|
||||
└───utils
|
||||
```
|
||||
|
||||
### Contextes
|
||||
|
||||
Un contexte est un moyen de transmettre des données à travers l'arborescence de composants sans avoir à transmettre les propriétés manuellement à chaque niveau.
|
||||
|
||||
Voir [React Context](https://react.dev/reference/react#context-hooks) pour plus de détails.
|
||||
|
||||
### GraphQL
|
||||
|
||||
Comprend des fragments, des requêtes et des mutations.
|
||||
|
||||
Voir [GraphQL](https://graphql.org/learn/) pour plus de détails.
|
||||
|
||||
- Fragments
|
||||
|
||||
Un fragment est une partie réutilisable d'une requête, que vous pouvez utiliser dans différents endroits. En utilisant des fragments, il est plus facile d'éviter de dupliquer du code.
|
||||
|
||||
Voir [GraphQL Fragments](https://graphql.org/learn/queries/#fragments) pour plus de détails.
|
||||
|
||||
- Requêtes
|
||||
|
||||
Voir [GraphQL Queries](https://graphql.org/learn/queries/) pour plus de détails.
|
||||
|
||||
- Mutations
|
||||
|
||||
Voir [GraphQL Mutations](https://graphql.org/learn/queries/#mutations) pour plus de détails.
|
||||
|
||||
### Hooks
|
||||
|
||||
Voir [Hooks](https://react.dev/learn/reusing-logic-with-custom-hooks) pour plus de détails.
|
||||
|
||||
### États
|
||||
|
||||
Contient la logique de gestion des états. [RecoilJS](https://recoiljs.org) gère cela.
|
||||
|
||||
- Sélecteurs : Voir [RecoilJS Selectors](https://recoiljs.org/docs/basic-tutorial/selectors) pour plus de détails.
|
||||
|
||||
La gestion de l'état intégrée de React gère toujours l'état au sein d'un composant.
|
||||
|
||||
### Utilitaires
|
||||
|
||||
Devrait juste contenir des fonctions pures réutilisables. Autrement, créez des hooks personnalisés dans le dossier `hooks`.
|
||||
|
||||
## UI
|
||||
|
||||
Contient tous les composants d'interface utilisateur réutilisables utilisés dans l'application.
|
||||
|
||||
Ce dossier peut contenir des sous-dossiers, comme `data`, `display`, `feedback`, et `input` pour des types de composants spécifiques. Chaque composant doit être autonome et réutilisable, de sorte que vous puissiez l'utiliser dans différentes parties de l'application.
|
||||
|
||||
En séparant les composants UI des autres composants dans le dossier `modules`, il est plus facile de maintenir un design cohérent et d'effectuer des changements de l'interface utilisateur sans affecter d'autres parties (logique métier) de la base de code.
|
||||
|
||||
## Interface et dépendances
|
||||
|
||||
Vous pouvez importer le code d'autres modules depuis n'importe quel module, sauf pour le dossier `ui`. Cela permettra de garder son code facile à tester.
|
||||
|
||||
### Interne
|
||||
|
||||
Chaque partie (hooks, états, ...) d'un module peut avoir un dossier `interne`, qui contient des parties utilisées uniquement au sein du module.
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
title: Commandes Frontend
|
||||
image: /images/user-guide/create-workspace/workspace-cover.png
|
||||
---
|
||||
|
||||
<Frame>
|
||||
<img src="/images/user-guide/create-workspace/workspace-cover.png" alt="Header" />
|
||||
</Frame>
|
||||
|
||||
## Commandes utiles
|
||||
|
||||
### Lancement de l'application
|
||||
|
||||
```bash
|
||||
npx nx start twenty-front
|
||||
```
|
||||
|
||||
### Régénérer le schéma GraphQL basé sur le schéma API GraphQL
|
||||
|
||||
```bash
|
||||
npx nx run twenty-front:graphql:generate --configuration=metadata
|
||||
```
|
||||
|
||||
OU
|
||||
|
||||
```bash
|
||||
npx nx run twenty-front:graphql:generate
|
||||
```
|
||||
|
||||
### Analyse
|
||||
|
||||
```bash
|
||||
npx nx run twenty-front:lint # pass --fix to fix lint errors
|
||||
```
|
||||
|
||||
## Traductions
|
||||
|
||||
```bash
|
||||
npx nx run twenty-front:lingui:extract
|
||||
npx nx run twenty-front:lingui:compile
|
||||
```
|
||||
|
||||
### Test
|
||||
|
||||
```bash
|
||||
npx nx run twenty-front:test # run jest tests
|
||||
npx nx run twenty-front:storybook:serve:dev # run storybook
|
||||
npx nx run twenty-front:storybook:test # run tests # (needs yarn storybook:serve:dev to be running)
|
||||
npx nx run twenty-front:storybook:coverage # (needs yarn storybook:serve:dev to be running)
|
||||
```
|
||||
|
||||
## Écosystème Tech
|
||||
|
||||
Le projet a une stack simple et propre, avec un code boilerplate minimal.
|
||||
|
||||
**Application**
|
||||
|
||||
- [React](https://react.dev/)
|
||||
- [Apollo](https://www.apollographql.com/docs/)
|
||||
- [GraphQL Codegen](https://the-guild.dev/graphql/codegen)
|
||||
- [Recoil](https://recoiljs.org/docs/introduction/core-concepts)
|
||||
- [TypeScript](https://www.typescriptlang.org/)
|
||||
|
||||
**Tests**
|
||||
|
||||
- [Jest](https://jestjs.io/)
|
||||
- [Storybook](https://storybook.js.org/)
|
||||
|
||||
**Outils**
|
||||
|
||||
- [Yarn](https://yarnpkg.com/)
|
||||
- [Craco](https://craco.js.org/docs/)
|
||||
- [ESLint](https://eslint.org/)
|
||||
|
||||
## Architecture
|
||||
|
||||
### Routage
|
||||
|
||||
[React Router](https://reactrouter.com/) gère le routage.
|
||||
|
||||
Pour éviter les [re-renders](/developers/frontend-development/best-practices-front#managing-re-renders) inutiles, toute la logique de routage est dans un `useEffect` dans `PageChangeEffect`.
|
||||
|
||||
### Gestion de l'État
|
||||
|
||||
[Recoil](https://recoiljs.org/docs/introduction/core-concepts) gère la gestion de l'état.
|
||||
|
||||
Voir [les meilleures pratiques](/developers/frontend-development/best-practices-front#state-management) pour plus d'informations sur la gestion de l'état.
|
||||
|
||||
## Tests
|
||||
|
||||
[Jest](https://jestjs.io/) sert de guide pour les tests unitaires tandis que [Storybook](https://storybook.js.org/) est utilisé pour les tests de composants.
|
||||
|
||||
Jest est principalement utilisé pour tester les fonctions utilitaires, et non les composants eux-mêmes.
|
||||
|
||||
Storybook est utilisé pour tester le comportement des composants isolés, ainsi que pour afficher le système de design.
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
---
|
||||
title: Raccourcis clavier
|
||||
image: /images/user-guide/table-views/table.png
|
||||
---
|
||||
|
||||
<Frame>
|
||||
<img src="/images/user-guide/table-views/table.png" alt="Header" />
|
||||
</Frame>
|
||||
|
||||
## Introduction
|
||||
|
||||
Lorsque vous devez écouter une touche de raccourci, vous utilisez normalement l'événement `onKeyDown`.
|
||||
|
||||
Cependant, dans `twenty-front`, vous pourriez avoir des conflits entre les mêmes raccourcis utilisés dans différents composants, montés en même temps.
|
||||
|
||||
Par exemple, si vous avez une page qui écoute la touche Entrée, et une fenêtre modale qui écoute aussi la touche Entrée, avec un composant Select à l'intérieur de cette fenêtre qui écoute également la touche Entrée, vous risquez d'avoir un conflit lorsque tous sont montés en même temps.
|
||||
|
||||
## Le hook `useScopedHotkeys`
|
||||
|
||||
Pour résoudre ce problème, nous avons un hook personnalisé qui permet d'écouter les raccourcis sans aucun conflit.
|
||||
|
||||
Vous l'insérez dans un composant et il écoutera les raccourcis uniquement lorsque le composant est monté ET lorsque le **périmètre du raccourci** spécifié est actif.
|
||||
|
||||
## Comment écouter les raccourcis en pratique ?
|
||||
|
||||
Deux étapes sont nécessaires pour configurer l'écoute des raccourcis :
|
||||
|
||||
1. Définir le [périmètre du raccourci](#what-is-a-hotkey-scope-) qui écoutera les raccourcis
|
||||
2. Utiliser le hook `useScopedHotkeys` pour écouter les raccourcis
|
||||
|
||||
La configuration des périmètres de raccourcis est nécessaire même sur des pages simples, car d'autres éléments de l'interface utilisateur comme le menu de gauche ou le menu de commandes pourraient également écouter les raccourcis.
|
||||
|
||||
## Cas d'utilisation des raccourcis
|
||||
|
||||
En général, vous aurez deux cas d'utilisation nécessitant des raccourcis :
|
||||
|
||||
1. Dans une page ou un composant monté dans une page
|
||||
2. Dans un composant de type modal qui prend le focus à la suite d'une action utilisateur
|
||||
|
||||
Le deuxième cas d'utilisation peut se produire de manière récursive : un menu déroulant dans une fenêtre modale par exemple.
|
||||
|
||||
### Écouter les raccourcis dans une page
|
||||
|
||||
Exemple :
|
||||
|
||||
```tsx
|
||||
const PageListeningEnter = () => {
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
// 1. Set the hotkey scope in a useEffect
|
||||
useEffect(() => {
|
||||
setHotkeyScopeAndMemorizePreviousScope(
|
||||
ExampleHotkeyScopes.ExampleEnterPage,
|
||||
);
|
||||
|
||||
// Revert to the previous hotkey scope when the component is unmounted
|
||||
return () => {
|
||||
goBackToPreviousHotkeyScope();
|
||||
};
|
||||
}, [goBackToPreviousHotkeyScope, setHotkeyScopeAndMemorizePreviousScope]);
|
||||
|
||||
// 2. Use the useScopedHotkeys hook
|
||||
useScopedHotkeys(
|
||||
Key.Enter,
|
||||
() => {
|
||||
// Some logic executed on this page when the user presses Enter
|
||||
// ...
|
||||
},
|
||||
ExampleHotkeyScopes.ExampleEnterPage,
|
||||
);
|
||||
|
||||
return <div>My page that listens for Enter</div>;
|
||||
};
|
||||
```
|
||||
|
||||
### Écouter les raccourcis dans un composant de type modal
|
||||
|
||||
Pour cet exemple, nous allons utiliser un composant modal qui écoute la touche Échap pour informer son parent de le fermer.
|
||||
|
||||
Ici, l'interaction utilisateur change le périmètre.
|
||||
|
||||
```tsx
|
||||
const ExamplePageWithModal = () => {
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
const handleOpenModalClick = () => {
|
||||
// 1. Set the hotkey scope when user opens the modal
|
||||
setShowModal(true);
|
||||
setHotkeyScopeAndMemorizePreviousScope(
|
||||
ExampleHotkeyScopes.ExampleModal,
|
||||
);
|
||||
};
|
||||
|
||||
const handleModalClose = () => {
|
||||
// 1. Revert to the previous hotkey scope when the modal is closed
|
||||
setShowModal(false);
|
||||
goBackToPreviousHotkeyScope();
|
||||
};
|
||||
|
||||
return <div>
|
||||
<h1>My page with a modal</h1>
|
||||
<button onClick={handleOpenModalClick}>Open modal</button>
|
||||
{showModal && <MyModalComponent onClose={handleModalClose} />}
|
||||
</div>;
|
||||
};
|
||||
```
|
||||
|
||||
Ensuite, dans le composant modal :
|
||||
|
||||
```tsx
|
||||
const MyDropdownComponent = ({ onClose }: { onClose: () => void }) => {
|
||||
// 2. Use the useScopedHotkeys hook to listen for Escape.
|
||||
// Note that escape is a common hotkey that could be used by many other components
|
||||
// So it's important to use a hotkey scope to avoid conflicts
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
() => {
|
||||
onClose()
|
||||
},
|
||||
ExampleHotkeyScopes.ExampleModal,
|
||||
);
|
||||
|
||||
return <div>My modal component</div>;
|
||||
};
|
||||
```
|
||||
|
||||
Il est important d'utiliser ce schéma lorsque vous n'êtes pas sûr que l'utilisation simple d'un useEffect avec montage/démontage suffira à éviter les conflits.
|
||||
|
||||
Ces conflits peuvent être difficiles à déboguer et peuvent survenir plus souvent qu'on ne le croit avec les useEffects.
|
||||
|
||||
## Qu'est-ce qu'un périmètre de raccourci ?
|
||||
|
||||
Un périmètre de raccourci est une chaîne de caractères qui représente un contexte dans lequel les raccourcis sont actifs. Il est généralement encodé sous forme d'enum.
|
||||
|
||||
Lorsque vous modifiez le périmètre de raccourci, les raccourcis qui écoutent ce périmètre seront activés et ceux qui écoutent d'autres périmètres seront désactivés.
|
||||
|
||||
Vous ne pouvez définir qu'un seul périmètre à la fois.
|
||||
|
||||
Par exemple, les périmètres de raccourcis pour chaque page sont définis dans l'`enum PageHotkeyScope` :
|
||||
|
||||
```tsx
|
||||
export enum PageHotkeyScope {
|
||||
Settings = 'settings',
|
||||
CreateWorkspace = 'create-workspace',
|
||||
SignInUp = 'sign-in-up',
|
||||
CreateProfile = 'create-profile',
|
||||
PlanRequired = 'plan-required',
|
||||
ShowPage = 'show-page',
|
||||
PersonShowPage = 'person-show-page',
|
||||
CompanyShowPage = 'company-show-page',
|
||||
CompaniesPage = 'companies-page',
|
||||
PeoplePage = 'people-page',
|
||||
OpportunitiesPage = 'opportunities-page',
|
||||
ProfilePage = 'profile-page',
|
||||
WorkspaceMemberPage = 'workspace-member-page',
|
||||
TaskPage = 'task-page',
|
||||
}
|
||||
```
|
||||
|
||||
En interne, le périmètre sélectionné est stocké dans un état Recoil qui est partagé dans toute l'application :
|
||||
|
||||
```tsx
|
||||
export const currentHotkeyScopeState = createState<HotkeyScope>({
|
||||
key: 'currentHotkeyScopeState',
|
||||
defaultValue: INITIAL_HOTKEYS_SCOPE,
|
||||
});
|
||||
```
|
||||
|
||||
Mais cet état Recoil ne doit jamais être manipulé manuellement ! Nous verrons comment l'utiliser dans la prochaine section.
|
||||
|
||||
## Comment cela fonctionne-t-il en interne ?
|
||||
|
||||
Nous avons créé un léger emballage au-dessus de [react-hotkeys-hook](https://react-hotkeys-hook.vercel.app/docs/intro) qui le rend plus performant et évite les rendus inutiles.
|
||||
|
||||
Nous créons également un état Recoil pour gérer l'état du périmètre des raccourcis et le rendre disponible partout dans l'application.
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Storybook
|
||||
description: Parcourir la bibliothèque de composants UI de Twenty
|
||||
---
|
||||
|
||||
Consultez notre bibliothèque de composants complète et la documentation dans Storybook.
|
||||
|
||||
[Ouvrir Storybook →](https://storybook.twenty.com)
|
||||
@@ -0,0 +1,295 @@
|
||||
---
|
||||
title: Guide de style
|
||||
image: /images/user-guide/notes/notes_header.png
|
||||
---
|
||||
|
||||
<Frame>
|
||||
<img src="/images/user-guide/notes/notes_header.png" alt="Header" />
|
||||
</Frame>
|
||||
|
||||
Ce document inclut les règles à suivre lors de l'écriture de code.
|
||||
|
||||
L'objectif ici est d'avoir une base de code cohérente, facile à lire et à maintenir.
|
||||
|
||||
Pour cela, il vaut mieux être un peu plus verbeux que trop concis.
|
||||
|
||||
Gardez toujours à l'esprit que les gens lisent le code plus souvent qu'ils ne l'écrivent, surtout dans un projet open source où tout le monde peut contribuer.
|
||||
|
||||
Il existe de nombreuses règles qui ne sont pas définies ici, mais qui sont vérifiées automatiquement par des linters.
|
||||
|
||||
## React
|
||||
|
||||
### Utilisez des composants fonctionnels
|
||||
|
||||
Utilisez toujours des composants fonctionnels TSX.
|
||||
|
||||
N'utilisez pas `import` par défaut avec `const`, car c'est plus difficile à lire et plus difficile à importer avec l'autocomplétion du code.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad, harder to read, harder to import with code completion
|
||||
const MyComponent = () => {
|
||||
return <div>Hello World</div>;
|
||||
};
|
||||
|
||||
export default MyComponent;
|
||||
|
||||
// ✅ Good, easy to read, easy to import with code completion
|
||||
export function MyComponent() {
|
||||
return <div>Hello World</div>;
|
||||
};
|
||||
```
|
||||
|
||||
### Propriétés
|
||||
|
||||
Créez le type des props et nommez-le `(NomDuComposant)Props` s'il n'est pas nécessaire de l'exporter.
|
||||
|
||||
Utilisez la déstructuration des props.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad, no type
|
||||
export const MyComponent = (props) => <div>Hello {props.name}</div>;
|
||||
|
||||
// ✅ Good, type
|
||||
type MyComponentProps = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const MyComponent = ({ name }: MyComponentProps) => <div>Hello {name}</div>;
|
||||
```
|
||||
|
||||
#### Évitez d'utiliser `React.FC` ou `React.FunctionComponent` pour définir les types de props.
|
||||
|
||||
```tsx
|
||||
/* ❌ - Bad, defines the component type annotations with `FC`
|
||||
* - With `React.FC`, the component implicitly accepts a `children` prop
|
||||
* even if it's not defined in the prop type. This might not always be
|
||||
* desirable, especially if the component doesn't intend to render
|
||||
* children.
|
||||
*/
|
||||
const EmailField: React.FC<{
|
||||
value: string;
|
||||
}> = ({ value }) => <TextInput value={value} disabled fullWidth />;
|
||||
```
|
||||
|
||||
```tsx
|
||||
/* ✅ - Good, a separate type (OwnProps) is explicitly defined for the
|
||||
* component's props
|
||||
* - This method doesn't automatically include the children prop. If
|
||||
* you want to include it, you have to specify it in OwnProps.
|
||||
*/
|
||||
type EmailFieldProps = {
|
||||
value: string;
|
||||
};
|
||||
|
||||
const EmailField = ({ value }: EmailFieldProps) => (
|
||||
<TextInput value={value} disabled fullWidth />
|
||||
);
|
||||
```
|
||||
|
||||
#### Pas de propagation de props à variable unique dans les éléments JSX
|
||||
|
||||
Évitez d'utiliser la propagation de props à variable unique dans les éléments JSX, comme `{...props}`. Cette pratique résulte souvent en un code moins lisible et plus difficile à maintenir car il n'est pas clair quels props le composant reçoit.
|
||||
|
||||
```tsx
|
||||
/* ❌ - Bad, spreads a single variable prop into the underlying component
|
||||
*/
|
||||
const MyComponent = (props: OwnProps) => {
|
||||
return <OtherComponent {...props} />;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
/* ✅ - Good, Explicitly lists all props
|
||||
* - Enhances readability and maintainability
|
||||
*/
|
||||
const MyComponent = ({ prop1, prop2, prop3 }: MyComponentProps) => {
|
||||
return <OtherComponent {...{ prop1, prop2, prop3 }} />;
|
||||
};
|
||||
```
|
||||
|
||||
Raisonnement :
|
||||
|
||||
- D'un coup d'œil, il est plus clair quels props le code transmet, le rendant plus facile à comprendre et à maintenir.
|
||||
- Cela aide à éviter le couplage serré entre les composants via leurs props.
|
||||
- Les outils de linting facilitent l'identification des props mal orthographiés ou inutilisées lorsque vous listez explicitement les props.
|
||||
|
||||
## JavaScript
|
||||
|
||||
### Utilisez l'opérateur de coalescence nulle `??`
|
||||
|
||||
```tsx
|
||||
// ❌ Bad, can return 'default' even if value is 0 or ''
|
||||
const value = process.env.MY_VALUE || 'default';
|
||||
|
||||
// ✅ Good, will return 'default' only if value is null or undefined
|
||||
const value = process.env.MY_VALUE ?? 'default';
|
||||
```
|
||||
|
||||
### Utilisez la chaîne facultative `?.`
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
onClick && onClick();
|
||||
|
||||
// ✅ Good
|
||||
onClick?.();
|
||||
```
|
||||
|
||||
## TypeScript
|
||||
|
||||
### Utilisez `type` au lieu de `interface`
|
||||
|
||||
Utilisez toujours `type` au lieu de `interface`, car ils se chevauchent presque toujours, et `type` est plus flexible.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
interface MyInterface {
|
||||
name: string;
|
||||
}
|
||||
|
||||
// ✅ Good
|
||||
type MyType = {
|
||||
name: string;
|
||||
};
|
||||
```
|
||||
|
||||
### Utilisez des littéraux de chaîne au lieu d'enums
|
||||
|
||||
[Les littéraux de chaîne](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) sont la méthode de référence pour gérer des valeurs semblables à des enums dans TypeScript. Ils sont plus faciles à étendre avec Pick et Omit, et offrent une meilleure expérience pour le développeur, notamment avec l'autocompletion de code.
|
||||
|
||||
Vous pouvez voir pourquoi TypeScript recommande d'éviter les enums [ici](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#enums).
|
||||
|
||||
```tsx
|
||||
// ❌ Bad, utilizes an enum
|
||||
enum Color {
|
||||
Red = "red",
|
||||
Green = "green",
|
||||
Blue = "blue",
|
||||
}
|
||||
|
||||
let color = Color.Red;
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ✅ Good, utilizes a string literal
|
||||
|
||||
let color: "red" | "green" | "blue" = "red";
|
||||
```
|
||||
|
||||
#### GraphQL et bibliothèques internes
|
||||
|
||||
Vous devriez utiliser les enums générés par le codegen GraphQL.
|
||||
|
||||
Il est également préférable d'utiliser un enum lors de l'utilisation d'une bibliothèque interne, afin que la bibliothèque interne n'ait pas à exposer un type de littéral de chaîne qui n'est pas lié à l'API interne.
|
||||
|
||||
Exemple :
|
||||
|
||||
```TSX
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
setHotkeyScopeAndMemorizePreviousScope(
|
||||
RelationPickerHotkeyScope.RelationPicker,
|
||||
);
|
||||
```
|
||||
|
||||
## Stylisme
|
||||
|
||||
### Utilisez StyledComponents
|
||||
|
||||
Styliser les composants avec [styled-components](https://emotion.sh/docs/styled).
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
<div className="my-class">Hello World</div>
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ✅ Good
|
||||
const StyledTitle = styled.div`
|
||||
color: red;
|
||||
`;
|
||||
```
|
||||
|
||||
Préfixez les composants stylisés avec "Styled" pour les différencier des composants "réels".
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
const Title = styled.div`
|
||||
color: red;
|
||||
`;
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ✅ Good
|
||||
const StyledTitle = styled.div`
|
||||
color: red;
|
||||
`;
|
||||
```
|
||||
|
||||
### Thematisation
|
||||
|
||||
Utiliser le thème pour la majorité du stylisme des composants est l'approche préférée.
|
||||
|
||||
#### Unités de mesure
|
||||
|
||||
Évitez d'utiliser des valeurs `px` ou `rem` directement dans les composants stylisés. Les valeurs nécessaires sont généralement déjà définies dans le thème, il est donc recommandé d'utiliser le thème à ces fins.
|
||||
|
||||
#### Couleurs
|
||||
|
||||
Évitez d'introduire de nouvelles couleurs ; utilisez plutôt la palette existante du thème. Si la palette ne correspond pas, veuillez laisser un commentaire pour que l'équipe puisse rectifier cela.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad, directly specifies style values without utilizing the theme
|
||||
const StyledButton = styled.button`
|
||||
color: #333333;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
margin-left: 4px;
|
||||
border-radius: 50px;
|
||||
`;
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ✅ Good, utilizes the theme
|
||||
const StyledButton = styled.button`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
font-size: ${({ theme }) => theme.font.size.md};
|
||||
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||
margin-left: ${({ theme }) => theme.spacing(1)};
|
||||
border-radius: ${({ theme }) => theme.border.rounded};
|
||||
`;
|
||||
```
|
||||
|
||||
## Application d'interdiction d'importations de type
|
||||
|
||||
Évitez les importations de type. Pour appliquer cette norme, une règle ESLint vérifie et signale toutes les importations de type. Cela aide à maintenir la cohérence et la lisibilité dans le code TypeScript.
|
||||
|
||||
```tsx
|
||||
// ❌ Bad
|
||||
import { type Meta, type StoryObj } from '@storybook/react';
|
||||
|
||||
// ❌ Bad
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
// ✅ Good
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
```
|
||||
|
||||
### Pourquoi éviter les importations de type
|
||||
|
||||
- **Cohérence** : En évitant les importations de type et en utilisant une seule approche pour les importations de type et de valeur, la base de code reste cohérente dans son style d'importation de module.
|
||||
|
||||
- **Lisibilité** : Les importations sans type améliorent la lisibilité du code en clarifiant quand vous importez des valeurs ou des types. Cela réduit l'ambiguïté et facilite la compréhension de l'objectif des symboles importés.
|
||||
|
||||
- **Maintenabilité** : Cela améliore la maintenabilité de la base de code car les développeurs peuvent identifier et localiser les importations uniquement de type lors de la révision ou de la modification du code.
|
||||
|
||||
### Règle ESLint
|
||||
|
||||
Une règle ESLint, `@typescript-eslint/consistent-type-imports`, applique la norme d'importation sans type. Cette règle génère des erreurs ou des avertissements pour toutes les violations d'importations de type.
|
||||
|
||||
Veillez à ce que cette règle aborde spécifiquement les rares cas particuliers où se produisent des importations de type involontaires. TypeScript lui-même déconseille cette pratique, comme mentionné dans les [notes de version de TypeScript 3.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html). Dans la majorité des situations, vous ne devriez pas avoir besoin d'utiliser des importations uniquement de type.
|
||||
|
||||
Pour garantir la conformité de votre code avec cette règle, assurez-vous d'exécuter ESLint dans le cadre de votre flux de travail de développement.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Travailler avec Figma
|
||||
info: Apprenez comment vous pouvez collaborer avec le Figma de Twenty
|
||||
image: /images/user-guide/objects/objects.png
|
||||
---
|
||||
|
||||
<Frame>
|
||||
<img src="/images/user-guide/objects/objects.png" alt="Header" />
|
||||
</Frame>
|
||||
|
||||
Figma est un outil de conception d'interface collaboratif qui aide à surmonter la barrière de communication entre designers et développeurs.
|
||||
Ce guide explique comment vous pouvez collaborer avec Figma.
|
||||
|
||||
## Accès
|
||||
|
||||
1. **Accédez au lien partagé :** Vous pouvez accéder au fichier Figma du projet [ici](https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty).
|
||||
2. **Se connecter :** Si vous n'êtes pas déjà connecté, Figma vous invitera à le faire.
|
||||
Les fonctionnalités clés ne sont disponibles que pour les utilisateurs connectés, telles que le mode développeur et la possibilité de sélectionner un cadre dédié.
|
||||
|
||||
<Warning>
|
||||
|
||||
Vous ne pourrez pas collaborer efficacement sans compte.
|
||||
|
||||
</Warning>
|
||||
|
||||
## Structure de Figma
|
||||
|
||||
Sur la barre latérale gauche, vous pouvez accéder aux différentes pages du Figma de Twenty. Voici comment elles sont organisées :
|
||||
|
||||
- **Page des composants :** C'est la première page. Le designer l'utilise pour créer et organiser les éléments de design réutilisables utilisés dans tout le fichier design. Par exemple, boutons, icônes, symboles ou tout autre composant réutilisable. Elle sert à maintenir la cohérence dans le design.
|
||||
- **Page principale :** La deuxième page est la page principale, qui montre l'interface utilisateur complète du projet. Vous pouvez appuyer sur _**Play**_ pour utiliser le prototype complet de l'application.
|
||||
- **Pages des fonctionnalités :** Les autres pages sont généralement dédiées aux fonctionnalités en cours de développement. Elles contiennent le design de fonctionnalités ou modules spécifiques de l'application ou du site web. Elles sont généralement encore en cours de développement.
|
||||
|
||||
## Conseils utiles
|
||||
|
||||
Avec un accès en lecture seule, vous ne pouvez pas modifier le design, mais vous pouvez accéder à toutes les fonctionnalités utiles pour convertir les designs en code.
|
||||
|
||||
### Utiliser le mode dev
|
||||
|
||||
Le Mode Dev de Figma améliore la productivité des développeurs en fournissant une navigation simple dans le design, une gestion efficace des ressources, des outils de communication performants, des intégrations de boîte à outils, des extraits de code rapides et des informations clés sur les calques, comblant ainsi le fossé entre design et développement. Vous pouvez en savoir plus sur le mode Dev [ici](https://www.figma.com/dev-mode/).
|
||||
|
||||
Basculez vers le mode « Développeur » dans la partie droite de la barre d'outils pour voir les spécifications du design, copier du CSS et accéder aux ressources.
|
||||
|
||||
### Utilisez le Prototype
|
||||
|
||||
Cliquez sur n'importe quel élément du canvas et appuyez sur le bouton « Play » en haut à droite de l'interface pour accéder à la vue du prototype. Le mode Prototype vous permet d'interagir avec le design comme s'il s'agissait du produit final. Il montre le flux entre les écrans et comment les éléments de l'interface tels que les boutons, les liens ou les menus se comportent lorsqu'ils sont interactifs.
|
||||
|
||||
1. **Comprendre les transitions et animations :** En mode Prototype, vous pouvez voir toutes les transitions ou animations ajoutées par un designer entre écrans ou éléments UI, fournissant des instructions visuelles claires aux développeurs sur le comportement et le style attendus.
|
||||
2. **Clarification de l'implémentation :** Un prototype peut aussi aider à réduire les ambiguïtés. Les développeurs peuvent interagir avec lui pour mieux comprendre la fonctionnalité ou l'apparence de certains éléments.
|
||||
|
||||
Pour des détails et instructions plus complets sur l'apprentissage de la plateforme Figma, vous pouvez visiter la [Documentation officielle de Figma](https://help.figma.com/hc/fr).
|
||||
|
||||
### Mesurer les distances
|
||||
|
||||
Sélectionnez un élément, maintenez la touche `Option` (Mac) ou `Alt` (Windows), puis survolez un autre élément pour voir la distance entre eux.
|
||||
|
||||
### Extension Figma pour VSCode (Recommandée)
|
||||
|
||||
[Figma pour VS Code](https://marketplace.visualstudio.com/items?itemName=figma.figma-vscode-extension)
|
||||
vous permet de naviguer et d'inspecter les fichiers design, de collaborer avec les designers, de suivre les changements et d'accélérer la mise en œuvre - le tout sans quitter votre éditeur de texte.
|
||||
Cela fait partie de nos extensions recommandées.
|
||||
|
||||
## Collaboration
|
||||
|
||||
1. **Utilisation des commentaires :** N'hésitez pas à utiliser la fonction commentaire en cliquant sur l'icône de bulle dans la partie gauche de la barre d'outils.
|
||||
2. **Conversation par curseur :** Une fonctionnalité intéressante de Figma est la conversation par curseur. Il suffit d'appuyer sur `;` sur Mac et `/` sur Windows pour envoyer un message si vous voyez quelqu'un d'autre utiliser Figma en même temps que vous.
|
||||
Reference in New Issue
Block a user