snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,329 @@
---
title: Osvědčené postupy
icon: star
---
Tento dokument popisuje osvědčené postupy, které byste měli dodržovat při práci na frontend.
## Správa stavu
React a Jotai zajišťují správu stavu v kódu.
### Použijte atomy Jotai k ukládání stavu
Je dobrým zvykem vytvořit tolik atomů, kolik potřebujete ke správě stavu.
<Warning>
Je lepší použít více atomů než se snažit být příliš stručný s prop drilling.
</Warning>
```tsx
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
export const myAtomState = createAtomState<string>({
key: 'myAtomState',
defaultValue: 'default value',
});
export const MyComponent = () => {
const [myAtom, setMyAtom] = useAtomState(myAtomState);
return (
<div>
<input
value={myAtom}
onChange={(e) => setMyAtom(e.target.value)}
/>
</div>
);
}
```
### Nepoužívejte `useRef` k ukládání stavu
Vyhněte se používání `useRef` k ukládání stavu.
Pokud chcete ukládat stav, měli byste použít `useState` nebo atomy Jotai s `useAtomState`.
Podívejte se, jak spravovat překreslení, pokud máte pocit, že potřebujete `useRef`, abyste zabránili některým překreslením.
## Správa překreslení
Překreslení může být obtížné spravovat v Reactu.
Zde jsou některá pravidla, která je třeba dodržovat, abyste se vyhnuli zbytečnému překreslování.
Pamatujte, že můžete **vždy** zabránit opakovanému renderování pochopením jejich příčiny.
### Pracujte na úrovni kořene
Vyhýbání se překreslení v nových funkcích je nyní snadné tím, že je eliminujete na úrovni kořene.
Komponenta "PageChangeEffect" obsahuje pouze jeden "useEffect", který drží veškerou logiku pro provedení změny stránky.
Tímto způsobem víte, že existuje pouze jedno místo, které může spustit překreslování.
### Vždy si dvakrát rozmyslete před přidáním `useEffect` do vaší kódové databáze
Opakované renderování jsou často způsobeny zbytečným `useEffect`.
Měli byste si myslet, zda potřebujete `useEffect`, nebo zda můžete přesunout logiku ve funkci obsluhy událostí.
Pro vás je obecně snadné přesunout logiku do funkce `handleClick` nebo `handleChange`.
Můžete je také najít v knihovnách jako Apollo: `onCompleted`, `onError` atd.
### Použij sourozeneckou komponentu k extrakci `useEffect` nebo logiky načítání dat
Pokud máte pocit, že potřebujete přidat `useEffect` do základní komponenty, měli byste zvážit její extrakci v postranním vozíku.
Stejný postup můžete aplikovat na logiku získávání dat pomocí Apollo hooks.
```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] = useAtomState(dataState);
const [someDependency] = useAtomState(someDependencyState);
useEffect(() => {
if(someDependency !== data) {
setData(someDependency);
}
}, [someDependency]);
return <div>{data}</div>;
};
export const App = () => (
<PageComponent />
);
```
```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] = useAtomState(dataState);
return <div>{data}</div>;
};
export const PageData = () => {
const [data, setData] = useAtomState(dataState);
const [someDependency] = useAtomState(someDependencyState);
useEffect(() => {
if(someDependency !== data) {
setData(someDependency);
}
}, [someDependency]);
return <></>;
};
export const App = () => (
<>
<PageData />
<PageComponent />
</>
);
```
### Použijte rodiny atomů a selektory
Rodiny atomů a selektory jsou skvělým způsobem, jak se vyhnout překreslování.
Jsou užitečné, když potřebujete uložit seznam položek.
### Neměli byste používat `React.memo(MyComponent)`
Vyhněte se používání `React.memo()`, protože to neřeší příčinu překreslování, ale spíše přeruší řetězec překreslování, což může vést k neočekávanému chování a ztěžuje refaktorování kódu.
### Omezit použití `useCallback` nebo `useMemo`
Často nejsou nutné a kód ztěžují na čtení a údržbu pro nepodstatné zlepšení výkonu.
## Console.logs
Příkazy `console.log` jsou hodnotné při vývoji, protože poskytují pohled na hodnoty proměnných a průběh kódu v reálném čase. Ale, zanechání v produkčním kódu může vést k několika problémům:
1. **Výkon**: Přílišné logování může ovlivnit výkon za běhu, zejména u aplikací na straně klienta.
2. **Bezpečnost**: Logování citlivých dat může vystavit kritické informace komukoliv, kdo nahlédne do konzole prohlížeče.
3. **Čistota**: Naplnění konzole logy může zatížit důležitá varování nebo chyby, které je třeba vidět.
4. **Profesionalita**: Koneční uživatelé nebo klienti kontrolující konzolu a vidící množství logovacích příkazů mohou zpochybnit kvalitu a úroveň kódu.
Ujistěte se, že odstraníte všechny `console.logs`, než uvedete kód do produkce.
## Pojmenovávání
### Pojmenování proměnných
Jména proměnných by měla přesně zobrazovat účel nebo funkci proměnné.
#### Problém s generickými jmény
Generická jména v programování nejsou ideální, protože postrádají specifikaci, což vede k nejednoznačnosti a snižuje čitelnost kódu. Taková jména neposkytnou informace o účelu proměnné nebo funkce, čímž ztěžují vývojářům pochopení záměru kódu bez hlubšího zkoumání. To může vést ke zvýšené době ladění, vyšší náchylnosti k chybám a obtížím při údržbě a spolupráci. Mezitím, použití popisných jmen činí kód samozřejmým a snadněji navigovatelným, čímž se zvyšuje jeho kvalita a produktivita vývojáře.
```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('');
```
#### Některá slova, kterým se vyhnout v názvech proměnných
* dummy
### Obsluhovače událostí
Jména obsluhovačů událostí by měla začínat `handle`, zatímco `on` je prefix používaný k pojmenování událostí v komponentech props.
```tsx
// ❌ Bad
const onEmailChange = (val: string) => {
// ...
};
```
```tsx
// ✅ Good
const handleEmailChange = (val: string) => {
// ...
};
```
## Volitelné props
Vyhněte se tomu, abyste pro volitelný props předávali výchozí hodnotu.
**PŘÍKLAD**
Vezměte komponent `EmailField` definovanou níže:
```tsx
type EmailFieldProps = {
value: string;
disabled?: boolean;
};
const EmailField = ({ value, disabled = false }: EmailFieldProps) => (
<TextInput value={value} disabled={disabled} fullWidth />
);
```
**Použití**
```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" />;
```
## Komponenta jako props
Pokuste se co nejvíce předávat neinstancované komponenty jako props, aby si děti mohly samy rozhodnout, které props potřebují předat.
Nejčastější příklad je komponenta ikon:
```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>
)
};
```
Aby React pochopil, že komponenta je komponenta, musíte použít PascalCase, aby později ji bylo možné instancovat pomocí `<MyIcon>`
## Prop Drilling: Udržujte to minimální
Prop drilling, v kontextu React, odkazuje na praktiku předávání stavových proměnných a jejich setterů skrze mnoho vrstev komponent, i když mezilehlé komponenty je nepoužívají. Zatímco občas je to nutné, přehnané prop drilling může vést k:
1. **Snížená čitelnost**: Sledování původu nebo využití vlastnosti může být komplikované ve složitě vnořených strukturách komponent.
2. **Problémy s údržbou**: Změny v struktuře vlastností jedné komponenty mohou vyžadovat úpravy v některých komponentech, i když tyto vlastnosti přímo nepoužívají.
3. **Snížená znovupoužitelnost komponentů**: Komponent přijímající mnoho props pouze pro jejich předání, se stává méně univerzálním a obtížněji použitelným v různých kontextech.
Pokud máte pocit, že používáte přílišné prop drilling, podívejte se na osvědčené postupy správy stavu.
## Importy
Při importu, upřednostněte určené aliasy před upřesňováním úplných či relativních cest.
**Aliasy**
```js
{
alias: {
"~": path.resolve(__dirname, "src"),
"@": path.resolve(__dirname, "src/modules"),
"@testing": path.resolve(__dirname, "src/testing"),
},
}
```
**Použití**
```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';
```
## Validace schématu
[Zod](https://github.com/colinhacks/zod) je validátor schémat pro netypová data:
```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>;
```
## Zlomové změny
Vždy proveďte důkladné manuální testování, abyste zajistili, že úpravy nezpůsobily problémy jinde, zejména pokud testy zatím nebyly široce integrovány.

View File

@@ -0,0 +1,110 @@
---
title: Architektura složek
icon: folder-tree
info: Podrobný pohled na naši architekturu složek
---
V tomto průvodci prozkoumáte detaily struktury projektového adresáře a jak přispívá k organizaci a udržovatelnosti Twenty.
Následováním této konvence architektury složek je snazší najít soubory související s konkrétními funkcemi a zajistit rozšiřitelnost a udržovatelnost aplikace.
```
front
└───modules
│ └───module1
│ │ └───submodule1
│ └───module2
│ └───ui
│ │ └───display
│ │ └───inputs
│ │ │ └───buttons
│ │ └───...
└───pages
└───...
```
## Stránky
Zahrnuje komponenty nejvyšší úrovně definované aplikačními trasami. Importují více nízkoúrovňových komponent ze složky modulů (více podrobností níže).
## Moduly
Každý modul představuje funkci nebo skupinu funkcí s jejich specifickými komponenty, stavy a provozní logikou.
Všechny by měly dodržovat strukturu níže. Moduly můžete vnořovat do sebe (tzv. podmoduly) a platí pro ně stejná pravidla.
```
module1
└───components
│ └───component1
│ └───component2
└───constants
└───contexts
└───graphql
│ └───fragments
│ └───queries
│ └───mutations
└───hooks
│ └───internal
└───states
│ └───selectors
└───types
└───utils
```
### Kontexty
Kontext je způsob, jak předávat data skrz strom komponent, aniž by se musely na každé úrovni ručně předávat props.
Více podrobností naleznete v [React Context](https://react.dev/reference/react#context-hooks).
### GraphQL
Zahrnuje fragmenty, dotazy a mutace.
Více podrobností naleznete v [GraphQL](https://graphql.org/learn/).
* Fragmenty
Fragment je znovupoužitelný kus dotazu, který můžete použít na různých místech. Pomocí fragmentů je snazší vyhnout se duplikaci kódu.
Více podrobností naleznete v [GraphQL Fragments](https://graphql.org/learn/queries/#fragments).
* Dotazy
Více podrobností naleznete v [GraphQL Queries](https://graphql.org/learn/queries/).
* Mutace
Více podrobností naleznete v [GraphQL Mutations](https://graphql.org/learn/queries/#mutations).
### Hooky
Více podrobností naleznete v [Hooks](https://react.dev/learn/reusing-logic-with-custom-hooks).
### Stavy
Obsahuje logiku správy stavů. To řeší [Jotai](https://jotai.org).
* Selektory: Odvozené atomy (pomocí `createAtomSelector`) odvozují hodnoty z jiných atomů a jsou automaticky memoizovány.
Vestavěná správa stavů v Reactu stále spravuje stav uvnitř komponenty.
### Pomocné funkce
Měly by obsahovat pouze znovupoužitelné čisté funkce. V opačném případě vytvořte vlastní hooky ve složce `hooks`.
## UI
Obsahuje všechny znovupoužitelné komponenty UI použité v aplikaci.
Tato složka může obsahovat podsložky, jako jsou `data`, `display`, `feedback` a `input` pro specifické typy komponent. Každá komponenta by měla být samostatná a znovupoužitelná, takže ji můžete použít v různých částech aplikace.
Oddělením komponent UI od ostatních komponent ve složce `modules` je snazší udržovat konzistentní design a provádět změny v rozhraní, aniž by to ovlivnilo jiné části (obchodní logiku) kódové základny.
## Rozhraní a závislosti
Můžete importovat kód jiných modulů z jakéhokoliv modulu kromě složky `ui`. Díky tomu zůstane jeho kód snadno testovatelný.
### Interní
Každá část (hooky, stavy, ...) modulu může mít složku `internal`, která obsahuje části používané pouze v rámci modulu.

View File

@@ -0,0 +1,91 @@
---
title: Příkazy Frontend
icon: terminal
---
## Užitečné příkazy
### Spuštění aplikace
```bash
npx nx start twenty-front
```
### Regenerujte schéma GraphQL na základě API graphql schématu
```bash
npx nx run twenty-front:graphql:generate --configuration=metadata
```
NEBO
```bash
npx nx run twenty-front:graphql:generate
```
### Linter
```bash
npx nx run twenty-front:lint # pass --fix to fix lint errors
```
## Překlady
```bash
npx nx run twenty-front:lingui:extract
npx nx run twenty-front:lingui:compile
```
### Testovat
```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)
```
## Technologický stack
Projekt má čistý a jednoduchý stack s minimálním počtem šablonových kódů.
**Aplikace**
* [React](https://react.dev/)
* [Apollo](https://www.apollographql.com/docs/)
* [GraphQL Codegen](https://the-guild.dev/graphql/codegen)
* [Jotai](https://jotai.org/)
* [TypeScript](https://www.typescriptlang.org/)
**Testování**
* [Jest](https://jestjs.io/)
* [Storybook](https://storybook.js.org/)
**Nástroje**
* [Yarn](https://yarnpkg.com/)
* [Craco](https://craco.js.org/docs/)
* [Oxlint](https://oxc.rs/docs/guide/usage/linter.html)
## Architektura
### Směrování
[React Router](https://reactrouter.com/) zajišťuje směrování.
Aby se předešlo zbytečné [re-renders](/l/cs/developers/contribute/capabilities/frontend-development/best-practices-front#managing-re-renders) ) je všechna směrovací logika v `useEffect` v `PageChangeEffect`.
### Správa stavu
[Jotai](https://jotai.org/) zajišťuje správu stavu.
Podívejte se na [osvědčené postupy](/l/cs/developers/contribute/capabilities/frontend-development/best-practices-front#state-management) pro více informací o správě stavu.
## Testování
[Jest](https://jestjs.io/) slouží jako nástroj pro testování jednotek, zatímco [Storybook](https://storybook.js.org/) je pro testování komponent.
Jest je primárně určen pro testování pomocných funkcí, nikoli samotných komponent.
Storybook slouží k testování chování izolovaných komponent, stejně jako k zobrazování návrhového systému.

View File

@@ -0,0 +1,178 @@
---
title: Klávesové zkratky
---
## Úvod
Pokud potřebujete poslouchat klávesovou zkratku, obvykle použijete posluchač událostí `onKeyDown`.
Ve `twenty-front` však můžete mít konflikty mezi stejnými klávesovými zkratkami, které jsou použity v různých komponentách, nasazených současně.
Například, pokud máte stránku, která poslouchá klávesu Enter, a modal, který poslouchá klávesu Enter, s komponentou Select uvnitř tohoto modalu, která poslouchá klávesu Enter, můžete mít konflikt, když jsou všechny nasazeny současně.
## Funkce hook `useScopedHotkeys`
K řešení tohoto problému máme vlastní hook, který umožňuje poslouchat klávesové zkratky bez jakéhokoliv konfliktu.
Umístíte ho do komponenty a bude poslouchat klávesové zkratky pouze když je komponenta nasazena A když je aktivní specifikovaný **hotkey scope**.
## Jak v praxi poslouchat klávesové zkratky?
Jsou potřebné dva kroky k nastavení poslouchání klávesových zkratek :
1. Nastavte [hotkey scope](#what-is-a-hotkey-scope-), který bude poslouchat klávesové zkratky
2. Použijte hook `useScopedHotkeys` k poslouchání klávesových zkratek
Nastavení oblastí klávesových zkratek je potřebné i na jednoduchých stránkách, protože jiné UI prvky jako levé menu nebo příkazové menu mohou také poslouchat klávesové zkratky.
## Použití klávesových zkratek
Obecně budete mít dva případy použití, které vyžadují klávesové zkratky :
1. Na stránce nebo v komponentě nasazené na stránce
2. V komponentě typu modal, která přebírá fokus kvůli akci uživatele
Druhý případ použití se může stát rekurzivně: například rozbalovací seznam v modalu.
### Poslouchání klávesových zkratek na stránce
Příklad :
```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>;
};
```
### Poslouchání klávesových zkratek v komponentě typu modal
V tomto příkladu použijeme komponentu typu modal, která poslouchá klávesu Escape, aby svému nadřazenému komponentu řekla, že se má zavřít.
Zde interakce uživatele mění rozsah.
```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>;
};
```
Pak v komponentě modalu :
```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>;
};
```
Je důležité použít tento vzor, když si nejste jisti, že pouhé použití useEffect s připojením/odpojením bude stačit k tomu, aby se předešlo konfliktům.
Tyto konflikty mohou být těžko laditelné a může se to stát častěji než s useEffects.
## Co je to hotkey scope?
Rozsah klávesových zkratek je řetězec, který představuje kontext, ve kterém jsou klávesové zkratky aktivní. Obecně je kódován jako enum.
Když změníte rozsah klávesových zkratek, klávesové zkratky, které poslouchají tento rozsah, budou povolené a klávesové zkratky, které poslouchají jiné rozsahy, budou zakázané.
Můžete nastavit pouze jeden rozsah najednou.
Například rozsahy klávesových zkratek pro každou stránku jsou definovány v `PageHotkeyScope` enumu:
```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',
}
```
Interně je aktuálně vybraný rozsah uložen v Jotai atomu, který je sdílen napříč aplikací :
```tsx
export const currentHotkeyScopeState = createState<HotkeyScope>({
key: 'currentHotkeyScopeState',
defaultValue: INITIAL_HOTKEYS_SCOPE,
});
```
Ale tento atom by se nikdy neměl spravovat ručně ! Ukážeme si, jak jej používat v příští sekci.
## Jak to funguje interně?
Vytvořili jsme tenkou vrstvu nad [react-hotkeys-hook](https://react-hotkeys-hook.vercel.app/docs/intro), která je výkonnější a vyhýbá se zbytečným překreslením.
Také vytváříme Jotai atom, abychom mohli řídit stav rozsahu klávesových zkratek a učinit jej dostupným kdekoli v aplikaci.

View File

@@ -0,0 +1,8 @@
---
title: Storybook
description: Prozkoumejte knihovnu komponent UI na Twenty
---
Prohlédněte si naši kompletní knihovnu komponent a dokumentaci ve Storybooku.
[Otevřít Storybook →](https://storybook.twenty.com)

View File

@@ -0,0 +1,291 @@
---
title: Stylová příručka
icon: paintbrush
---
Tento dokument obsahuje pravidla pro psaní kódu.
Cílem zde je mít konzistentní kódovou základnu, která je snadno čitelná a snadno udržovatelná.
Pro toto je lepší být trochu více rozvláčný než být příliš stručný.
Vždy mějte na paměti, že lidé čtou kód častěji než ho píší, zejména u projektu s otevřeným zdrojovým kódem, kde může kdokoli přispět.
Existuje mnoho pravidel, která zde nejsou definována, ale která jsou automaticky kontrolována lintery.
## React
### Používejte funkcionální komponenty
Vždy používejte funkcionální komponenty TSX.
Nepoužívejte implicitní `import` s `const`, protože je obtížnější číst a importovat s automatickým dokončováním kódu.
```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>;
};
```
### Vlastnosti
Vytvořte typ rekvizit a pojmenujte jej `(ComponentName)Props`, pokud není potřeba jej exportovat.
Použijte destrukturalizaci rekvizit.
```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>;
```
#### Upusťte od používání `React.FC` nebo `React.FunctionComponent` k definování typů rekvizit
```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 />
);
```
#### Nepoužívejte rozbalení jediného objektu rekvizit v prvcích JSX
Vyhněte se používání rozbalení jediného objektu rekvizit v prvcích JSX, například `{...props}`. Tato praxe často vede k tomu, že kód je méně čitelný a obtížnější udržovat, protože není jasné, které rekvizity komponenta přijímá.
```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 }} />;
};
```
Odůvodnění:
* Na první pohled je jasné, které prop kód předává, čímž je snazší pochopit a udržovat.
* Pomáhá to předcházet těsnému provázání mezi komponentami prostřednictvím jejich rekvizit.
* Lintovací nástroje usnadňují identifikaci překlepů nebo nepoužívaných rekvizit, když rekvizity uvádíte explicitně.
## JavaScript
### Používejte operátor nullish-coalescing `??`
```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';
```
### Používejte volitelné zřetězení `?.`
```tsx
// ❌ Bad
onClick && onClick();
// ✅ Good
onClick?.();
```
## TypeScript
### Používejte `type` místo `interface`
Vždy používejte `type` místo `interface`, protože se téměř vždy překrývají a `type` je flexibilnější.
```tsx
// ❌ Bad
interface MyInterface {
name: string;
}
// ✅ Good
type MyType = {
name: string;
};
```
### Používejte textové literály místo výčtů
[Textové literály](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) jsou preferovaný způsob pro zpracování hodnot podobných výčtům v TypeScriptu. Snadněji se rozšiřují pomocí Pick a Omit a nabízejí lepší vývojářskou zkušenost, zejména s automatickým dokončováním kódu.
Proč TypeScript doporučuje vyhnout se výčtům zjistíte [zde](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 a interní knihovny
Měli byste používat výčty, které generuje kód generátor GraphQL.
Je také lepší používat výčet při používání interní knihovny, aby interní knihovna nemusela vystavovat textový typ neusouvisející s interním API.
Příklad:
```TSX
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
setHotkeyScopeAndMemorizePreviousScope(
RelationPickerHotkeyScope.RelationPicker,
);
```
## Styling
### Používejte StyledComponents
Stylujte komponenty pomocí [Linaria styled](https://github.com/callstack/linaria).
```tsx
// ❌ Bad
<div className="my-class">Hello World</div>
```
```tsx
// ✅ Good
const StyledTitle = styled.div`
color: red;
`;
```
Prefixujte stylizované komponenty "Styled", abyste je odlišili od "skutečných" komponent.
```tsx
// ❌ Bad
const Title = styled.div`
color: red;
`;
```
```tsx
// ✅ Good
const StyledTitle = styled.div`
color: red;
`;
```
### Theming
Využití tématu pro většinu stylování komponent je preferovaný přístup.
#### Jednotky měření
Vyhýbejte se používání hodnot `px` nebo `rem` přímo ve stylizovaných komponentách. Potřebné hodnoty jsou obvykle již definovány v tématu, takže se doporučuje využívat je pro tyto účely.
#### Barvy
Zdržte se zavádění nových barev; místo toho použijte existující paletu z tématu. Pokud by došlo k tomu, že paleta neodpovídá, prosím nechte komentář, aby to tým mohl napravit.
```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};
`;
```
## Prosazování Zákazu Importů Typů
Vyhýbejte se typovým importům. K prosazení tohoto standardu pravidlo Oxlint kontroluje a hlásí jakékoli typové importy. To pomáhá udržovat konzistenci a čitelnost v TypeScript kódu.
```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';
```
### Proč Zákaz Importů Typů
* **Konzistence**: Vyhýbáním se importům typů a použitím jednotného přístupu pro importy typů i hodnot zůstává kódová základna konzistentní ve svém stylu importů modulů.
* **Čitelnost**: Importy bez type zlepšují čitelnost kódu tím, že je jasné, zda importujete hodnoty nebo typy. Tím se snižuje dvojznačnost a usnadňuje pochopení účelu importovaných symbolů.
* **Udržovatelnost**: Zvyšuje udržovatelnost kódové základny, protože vývojáři mohou při revizi nebo úpravách kódu identifikovat a najít importy pouze typů.
### Pravidlo Oxlint
Pravidlo Oxlint, `typescript/consistent-type-imports`, prosazuje standard zákazu importů typů. Toto pravidlo generuje chyby nebo varování pro jakékoli porušení typového importu.
Upozorňujeme, že toto pravidlo konkrétně řeší vzácné okrajové případy, kdy dochází k neúmyslným typovým importům. TypeScript sám odrazuje tuto praxi, jak je uvedeno v [poznámkách k verzi TypeScript 3.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html). Ve většině případů byste neměli potřebovat používat pouze typové importy.
Aby váš kód splňoval toto pravidlo, spusťte Oxlint jako součást svého vývojového pracovního postupu.

View File

@@ -0,0 +1,61 @@
---
title: Práce s Figma
info: Zjistěte, jak můžete spolupracovat s Figmou Twenty
---
Figma je nástroj pro návrh uživatelského rozhraní, který pomáhá překlenout komunikační bariéru mezi návrháři a vývojáři.
Tento průvodce vysvětluje, jak můžete spolupracovat s Figma.
## Přístup
1. **Přístup ke sdílenému odkazu:** K Figma souboru projektu můžete přistoupit [zde](https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty).
2. **Přihlásit se:** Pokud ještě nejste přihlášeni, Figma vás k tomu vyzve.
Klíčové funkce jsou dostupné pouze přihlášeným uživatelům, jako je režim pro vývojáře a možnost výběru dedikovaného rámce.
<Warning>
Nebudete moci účinně spolupracovat bez účtu.
</Warning>
## Struktura Figma
Na levém postranním panelu můžete přistupovat k různým stránkám Figmy společnosti Twenty. Takto jsou organizovány:
* **Stránka komponentů:** Toto je první stránka. Návrhář ji používá k vytváření a organizování znovupoužitelných návrhových prvků použitých v celém návrhovém souboru. Například tlačítka, ikony, symboly nebo jakékoli jiné znovupoužitelné komponenty. Slouží k zajištění konzistence v celém návrhu.
* **Hlavní stránka:** Druhá stránka je hlavní stránka, která zobrazuje kompletní uživatelské rozhraní projektu. Můžete stisknout **"Přehrát"**, abyste použili kompletní prototyp aplikace.
* **Stránky funkcí:** Ostatní stránky jsou obvykle věnovány funkcím ve vývoji. Obsahují návrh specifických funkcí nebo modulů aplikace či webu. Typicky se stále vyvíjejí.
## Užitečné tipy
S přístupem pouze pro čtení nemůžete návrh upravovat, ale máte přístup ke všem funkcím užitečným pro přeměnu návrhu na kód.
### Použití režimu pro vývojáře
Dev Mode Figma zvyšuje produktivitu vývojářů díky snadné navigaci designem, efektivnímu spravování prvků, efektivním komunikačním nástrojům, integracím do nástrojů, rychlým částem kódu a klíčovým informacím o vrstvě, čímž překonává mezeru mezi návrhem a vývojem. O Dev Mode se můžete dozvědět více [zde](https://www.figma.com/dev-mode/).
Přepněte na režim „Vývojář“ v pravé části nástrojové lišty, kde si můžete prohlédnout specifikace návrhu, kopírovat CSS a přistupovat k prvkům.
### Použití prototypu
Klikněte na libovolný prvek na plátně a stiskněte tlačítko „Přehrát“ v pravém horním rohu rozhraní k zobrazení prototypu. Režim prototypu vám umožňuje interakci s návrhem, jakoby to byl finální produkt. Ukazuje tok mezi obrazovkami a jak se prvky uživatelského rozhraní jako tlačítka, odkazy nebo menu chovají při interakci.
1. **Pochopení přechodů a animací:** V prototypovém režimu můžete vidět libovolné přechody nebo animace, které návrhář přidal mezi obrazovky nebo prvky UI, což poskytuje jasné vizuální instrukce vývojářům o zamýšleném chování a stylu.
2. **Objasnění implementace:** Prototyp může také pomoci snížit nejasnosti. Vývojáři s ním mohou interagovat pro lepší pochopení funkčnosti či vzhledu konkrétních prvků.
Pro podrobnější detaily a pokyny k Figma platformě můžete navštívit oficiální [Figma Documentation](https://help.figma.com/hc/en-us).
### Měření vzdálenosti
Vyberte prvek, podržte klávesu `Option` (Mac) nebo `Alt` (Windows) a pak přejeďte kurzorem nad jiným prvkem, abyste viděli vzdálenost mezi nimi.
### Rozšíření Figma pro VSCode (doporučeno)
[Figma pro VS Code](https://marketplace.visualstudio.com/items?itemName=figma.figma-vscode-extension)
vám umožňuje procházet a zkoumat návrhové soubory, spolupracovat s návrháři, sledovat změny a zrychlit implementaci – vše bez opuštění vašeho textového editoru.
Je součástí našich doporučených rozšíření.
## Spolupráce
1. **Použití komentářů:** Jste vítáni použít funkci komentářů kliknutím na bublinu vlevo na nástrojové liště.
2. **Rozhovor prostřednictvím kurzoru:** Hezkou funkcí Figma je Rozhovor prostřednictvím kurzoru. Stačí stisknout `;` na Macu a `/` ve Windows a odeslat zprávu, pokud vidíte, že někdo jiný používá Figma současně s vámi.