Files
typst-leaf/PLAN.md
T
nav.sikand 008dab1cf9 feat: IDE shell, file management, UI rehaul, reliability, and git workflow
This is the next major chunk on top of the barebones MVP. It implements
the IDE shell, resizable editor/preview workspace, file CRUD, Git workflow
UI upgrade, SyncTeX/LSP reliability hardening, and documentation updates.

Highlights:

* New shared path utilities (typst-leaf-frontend/src/path-utils.ts):
  normalizeFsPath, encodeVirtualPathForFileUri, relativePathFromProject.

* SyncTeX reliability:
  * Jump targets now carry stable numeric IDs for deduplication.
  * tinymist/preview/scrollSource and window/showDocument payloads are
    validated and normalized through shared path utilities.
  * External preview paths are reported via a toast instead of silent drop.
  * Editor uses monaco.Uri.equals for URI comparison.

* IDE shell rehaul:
  * New components: TopBar, StatusBar, PanelSection, ResizableSplit,
    ToastHost, EmptyState.
  * App.tsx now uses a layered layout: top bar, sidebar tabs
    (Files/Git/Settings), resizable main workspace, status bar, toasts.
  * Sidebar tabs replace the old inline Git/settings panels.

* Resizable workspace:
  * Pointer-driven resizable split between editor and preview.
  * Split ratio persisted to localStorage (typst-leaf.split).
  * Double-click splitter resets to 55%.
  * onResize prop dispatches typst-leaf:layout so Monaco re-layouts.

* File management:
  * Backend CRUD: POST /file, DELETE /file, PATCH /file, POST /folder.
  * Frontend API wrappers and inline FileTree create/rename/delete.
  * Backend tree endpoint returns empty directories in a folders array.
  * Rename protects the .typ extension and rejects overwriting existing
    files atomically on POSIX.
  * Newly created files are opened automatically.
  * Dirty file badges in the tree.

* Git workflow upgrade:
  * GitPanel now shows changed files grouped by staged/unstaged, deduped
    by path, with per-file status icons.
  * Click a changed file to open it.
  * Commit disabled when clean or no message.
  * Push/pull with success/error toasts.
  * FileTree shows dirty badges from git status.

* Preview UX:
  * Preview toolbar with status chip, reload button, and SyncTeX hint.
  * Preview hidden/marked as "open a file" when no file is open.

* State/UX infrastructure (app-state.tsx):
  * activePanel, fileDirty, saving, notice (toast), vimOn, treeVersion,
    folders, and stable jumpTarget.id.
  * focusCommit switches to the Git panel.
  * selectProject resets more state to avoid stale data.

* Editor improvements:
  * Monaco model disposed on unmount so LSP sees didClose.
  * mountedRef survives React StrictMode remounts.
  * Global save/layout events bridge TopBar and ResizableSplit to the
    editor instance.
  * Vim mode state moved to global state/localStorage.
  * Removed redundant automaticLayout and inline Save button.

* Documentation:
  * Added DESIGN.md with the full UI aesthetic guide.
  * Updated PLAN.md, README.md, VISION.md, and the frontend README.

Verification:
  * pnpm -r typecheck passes.
  * pnpm --filter typst-leaf-frontend build passes.
2026-07-02 02:05:04 +05:30

201 lines
8.1 KiB
Markdown

# 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.