From ae0d888ddf97d3e5a1d3f932c6676d660d05a6c7 Mon Sep 17 00:00:00 2001 From: Navraj Sikand Date: Fri, 3 Jul 2026 13:34:47 +0530 Subject: [PATCH] =?UTF-8?q?feat:=20complete=20UI=20redesign=20=E2=80=94=20?= =?UTF-8?q?editorial-paper=20palette,=20Monaco=20theme,=20lucide=20icons,?= =?UTF-8?q?=20primitives?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- DESIGN.md | 229 +++++++++--------- PLAN.md | 200 --------------- pnpm-lock.yaml | 28 +++ typst-leaf-frontend/index.html | 2 + typst-leaf-frontend/package.json | 7 +- typst-leaf-frontend/src/App.tsx | 68 +++--- typst-leaf-frontend/src/components/Editor.tsx | 22 +- .../src/components/EmptyState.tsx | 8 +- .../src/components/FileTree.tsx | 57 ++--- .../src/components/GitPanel.tsx | 124 +++++----- .../src/components/PanelSection.tsx | 4 +- .../src/components/Preview.tsx | 48 ++-- .../src/components/ProjectPicker.tsx | 25 +- .../src/components/ResizableSplit.tsx | 2 +- .../src/components/SettingsPanel.tsx | 31 +-- .../src/components/StatusBar.tsx | 48 ++-- .../src/components/ToastHost.tsx | 30 +-- typst-leaf-frontend/src/components/TopBar.tsx | 88 +++---- .../src/components/ui/Button.tsx | 35 +++ .../src/components/ui/Chip.tsx | 26 ++ .../src/components/ui/Icon.tsx | 9 + .../src/components/ui/IconButton.tsx | 20 ++ .../src/components/ui/SectionHeader.tsx | 13 + .../src/components/ui/StatusDot.tsx | 19 ++ .../src/components/ui/TextInput.tsx | 12 + typst-leaf-frontend/src/index.css | 27 +++ typst-leaf-frontend/src/main.tsx | 2 + typst-leaf-frontend/src/theme/monaco-theme.ts | 54 +++++ 28 files changed, 616 insertions(+), 622 deletions(-) delete mode 100644 PLAN.md create mode 100644 typst-leaf-frontend/src/components/ui/Button.tsx create mode 100644 typst-leaf-frontend/src/components/ui/Chip.tsx create mode 100644 typst-leaf-frontend/src/components/ui/Icon.tsx create mode 100644 typst-leaf-frontend/src/components/ui/IconButton.tsx create mode 100644 typst-leaf-frontend/src/components/ui/SectionHeader.tsx create mode 100644 typst-leaf-frontend/src/components/ui/StatusDot.tsx create mode 100644 typst-leaf-frontend/src/components/ui/TextInput.tsx create mode 100644 typst-leaf-frontend/src/theme/monaco-theme.ts diff --git a/DESIGN.md b/DESIGN.md index d2c2a34..330cd0f 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,171 +1,160 @@ -# DESIGN.md — typst-leaf UI Rehaul +# DESIGN.md — typst-leaf UI -This document is the aesthetic reference for the next chunk in `PLAN.md`. Every UI decision in `PLAN.md` should match this guide. Direction is "document editor" — warmth, restraint, a thin layer of leaf. +## 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. -- Personality: quiet, considered, a serious editor for prose, papers, and beautiful documents. -- Not "developer marketing." Not "dashboard SaaS." Closer to a focused notebook. +- **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. -## Aesthetic Pillars +## Palette (Tailwind v4 `@theme`) -1. **Paper, not glass.** - Surfaces are warm off-white, not slate. Borders separate panels; we don't blur or float. -2. **Functional color, decorative restraint.** - Greens only when communicating success/active/leaf. Use amber for warnings, slate for muted text, rose for errors. No gradients on chrome. -3. **Typography is the interface.** - System sans for chrome, monospace for paths/git/lsp status. We say things in words, not icons. -4. **A whisper, not a shout.** - Rounded corners are subtle (`rounded-md`). Focus rings are visible but quiet. +Custom tokens in `src/index.css`: -## Palette (Tailwind v4 via CSS-first) - -| Token | Use | Tailwind class | +| Token | Value | Use | |---|---|---| -| Page background | Shell chrome | `bg-stone-50` | -| Panel surface | Cards, panels | `bg-white` | -| Sidebar | Activity + sections | `bg-stone-50` with inner panels `bg-white` | -| Text primary | Body | `text-zinc-800` | -| Text muted | Meta | `text-zinc-500` | -| Text subtle | File paths | `text-zinc-400` | -| Divider | 1px borders | `border-zinc-200` | -| Hover surface | Buttons/list rows | `hover:bg-stone-100` | -| Accent (primary) | Save, commit | `bg-emerald-600 hover:bg-emerald-700 text-white` | -| Accent (soft) | Active file, focus | `bg-emerald-50 text-emerald-800 ring-emerald-200` | -| Warning | Behind | `text-amber-600` | -| Error | Dirty error | `text-rose-600` | -| Pill bg (status) | Status chips | `bg-white border-zinc-200` | +| `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 | -We do not introduce dark classes. Tailwind v4 is in CSS-first mode (`@import "tailwindcss"`); tokens live in plain CSS, not `tailwind.config.js`. +| 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` (system stack already from Tailwind). -- Monospace: `font-mono` for paths, git refs, LSP logs, status messages. -- Toolbar/header: `text-sm font-medium tracking-tight`. -- Meta and toasts: `text-xs text-zinc-500`. -- File names: `text-sm font-mono`. +- **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: leaf · [project ▾] · main.typ · Save · ●LSP ◌PRV │ +│ TopBar: # typst-leaf · project · main.typ Save LSP PRV @ │ ├──────────┬───────────────────────────────────────────────────────────┤ │ Sidebar │ │ │ Files │ │ -│ ▣ main │ Monaco Editor │ +│ ─────── │ Monaco Editor │ +│ ▣ main │ (typst-leaf-light theme) │ │ ▣ lib/ │ │ │ Git │ │ -│ ⚙ set │ │ -│ ├─────────────────────────────────────┬─────────────────────┤ +│ Settings├─────────────────────────────────────┬─────────────────────┤ │ │ Editor (resizable) │ Preview │ │ │ │ (iframe) │ │ │ │ │ └──────────┴─────────────────────────────────────┴─────────────────────┘ -│ StatusBar: main · clean · ready · vim:n · 1:23 │ +│ StatusBar: main · clean · LSP · Preview · vim · saving… │ └──────────────────────────────────────────────────────────────────────┘ ``` -## Component Specs (Tailwind) +## Component Specs ### TopBar -```tsx -
- typst-leaf - · - - main.typ - - LSP · ready - PRV · starting - - - -
-``` +- `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 (`PanelSection` + tabs) -```tsx - -``` +### 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 -```tsx -
-
/* editor */
- -``` +- `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 -```tsx -
-
Open a file from the sidebar.
-
Tip: ⌘P to jump, ⌘S to save.
-
-``` +- Centered with muted `Leaf` icon, message, and optional hint. +- `text-ink-subtle`. -### Toast -```tsx -
-
- - Committed a1b2c3d -
-
-``` +### ToastHost +- Fixed bottom-right, `rounded-lg shadow-sm`. +- `StatusDot` + message + lucide `X` close. +- Kinds: teal (success), rose (error), neutral (info). -### Status chips -```tsx - - - LSP · ready - -``` +### 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 "No project yet." -- **Connecting:** preview shows "starting…" with a quiet spinner (CSS, not library). -- **External preview source:** toast "Source outside project — ignored." -- **Save error:** rose-600 message in toast + small dot in TopBar file path. -- **Git dirty:** emerald-50 row tint + small dot next to filename in tree. +- **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: `transition-colors duration-100`. -- Splitter drag: no transition. -- Toast in/out: 150ms opacity, no spring. +- 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-emerald-300 focus-visible:ring-offset-1`. -- All interactive controls reachable by keyboard. -- Status communicated by text + color, never color alone. +- 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 whitespace panels. -- No animated chrome unless it's a real state change. -- No emoji decorations in product UI (only as icons in narrow toolbars). - -## Thumbnail: vibe check - -> Imagine a warm, slightly off-white IDE with a single green accent for "commit ready" and a quiet three-dot status footer. It's the IDE equivalent of a blank page of cream paper, not a glass dashboard. +- 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. diff --git a/PLAN.md b/PLAN.md deleted file mode 100644 index e959392..0000000 --- a/PLAN.md +++ /dev/null @@ -1,200 +0,0 @@ -# Next Chunk: IDE Shell, File Management, UI Rehaul, Reliability, Git Workflow - -This chunk is the next deliverable on top of the `bfb4d8b` commit. It picks **options 1, 2, and 3**: IDE shell + file management + UI rehaul, reliability and LSP/Preview hardening, and Git workflow upgrade. Direction and aesthetic decisions live in `DESIGN.md` — every UI decision below should read against that doc. - -## Guiding Constraints - -- Tailwind only, light theme only, no dark variant. -- Browser-first; Tauri APIs only behind `window.__TAURI__` guards. -- No databases; filesystem + `.git` remain the source of truth. -- No polling for file or preview changes. -- Backend stays a thin proxy. No Typst or LSP reimplementation in TypeScript. -- `tinymist` remains the LSP/preview source of truth. -- Keep the raw JSON-RPC LSP client. Do not reintroduce `monaco-languageclient`. -- Strict TypeScript with zod at API boundaries. - -## Aesthetic Direction (see DESIGN.md) - -- Document-editor tone: warm paper background, subtle emerald accents, no marketing gradients. -- Dense-but-readable developer layout. System sans for chrome, monospace for paths/git. -- Rounded corners and borders restrained to "panel" and "card"; default to `rounded-md`. -- Status indicators must read clearly (label + color, never color alone). -- Splitter, focus rings, etc. all designed in DESIGN.md; the implementation must match. - -## Phase 1 — Path Utilities and Jump Reliability - -Move path/jump helpers into a single module so all callers use the same normalization rules. - -**New file** -- `typst-leaf-frontend/src/path-utils.ts`: - - `normalizeFsPath(input: string): string` - - `encodeVirtualPathForFileUri(path: string): string` - - `relativePathFromProject(projectUri: string, filepath: string): string | null` - -**State changes** (`app-state.tsx`) -- `jumpTarget: { id: number; file: string; start?: [number,number]; end?: [number,number] } | null` -- `setJumpTarget` action carries an `id`; reducer increments counter and stamps. -- New `pushNotice` action for transient messages ("Preview source outside project"). - -**LSP hardening** (`lsp.ts`) -- Validate `tinymist/preview/scrollSource` payload strictly: `filepath` string, optional numeric `start/end`. -- Forward only well-formed paths to `onJumpToSource`. - -**Editor** (`Editor.tsx`) -- Use shared path utility. -- Compare URIs via `monaco.Uri.equals` after parsing both sides. -- Dedupe by `jump.id`, not object identity. -- Keep the existing `ResizeObserver` and `editor.layout()` call before reveal. - -**Verification** -- External preview path ignored with non-blocking message. -- Numeric start/end coercion. -- Rapid clicks keep latest, no swallowed targets. - -## Phase 2 — UI Foundation (Rehaul) - -Replace the current sparse shell with the layered "IDE" layout in DESIGN.md. - -**Files** -- `typst-leaf-frontend/src/App.tsx` (restructure) -- `typst-leaf-frontend/src/index.css` (extend `tailwindcss` import; nothing else without need) -- New components: - - `TopBar.tsx` - - `StatusBar.tsx` - - `Sidebar.tsx` - - `PanelSection.tsx` - - `ActivityBar.tsx` - - `ResizableSplit.tsx` - - `ToastHost.tsx` - - `EmptyState.tsx` - -**Layout** -- Top bar: project switcher, current file/dirty indicator, save, LSP/preview/git chips, settings. -- Sidebar tabs: Files / Git / Settings. -- Main: resizable editor / preview split. -- Status bar: branch, clean/dirty, LSP, preview, vim state, cursor (optional). - -**Aesthetic tokens** (mirror DESIGN.md) -- `bg-stone-50` for chrome, `bg-white` for editor surface, `bg-emerald-600` for primary actions, `border-zinc-200` for panel dividers, `text-zinc-500` for muted metadata. -- Tailwind reference snippets are kept in DESIGN.md. - -**QOL** -- Toasts for save/commit/push/pull, configured via `pushNotice`. -- Clear empty states ("Select a project", "Open a file", "No changes to commit"). -- Keyboard shortcuts surfaced in `StatusBar` hints later if time. - -## Phase 3 — Resizable Workspace and Preview UX - -- Build `ResizableSplit.tsx` (pointer-driven, double-click reset, persisted ratio). -- Persist `typst-leaf.split` in `localStorage`. -- Add `PreviewToolbar` on top of iframe: status chip, reload button, "Click to jump" hint. -- During drag and on drag-end, call `editor.layout()` so Monaco keeps accurate viewports. - -## Phase 4 — File Management - -Make projects usable from the UI. - -### Backend -`typst-leaf-backend/src/routes/files.ts`: -- `POST /api/projects/:project/file` -- `DELETE /api/projects/:project/file?path=…` -- `PATCH /api/projects/:project/file` -- `POST /api/projects/:project/folder` - -All paths through `resolveFile`/`relPathSchema`. zod validation stays. - -### Frontend -`api.ts`: -- `createFile`, `deleteFile`, `renameFile`, `createFolder`. - -`types.ts`: -- Add request types. - -`FileTree.tsx`: -- Group tree view; folders from existing file paths. -- Inline create/rename/delete actions; confirm destructive deletes. -- After mutation: refresh tree, dispatch `bumpGitVersion`, open new file or close deleted open file (with model disposal). - -`app-state.tsx`: -- Action `setTree` already exists. Add `bumpFileTree` counter or reuse `setProjects` invalidation by re-fetching tree on a `treeVersion`. - -## Phase 5 — SyncTeX/LSP Reliability Hardening - -(See Phase 1.) This phase covers the user-visible behavior of the jump path: - -- Stable IDs prevent dropped or duplicated jumps. -- External path is announced via toast instead of silently dropping. -- Vue of preview-after-resize: drag resize triggers `editor.layout()`. Preview iframe reload button re-syncs. -- A small dev-only "Diagnostics" panel hidden behind `?debug=1` later is optional. - -## Phase 6 — Git Workflow Upgrade - -Backend -- `GET /api/projects/:project/git/diff` returning unified diffs (later; not blocking if skipped). -- Optional `POST /api/projects/:project/git/stage` for partial staging (later). - -Frontend -- `GitPanel.tsx` becomes a workflow panel: - - Branch + ahead/behind + clean state - - Changed files list grouped by staged/unstaged/untracked (icons per status) - - Commit composer - - Push/Pull controls - - Remote inline input - - Recent commits list (keep existing) -- `FileTree.tsx` shows dirty file badges. -- Toasts on success/failure: "Committed abc1234", "Pushed to origin/main", etc. -- Disable commit when clean; message should explain why. - -`types.ts`: -- Confirm `FileStatusInfo` carries `A|M|D|?` (already does). - -## Phase 7 — State and UX Infrastructure - -Keep state in `app-state.tsx` (no Zustand yet). Add UI actions: -- `setActivePanel` (files | git | settings) -- `setFileDirty` -- `setSaving` -- `pushNotice` / `dismissNotice` -- `setSplitRatio` (effect persists via localStorage directly; not strict state) - -Toast component lives once at `App.tsx`, reads notices via context. - -## Phase 8 — Doc and Metadata Cleanup - -- `README.md`: port 1420, raw LSP client, preview-via-LSP-and-proxy model. -- `VISION.md`: note raw LSP client; soften `monaco-languageclient` claim. -- `typst-leaf-frontend/README.md`: replace Tauri-template text. -- `PLAN.md`: replace with this plan at commit time. Keep `DESIGN.md` separate and referenced. - -## Implementation Order - -1. Shared path utilities + jump IDs. -2. SyncTeX hardening (rely on shared utils, not yet aesthetic). -3. UI shell rehaul (TopBar, Sidebar, ResizableSplit, StatusBar, ToastHost). -4. File CRUD backend + frontend integration, FileTree rebuild. -5. Git workflow UI rebuild + badges in tree. -6. Preview toolbar and reload. -7. Doc cleanup. -8. Verification: - - `pnpm -r typecheck` - - `pnpm --filter typst-leaf-frontend build` - - Manual checks: file CRUD, resize-during-jump, Git flow, external preview path ignored. - -## Risks - -- File URI/path encoding is still the highest-risk area; reuse existing helpers in `Editor.tsx`. -- Rename/delete of currently open file must dispose Monaco model. -- Git status can stale if a file mutation does not bump `gitVersion`. -- Resizable panes must call `layout()` during and after drag. -- Preview iframe behavior is owned by typst-preview; do not over-customize it. - -## Scope Boundary - -In: -- IDE shell rehaul, resizable split, file CRUD, Git workflow UI upgrade, SyncTeX reliability, toasts, status bar. - -Out: -- Per-file staging workflow. -- Rich diff viewer. -- Drag/drop reordering, multi-tab editor, collaborative cursors. -- Tauri native file picker. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 88f32ae..5ea754e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,6 +48,12 @@ importers: typst-leaf-frontend: dependencies: + '@fontsource-variable/inter': + specifier: ^5.2.8 + version: 5.2.8 + '@fontsource-variable/jetbrains-mono': + specifier: ^5.2.8 + version: 5.2.8 '@monaco-editor/react': specifier: ^4.7.0 version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -57,6 +63,9 @@ importers: '@tauri-apps/plugin-opener': specifier: ^2 version: 2.5.4 + lucide-react: + specifier: ^1.23.0 + version: 1.23.0(react@19.2.7) monaco-editor: specifier: ^0.55.1 version: 0.55.1 @@ -339,6 +348,12 @@ packages: cpu: [x64] os: [win32] + '@fontsource-variable/inter@5.2.8': + resolution: {integrity: sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==} + + '@fontsource-variable/jetbrains-mono@5.2.8': + resolution: {integrity: sha512-WBA9elru6Jdp5df2mES55wuOO0WIrn3kpXnI4+W2ek5u3ZgLS9XS4gmIlcQhiZOWEKl95meYdvK7xI+ETLCq/Q==} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1076,6 +1091,11 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@1.23.0: + resolution: {integrity: sha512-38BpJcD0JhFosxHApP/BYsBetLpQFRoTRzEzstM/XCc3jsAG7wqaY1lgVwxiUe3xqYE+lNxo2PkCmYwXWrwwIw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -1565,6 +1585,10 @@ snapshots: '@esbuild/win32-x64@0.28.1': optional: true + '@fontsource-variable/inter@5.2.8': {} + + '@fontsource-variable/jetbrains-mono@5.2.8': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -2224,6 +2248,10 @@ snapshots: dependencies: yallist: 3.1.1 + lucide-react@1.23.0(react@19.2.7): + dependencies: + react: 19.2.7 + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 diff --git a/typst-leaf-frontend/index.html b/typst-leaf-frontend/index.html index 77dee06..12f8bca 100644 --- a/typst-leaf-frontend/index.html +++ b/typst-leaf-frontend/index.html @@ -4,6 +4,8 @@ + + typst-leaf diff --git a/typst-leaf-frontend/package.json b/typst-leaf-frontend/package.json index 6540451..c0b5d67 100644 --- a/typst-leaf-frontend/package.json +++ b/typst-leaf-frontend/package.json @@ -11,9 +11,12 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@fontsource-variable/inter": "^5.2.8", + "@fontsource-variable/jetbrains-mono": "^5.2.8", "@monaco-editor/react": "^4.7.0", "@tauri-apps/api": "^2", "@tauri-apps/plugin-opener": "^2", + "lucide-react": "^1.23.0", "monaco-editor": "^0.55.1", "monaco-vim": "^0.4.4", "react": "^19.1.0", @@ -22,13 +25,13 @@ }, "devDependencies": { "@tailwindcss/vite": "^4.1.6", + "@tauri-apps/cli": "^2", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", "@vitejs/plugin-react": "^4.6.0", "tailwindcss": "^4.1.6", "typescript": "~5.8.3", - "vite": "^7.0.4", - "@tauri-apps/cli": "^2" + "vite": "^7.0.4" }, "packageManager": "pnpm@10.23.0" } diff --git a/typst-leaf-frontend/src/App.tsx b/typst-leaf-frontend/src/App.tsx index 960c36c..ba8440d 100644 --- a/typst-leaf-frontend/src/App.tsx +++ b/typst-leaf-frontend/src/App.tsx @@ -11,12 +11,20 @@ import { EmptyState } from "./components/EmptyState"; import { PanelSection } from "./components/PanelSection"; import { SettingsPanel } from "./components/SettingsPanel"; import { ResizableSplit } from "./components/ResizableSplit"; +import { Files, GitGraph, Settings } from "lucide-react"; +import { Icon } from "./components/ui/Icon"; function Shell() { const { state, dispatch } = useApp(); + const panelTabs = [ + { id: "files" as const, label: "Files", icon: Files }, + { id: "git" as const, label: "Git", icon: GitGraph }, + { id: "settings" as const, label: "Settings", icon: Settings }, + ]; + return ( -
+
{state.error && ( @@ -27,51 +35,33 @@ function Shell() {
{/* Sidebar */} -