Palette overhaul: - Warm cream canvas (#faf8f4) + near-white surfaces (#fdfdfb) + deep teal accent (#0f766e) - Unified on stone-warm neutrals via @theme block in index.css Typography: - Inter Variable + JetBrains Mono Variable via fontsource (self-hosted) - Monaco editor set to JetBrains Mono for consistency Icons: - lucide-react replaces all 8 hand-rolled SVGs - Leaf brand mark beside wordmark Shared primitives (src/components/ui/): - Icon, Button (4 variants, 2 sizes), IconButton, TextInput, SectionHeader, StatusDot, Chip Custom Monaco theme (src/theme/monaco-theme.ts): - typst-leaf-light: warm near-white background, restrained rainbow-free syntax - Keywords teal, strings warm green, comments stone italic, most tokens ink Component reworks: - TopBar: Leaf icon, h-12, chip-based status, Button/IconButton primitives - Sidebar: w-72, icon+label tabs with teal bottom border - StatusBar: lucide GitBranch/ArrowUp/ArrowDown, chip-based status - FileTree: lucide Plus/FolderPlus/Pencil/Trash2, teal active state - GitPanel: lucide status icons, restored staged/unstaged bg tint - Preview: RotateCw reload icon, chip status - EmptyState: muted Leaf icon - ToastHost: StatusDot + lucide X Fixes: - GitPanel staged/unstaged/untracked rows now have distinct bg tints - Button defaults to type="button" to prevent accidental form submission - Editor error fallback from red-400 to rose-600 - DESIGN.md: removed emoji from layout skeleton, fixed Modals/Monaco typo Build: pnpm -r typecheck + pnpm build pass.
7.5 KiB
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
Leaficon (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:
Leaficon (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 primarySave,IconButtonSettings. - 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.GitBranchicon + 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
Leaficon, message, and optional hint. text-ink-subtle.
ToastHost
- Fixed bottom-right,
rounded-lg shadow-sm. StatusDot+ message + lucideXclose.- Kinds: teal (success), rose (error), neutral (info).
Preview
bg-surface, toolbar with "Preview" label, status Chip,RotateCwreload 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-lighttheme (warm near-white background, restrained rainbow-free syntax palette).
FileTree
- Nested tree with
hover:bg-surface-hoverrows, active filebg-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.