# DESIGN.md — typst-leaf UI ## Vision **"A fresh sheet of paper on a warm desk."** Refined editorial-paper aesthetic with a deep teal accent and warm cream neutrals. The app chrome (sidebar, topbar, statusbar) is a warm cream; editor and preview surfaces are a brighter near-white — so reading and writing happen on a sheet of paper that lifts off the desk. ## Brand - **Name:** typst-leaf — warm, organic, paper-and-ink. - **Mark:** A teal `Leaf` icon (lucide) beside the wordmark. - **Personality:** Quiet, considered, a serious editor for prose, papers, and beautiful documents. Like a focused notebook, not a dashboard. ## Palette (Tailwind v4 `@theme`) Custom tokens in `src/index.css`: | Token | Value | Use | |---|---|---| | `canvas` | `#faf8f4` | App chrome (sidebar, topbar, statusbar, app bg) | | `surface` | `#fdfdfb` | Editor, preview, raised panels, inputs | | `surface-hover` | `#f3f1ec` | Hover backgrounds | | `ink` | `#1c1917` | Primary body text | | `ink-muted` | `#78716c` | Secondary text, meta | | `ink-subtle` | `#a8a29e` | Placeholders, subtle meta | | `line` | `#e7e5e4` | Hairline borders, dividers | | `line-strong` | `#d6d3d1` | Input borders | | Token | Value | Use | |---|---|---| | `teal-50` | `#f0f9f8` | Active row tints, soft accents | | `teal-100` | `#d5edea` | Focus ring, highlights | | `teal-500` | `#14b8a6` | Status dots, focus border | | `teal-600` | `#0f766e` | Primary actions, active text | | `teal-700` | `#115e59` | Primary hover | Functional: `amber-*` (warnings, dirty, behind), `rose-*` (errors, destructive). Monaco defaults (`zinc-*` border, body text) are left as-is. No dark classes. Tailwind v4 CSS-first only. ## Typography - **UI:** `font-sans` → Inter Variable (via `@fontsource-variable/inter`). - **Mono:** `font-mono` → JetBrains Mono Variable (via `@fontsource-variable/jetbrains-mono`). - **Monaco editor** also uses JetBrains Mono for consistency. - Brand wordmark: `font-semibold tracking-tight`. - Section headers: `text-[11px] uppercase tracking-wider text-ink-subtle`. - File paths: `font-mono text-ink-muted`. - Meta: `text-xs text-ink-subtle`. ## Icons lucide-react, tree-shakeable. Wrapped via `Icon` component with `size-4 stroke-[1.5] text-current`. Curated set: `Leaf`, `Plus`, `FolderPlus`, `Pencil`, `Trash2`, `ChevronDown`, `ChevronRight`, `X`, `Settings`, `RotateCw`, `GitBranch`, `ArrowUp`, `ArrowDown`, `Files`, `GitGraph`. ## Layout Skeleton ``` ┌──────────────────────────────────────────────────────────────────────┐ │ TopBar: # typst-leaf · project · main.typ Save LSP PRV @ │ ├──────────┬───────────────────────────────────────────────────────────┤ │ Sidebar │ │ │ Files │ │ │ ─────── │ Monaco Editor │ │ ▣ main │ (typst-leaf-light theme) │ │ ▣ lib/ │ │ │ Git │ │ │ Settings├─────────────────────────────────────┬─────────────────────┤ │ │ Editor (resizable) │ Preview │ │ │ │ (iframe) │ │ │ │ │ └──────────┴─────────────────────────────────────┴─────────────────────┘ │ StatusBar: main · clean · LSP · Preview · vim · saving… │ └──────────────────────────────────────────────────────────────────────┘ ``` ## Component Specs ### TopBar - `h-12`, `bg-canvas`, `border-b border-line`. - Left: `Leaf` icon (teal-600, size-5), "typst-leaf" (semibold, tracking-tight), middot divider, project name, `/` divider, file path (`font-mono text-ink-subtle`). - Right: LSP/Preview Chip (hidden when no file), `Button primary` Save, `IconButton` Settings. - When no project: text-centered "Select a project to begin". ### Sidebar - `w-72`, `bg-canvas`, `border-r border-line`. - ProjectPicker at top with `border-b border-line`. - Three icon+label tabs (Files, Git, Settings): active = teal text + 2px teal bottom border on surface; inactive = ink-muted. - Section headers: `uppercase tracking-wider text-ink-subtle text-[11px]`. ### StatusBar - `h-7`, `bg-canvas`, `border-t border-line`. - `GitBranch` icon + branch name, clean/dirty, ahead/behind with arrows. - LSP/Preview Chip. - Vim indicator and saving indicator. ### ResizableSplit - `flex h-full min-h-0 w-full flex-1`. - Divider: `w-1 bg-line hover:bg-teal-400`, `cursor-col-resize`, `transition-colors`. - Panels: `min-w-[280px] overflow-hidden`. ### EmptyState - Centered with muted `Leaf` icon, message, and optional hint. - `text-ink-subtle`. ### ToastHost - Fixed bottom-right, `rounded-lg shadow-sm`. - `StatusDot` + message + lucide `X` close. - Kinds: teal (success), rose (error), neutral (info). ### Preview - `bg-surface`, toolbar with "Preview" label, status Chip, `RotateCw` reload button. - Content: full-height iframe or centered placeholder text. ### Editor - `h-full flex flex-col min-h-0`. Toolbar: mono file path, Vim toggle, vim status. - Monaco with custom `typst-leaf-light` theme (warm near-white background, restrained rainbow-free syntax palette). ### FileTree - Nested tree with `hover:bg-surface-hover` rows, active file `bg-teal-50 text-teal-700`. - Inline rename/create inputs with `border-teal-400`. - Hover actions with lucide icons (Plus, FolderPlus, Pencil, Trash2). - Dirty files marked with amber dot. ### GitPanel - Section header with branch name, ahead/behind arrows. - Changed files with lucide status icons (Plus/Pencil/X/HelpCircle). - Button primary Commit, Button secondary Push/Pull with ArrowUp/ArrowDown icons. - Collapsible Log with chevron. ### SettingsPanel - "Git Identity" section. - TextInputs for name/email, Button primary Save, Button secondary Clear. ## States - **No project:** large empty state in main area; sidebar shows project list. - **Connecting:** amber pulse dot on LSP/Preview chips. - **Error:** rose-600 text in error banner and toasts. - **Save error:** rose toast + dirty marker on file name. - **Git dirty:** amber dot on file in tree. ## Motion - Hover/focus: `transition-colors duration-150`. - Button press: `active:scale-[0.98]` on primary buttons. - Toast: none (instant show/hide). - Connecting dots: `animate-pulse`. ## Accessibility - Visible focus rings: `focus-visible:ring-2 focus-visible:ring-teal-100 focus-visible:ring-offset-2`. - All interactive controls keyboard-reachable. - State communicated by text + color, never color alone. ## Don'ts - No gradients on chrome. - No shadows on panels (only on toasts). - No animated chrome unless real state change. - No emoji in product UI — icons only from lucide. - No dark mode.