diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..b55655d1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,156 @@ +# Vojo — Project Guide + +Matrix chat client (React 18 + TypeScript), forked from Cinny and rebranded as Vojo. + +## Quick Start + +```bash +npm start # dev server on :8080 +npm run build # production build → dist/ +npm run lint # eslint + prettier +npm run typecheck # tsc --noEmit +``` + +Build: **Vite 5.4** with vanilla-extract, WASM, PWA plugins. + +## Source Layout + +``` +src/ +├── index.tsx # Entry point +├── client/ +│ ├── initMatrix.ts # Matrix SDK init (createClient, startClient, logout) +│ └── secretStorageKeys.js # Crypto callbacks +├── types/matrix/ # Matrix protocol types (room.ts, accountData.ts, common.ts) +└── app/ + ├── i18n.ts # i18next config + ├── pages/ + │ └── App.tsx # Root component (providers, config loader) + ├── features/ # Feature modules + ├── components/ # Shared components + ├── hooks/ # ~117 custom hooks + ├── state/ # Jotai atoms + ├── plugins/ # Content plugins + ├── utils/ # Utilities + └── styles/ # Vanilla-extract global styles +``` + +## Pages & Routing (`src/app/pages/`) + +Router in `Router.tsx` — createBrowserRouter / createHashRouter. + +- **Auth**: `auth/login/`, `auth/register/`, `auth/reset-password/` +- **Client**: `client/` — main layout after login + - `home/` — Home timeline (path: `/home/`, root `/` redirects here) + - `direct/` — DMs (path: `/direct/`) + - `space/` — Space view (path: `/:spaceIdOrAlias/`) + - `explore/` — Public rooms (path: `/explore/`) + - `inbox/` — Notifications, invites (path: `/inbox/`) + - `create/` — New room/space (path: `/create/`) + - `sidebar/` — Tab components for sidebar nav + - `WelcomePage.tsx` — Empty state + - `SyncStatus.tsx`, `SpecVersions.tsx` — Connection status + +## Features (`src/app/features/`) + +| Dir | Purpose | +|-----|---------| +| `room/` | Core room view — **RoomTimeline.tsx** (63KB), **RoomInput.tsx** (24KB), **RoomViewHeader.tsx** (18KB), MembersDrawer, MessageEditor, RoomTombstone | +| `room-nav/` | Room list navigation items & categories | +| `room-settings/` | Room-specific settings page | +| `common-settings/` | Shared settings: general, members, permissions, emojis-stickers, developer-tools | +| `space-settings/` | Space-specific settings | +| `settings/` | User settings (general, account, notifications, devices, emojis, about, dev-tools) | +| `lobby/` | Space/room lobby view | +| `search/` | Global search | +| `message-search/` | In-room message search | +| `create-chat/` | DM creation flow | +| `create-room/` | Room creation | +| `create-space/` | Space creation | +| `add-existing/` | Join existing rooms | +| `join-before-navigate/` | Pre-join navigation logic | +| `call/` | Element Call integration | +| `call-status/` | Call state display | + +## Key Components (`src/app/components/`) + +- `message/` — Message rendering (layout variants: compact, bubble, modern) +- `editor/` — Slate-based rich text editor +- `emoji-board/` — Emoji picker +- `image-pack-view/` — Custom emoji pack management +- `image-viewer/`, `Pdf-viewer/` — Media viewers +- `sidebar/` — Sidebar navigation +- `user-profile/` — User info, power chips, moderation +- `member-tile/` — Member list items +- `power/` — Power level UI +- `upload-card/` — Upload progress cards +- `url-preview/` — Link previews +- `page/` — Page layout wrapper (Page, PageHeader, PageContent) +- `setting-tile/` — Settings list item pattern +- `sequence-card/`, `cutout-card/` — Card layouts +- `uia-stages/` — User-interactive auth stages (email, captcha, token) +- `room-intro/` — Room introduction card +- `invite-user-prompt/`, `join-address-prompt/`, `leave-room-prompt/` — Dialogs + +## State Management + +**Jotai** atoms in `src/app/state/`: +- `settings.ts` — User preferences (MessageLayout, DateFormat, etc.) +- `sessions.ts` — Active session +- `upload.ts` — Upload progress +- `room/` — roomInputDrafts, roomToParents, roomToUnread +- `room-list/` — roomList, inviteList, sorting/filtering + +Some atoms persist to localStorage (e.g. `settings.ts`, `navToActivePath.ts`), others are in-memory only (e.g. `upload.ts`, `roomInputDrafts.ts`). Access via hooks in `state/hooks/`. + +## Localisation (i18n) + +**Config**: `src/app/i18n.ts` — i18next + HTTP backend + language detector, `fallbackLng: 'ru'` + +**Locale files**: `public/locales/en.json`, `public/locales/ru.json` + +**Namespaces** (top-level keys in JSON): +`Organisms`, `Auth`, `Settings`, `Search`, `Home`, `Direct`, `Room`, `Inbox`, `Explore`, `Create`, `RoomSettings` + +**Pattern**: +```tsx +import { useTranslation } from 'react-i18next'; + +const { t } = useTranslation(); +return {t('RoomSettings.some_key')}; +``` + +**Conventions**: +- Each component gets its own `useTranslation()` call +- In custom hooks with `useMemo`, add `[t]` to dependency array +- `react-i18next` import goes after framework imports, before local imports +- For dynamic values: `t('key', { count: 5 })` +- For rare cases with HTML in translations: `dangerouslySetInnerHTML` (used sparingly, e.g. in RoomAddress.tsx) + +## Key Libraries + +- **React 18.2** + React Router DOM 6 +- **matrix-js-sdk 38.2** — Matrix protocol +- **folds 2.6** — UI component library +- **jotai 2.6** — State management +- **vanilla-extract** — Type-safe CSS +- **slate 0.123** — Rich text editor +- **@tanstack/react-query 5** — Data fetching +- **@tanstack/react-virtual 3** — Virtual scrolling +- **i18next 23 + react-i18next 15** — Localisation + +## Matrix SDK Patterns + +```tsx +const mx = useMatrixClient(); // Get SDK instance +const room = useRoom(); // Current room +const stateEvent = useStateEvent(room, StateEvent.Type); // Room state +const powerLevels = usePowerLevels(room); // Permissions +``` + +## Git + +- Main branch: `dev` +- Current work branch: `vojo/dev` +- Semantic-release on `dev` branch +- CI: GitHub Actions (build, deploy, docker, netlify)