Files
pdf/docs/ui-redesign-plan.md
T

21 KiB
Raw Blame History

PDF Editor — UI Redesign: Gap Analysis & Implementation Plan

Status: Draft for review Goal: Replace the current "baby-like" UI with a sophisticated, comprehensive, professional PDF-editor interface that surfaces the full capability already built into the engine + gateway — without breaking or losing any existing functionality or workflow. Naming: Drop "EditQube"/"DocQube" branding. Use plain "PDF Editor" for now.


1. What we have today (baseline inventory)

1.1 Architecture (this is solid — we keep it)

React 19 + Vite 8 + Tailwind v4
  App.tsx ............ central state owner (zoom, tool, annotations, search, docs)
  components/ ........ Toolbar, LeftSidebar (tool rail), Sidebar (right tabs), SearchBar, Thumbnail, WasmInspector
  viewer/ ............ PDFViewer + 6 stacked layers (Canvas, Annotation, Selection, Redaction, Overlay, SearchOverlay)
  lib/ ............... gatewayService (REST client), coordinateMapping, wasmLoader
        |
        v REST
FastAPI gateway (app/routers: documents, edits, render, info, health)
        |
        v pybind11
C++ engine (PDFium + Skia + FreeType + HarfBuzz)

The layered-canvas viewer and the typed edit-operation envelope ({version, operations[]}) are genuinely good foundations. The redesign is a UI/UX re-skin + feature-surfacing effort, not an architecture rewrite.

1.2 Existing tools (left rail) — 8 tools

Select · Search · Pan · Highlight · Draw (ink) · Comment (sticky) · Signature · Redact

1.3 Existing right-sidebar tabs — 4

Files · Pages (thumbnails + delete/reorder) · Notes (annotation list) · Settings (empty stub)

1.4 Existing toolbar controls

Logo · Gateway-health % · device-preview icons (non-functional) · undo/redo (non-functional) · rotate · zoom ± · Comments · Share (stub) · Export · Save Edits

1.5 Workflows that currently work (MUST be preserved)

  1. Upload PDF → list → select → view (with mock fallback when gateway is down)
  2. Virtualized scroll viewer with per-page render + zoom
  3. Highlight via drag-select → persists via applyEdits (creates new doc id)
  4. Freehand ink draw → persists
  5. Sticky-note comment (click → popup → save) → persists
  6. Redact area (drag → confirm → permanent removal, full save)
  7. Page rotate / delete / reorder → persists
  8. Live full-text search (debounced) with prev/next + on-page highlight overlay
  9. Export / download edited PDF
  10. WASM inspector (debug panel) — client-side engine probe

2. The core problems (why it feels "baby-like")

# Problem Evidence
P1 Two fighting themes. index.css defines a full dark "enterprise" component system (rgba(2,6,23,…), white-on-dark) but App.tsx/components render a light theme with ad-hoc inline Tailwind. Half the CSS classes are unused or visually contradict what's on screen. index.css .toolbar, .sidebar, .doc-card vs. App.tsx bg-gray-50, text-gray-900
P2 No design system. Spacing, radii, colors, font-weights are chosen per-component. Multiple blues (#3b82f6 called "indigo"), random rounded-full pills, heavy drop-shadows. Toolbar uses shadow-lg; CSS uses 0 4px 20px rgba(0,0,0,.25)
P3 Gimmicky chrome. "Nice work! You completed 2/6 steps!" gamification toast, oversized circular page badge, decorative non-functional device-preview + undo/redo icons. App.tsx:470, Toolbar
P4 Thin feature surface. The engine/gateway expose ~20 endpoints and 10 edit types; the UI wires maybe half. Big capabilities (metadata, fonts, structured text model, free-text, image/stamp, real text selection) are invisible. §3 gap table
P5 Stubs masquerading as features. Text selection returns mock text (SelectionLayer.tsx:52); Signature tool only shows a banner; device-preview & undo/redo do nothing. SelectionLayer, OverlayLayer, Toolbar
P6 No empty/error/loading polish. Single spinner + "No active document." No drag-drop upload zone, no toasts system, no command surface, no keyboard shortcuts. App.tsx
P7 Branding leftovers. "EditQube" logo, "DocQube PDF Engine" baked into mock-page SVG. Toolbar.tsx:40, gatewayService.ts:361,415

3. Gap analysis — engine readiness vs. UI exposure

Reworked against the master engineering roadmap. Every UI feature is now gated on whether the engine actually supports it. We must build the UI to comprehensively surface what's Done, gracefully stub what's In-progress / Not-started, and never ship UI ahead of the engine.

Engine status (from roadmap): 🟢 Done · 🟠 In-progress · 🔴 Not-started/None UI status: wired · 🟡 partial/stub · absent

Capability Endpoint / edit type Engine UI Action
Render / zoom / pan / nav / thumbnails GET …/render 🟢 Keep; re-skin
Full-text search w/ rects GET …/search 🟢 Keep; add results-list panel
Text extraction + glyph bounds GET …/pages/{i}/text, …/model 🟢 🟡 mocked Wire real selection + copy (SelectionLayer.tsx:53 returns mock; clipboard never wired)
Structured model (para→line→run→glyph) GET …/pages/{i}/model 🟢 (logged only) Use for line-box selection now; reflow is future
Coordinate transforms (page↔device) GET …/transform/* 🟢 (client math) Use for pixel-accurate placement
Glyph-width measure GET …/glyph-width 🟢 Use for free-text/overlay layout
Document metadata (read) GET …/metadata 🟢 Properties panel (read-only)
Fonts inventory (embedded/subset/substituted…) GET …/fonts 🟢 (only WASM debug) Fonts inspector (differentiator)
Highlight edit highlight 🟢 Add color/opacity picker
Freehand ink edit freehand 🟢 Add color/thickness/eraser
Comment / sticky (create) edit comment 🟢 Keep; create-only (see edit/delete below)
Free-text box edit free_text 🟢 Add "Text box" tool
Text overlay / stamp edit text_overlay 🟢 Add stamp / text-overlay tool
Image overlay edit image_overlay 🟢 Visual Signature (draw/type/upload) + image stamp
Redaction edit redaction 🟠 (in progress) Keep; add multi-area when engine lands
Page rotate / delete / reorder edits page_* 🟢 Keep; add multi-select
Export / download (full save) GET …/export 🟠 (in progress) Keep; add print/flatten when ready
Annotation reader (existing annots) GET …/annotations 🟠 (in progress) list Read-only list; refine when reader lands
Edit / delete existing annotation (no edit op exists) 🔴 🔧 Needs new backend op; UI shows create-only until then
Underline / strikeout / squiggly markup decoration renderer 🔴 (Phase 3) 🟡 render-only Defer real markup; keep FE strikeout as-is
Glyph-accurate hit-testing (spatial index) hit-test module 🔴 (Phase 3) Approximate (line-box) selection only for v1
Edit existing text / replace / reflow content-stream editor 🔴 (Phase 3) Not a v1 UI feature — set expectations
Form fields (view / fill) AcroForm 🔴 (P2 view + P3 fill) Defer; stub "Forms" as coming-soon
Bookmarks / Outline (no API anywhere) 🔴 🔧 Needs new engine+gateway; stub Outline tab
Encrypted / password PDFs encryption 🔴 (Phase 3) Defer password prompt until engine supports
Digital (cryptographic) signature cert/PKI 🔴 (Phase 4, out of v1 scope) Do visual sig only; label as not certified
WASM in-browser render + worker wasm path 🟠 (in progress) 🟡 (inspector) Keep behind dev flag

3.1 What this rework changes vs. the first draft

  • Real text selection/copy is the #1 win and is genuinely ready — the engine extracts glyphs with bounds; the live viewer just never calls it. This is wiring, not new engine work. (Note: glyph-perfect hit-testing is Phase 3, so v1 selection is line-box-accurate, not per-glyph.)
  • Signature stays a flagship — but as a visual signature (image_overlay, which is Done), explicitly not a cryptographic/certified signature (Phase 4, out of v1 scope). UI copy must not imply legal e-signature.
  • 🔧 Three features I'd wrongly treated as "easy UI wins" are blocked on backend: (1) edit/delete of existing annotations (no edit op), (2) Outline/Bookmarks (no API at all), (3) password/encrypted PDFs (Phase 3). These become either small backend tickets or graceful stubs — not silent dead buttons.
  • "Edit existing text" must be framed as future. Users hear "PDF editor" and expect to retype existing paragraphs — that's the Phase 3 content-stream editor, Not-started. The UI should make the v1 capability set (annotate, overlay, redact, organize pages, fill-via-overlay) clear so it doesn't feel broken.

3.2 Small backend tickets that unlock high-value UI (flag to engine devs)

Ticket Unlocks Size
delete_annotation / update_annotation edit op Editable/deletable comments & markup in the inspector Small
GET …/outline (PDFium FPDFBookmark_*) Outline/Bookmarks navigation tab Small
Surface password flow + encryption (Phase 3) Open protected PDFs Medium (already roadmapped)

4. Target experience (the redesign)

4.1 Layout model — professional editor shell

┌────────────────────────────────────────────────────────────────────┐
│  TOP BAR:  [≡ File ▾] PDF Editor   ·   doc name   ·  ⟲⟳ undo/redo │
│            ·  save-state ("All changes saved" / "Saving…")          │
│            ·  zoom  ·  page X/Y  ·  [Share] [Export ▾]              │
├──┬─────────────────────────────────────────────────────┬───────────┤
│  │  CONTEXTUAL TOOL STRIP (changes with active tool):    │           │
│T │  e.g. Highlight → color swatches, opacity            │  RIGHT    │
│O │       Draw      → color, thickness, eraser           │  PANEL    │
│O ├───────────────────────────────────────────────────────┤  (tabbed) │
│L │                                                       │  Pages    │
│  │              PAGE CANVAS (scroll / virtualized)       │  Outline  │
│R │              + layered overlays (unchanged)           │  Comments │
│A │                                                       │  Search   │
│I │                                                       │  Props    │
│L │                                                       │  Fonts    │
└──┴───────────────────────────────────────────────────────┴───────────┘

Key moves vs. today:

  • Contextual tool strip under the top bar that swaps controls per active tool (this is what makes it feel like Acrobat/Figma rather than a toy). Replaces hardcoded colors/thicknesses with real pickers — closes several gaps at once.
  • Tool rail stays on the left (familiar), but redrawn on the new design system with consistent icons + tooltips + keyboard shortcut hints.
  • Right panel becomes a real tabbed inspector. Tabs are gated on engine readiness:
    • Ready now (engine Done): Pages, Comments/Notes (read + create), Search results, Properties (metadata, read-only), Fonts.
    • Stubbed (engine Not-started): Outline/Bookmarks and Forms render as a clean "coming soon" empty-state, not a broken tab — they light up when their backend ticket lands.
  • Command-driven top bar: real undo/redo (operation history), explicit save-state indicator, Export dropdown (Download / Print-when-ready / Flatten-when-ready).
  • Remove gamification toast, decorative device-preview icons, oversized page badge.

4.2 Design system (single source of truth)

Define tokens once (CSS variables + a Tailwind theme) and delete the contradictory legacy classes.

  • Theme: light, neutral, low-chroma workspace (Acrobat/Foxit-like) — locked (§8). Tokens structured so dark mode is a later toggle.
  • Color: one primary accent + neutral grays + semantic (success/warn/error). Kill the "indigo that's actually blue" ambiguity.
  • Type: keep Outfit (UI) + JetBrains Mono (debug/metadata). Define a type scale (xs2xl) and stop per-component font-weights.
  • Spacing/radii/shadow: 4px grid; 2 radii (control / card); 2 elevations. No more 0 4px 20px rgba(0,0,0,.25) on a light UI.
  • Primitives: small set of reusable components — Button, IconButton, Tooltip, Panel, Tab, Toolbar, Popover, ColorPicker, Slider, Toast, Modal, EmptyState, Spinner. Everything else composes these.

4.3 Interaction upgrades

  • Keyboard shortcuts (V select, H highlight, etc.; ⌘/Ctrl+Z undo, ⌘F search).
  • Drag-and-drop file upload onto the canvas with a real drop zone.
  • Toast/notification system (replace the gamification + scattered alert()/confirm() calls with a consistent confirm modal + toasts).
  • Proper unsaved-changes tracking and "Save"/"Saved" affordance.

5. Implementation plan (phased, non-breaking)

Principle: re-skin behind stable behavior first, surface only engine-Done features, stub the rest gracefully. Each phase compiles and ships; no phase removes a working workflow until its replacement is proven; no phase ships UI for an engine feature that isn't Done.

v1 capability framing (set in the UI so it doesn't feel broken): PDF Editor v1 = annotate (highlight/ink/comment), overlay (text box / stamp / visual signature), redact, organize pages (rotate/delete/reorder), search, select & copy text, inspect (properties/fonts), export. It does not yet edit existing text, fill forms, or apply certified digital signatures — those are engine Phase 3/4.

Phase 0 — Foundation & rename (no behavior change) — small

  • Establish design tokens: rewrite index.css into a coherent token layer + Tailwind theme; remove dead/contradictory classes.
  • Build the primitive component library (§4.2) as empty-but-styled shells.
  • Rename: "EditQube"/"DocQube" → "PDF Editor" (Toolbar.tsx:40, gatewayService.ts:361,415, index.html title, favicon/logo). Remove gamification toast (App.tsx:470) and decorative non-functional icons (device-preview).
  • Exit criteria: app looks cleaner, every existing workflow still works, zero functional regressions.

Phase 1 — App shell & top bar — medium

  • New top bar: File menu, doc title, real undo/redo (operation-history stack in App.tsx over the existing applyEdits model — each edit returns a newDocumentId, so keep a stack of doc ids for instant undo/redo), save-state indicator, zoom, page nav, Export dropdown.
  • Exit criteria: every top-bar control is functional or removed; undo/redo works for highlight/ink/comment/redact/page ops.

Phase 2 — Tool rail + contextual tool strip — medium

  • Redraw the tool rail on the new system with tooltips + shortcuts.
  • Add the contextual strip; move color/opacity (highlight) and color/thickness/eraser (draw) into real pickers — closes the hardcoded-color gaps (all engine-Done).
  • Exit criteria: highlight + draw fully parameterized; tool switching is keyboard-driven.

Phase 3 — Right inspector panel — medium

  • Rebuild right sidebar as tabbed inspector. Build the engine-Done tabs for real; stub the rest:
    • Pages — improved thumbnails + multi-select (Done).
    • Search — results list + on-page sync (Done).
    • Properties/metadata, read-only (Done).
    • Fonts/fonts inventory, the differentiator (Done).
    • Comments/Notes — list + create only (annotation reader in-progress; edit/delete deferred until the delete/update_annotation op exists — show a disabled affordance, not a dead button).
    • Outline + Forms — clean "coming soon" empty-states (no engine API yet).
  • Exit criteria: metadata + fonts + search-list visible; comments listed; stubbed tabs render an intentional empty-state.

Phase 4 — Real text layer (replace the mock) — medium-large

  • Replace SelectionLayer's mock (SelectionLayer.tsx:53) with real glyph data from /pages/{i}/text / /model: selectable text, copy-to-clipboard (currently never wired), highlight quad-points snapped to text.
  • v1 selection is line-box accurate (uses returned glyph bboxes); per-glyph hit-testing waits on the engine Phase 3 spatial index.
  • Exit criteria: user selects and copies real text; highlights align to text runs.

Phase 5 — New overlay tools: Visual Signature, Text box, Stamp — medium-large

  • Visual Signature via image_overlay (Done): draw-pad / type / upload → place on page. Replaces the banner-only stub. Label clearly as a visual signature, not a certified/digital signature.
  • Text box via free_text (Done); Stamp / text overlay via text_overlay / image_overlay (Done).
  • Exit criteria: signature + text box + stamp produce real edits and survive export.

Phase 6 — Polish & power features — ongoing

  • Drag-drop upload, toast system, confirm modals (replace scattered alert/confirm), keyboard-shortcut help overlay, search-and-redact, multi-select page ops, dark-mode toggle.
  • Engine-gated (wire when their tickets land): edit/delete annotations, Outline navigation, Forms view/fill, encrypted-PDF password prompt, print/flatten export, page insert/duplicate/extract, in-browser WASM worker render.

Phases 03 deliver the sophisticated look + surface every Done capability. Phases 45 wire the two flagships (real text, visual signature). Phase 6 polishes and lights up engine features as they land. "Everything (06)" = everything the engine currently supports, with graceful forward-compat stubs for the rest.


6. Preserve-don't-break checklist (regression guardrails)

Each phase must keep these intact (manual smoke + ideally a test):

  • Upload (real gateway and mock fallback when gateway 501/offline)
  • Document list / select / metadata load
  • Virtualized scroll + per-page render + zoom (0.5×–3×) + rotate
  • Highlight → applyEdits → new doc id swap
  • Freehand ink → persists
  • Comment popup → persists
  • Redact → confirm → full save → persists
  • Page rotate / delete / reorder → persists + current-page math
  • Search debounce + prev/next + on-page overlay + scroll-to-page
  • Export download
  • WASM inspector still loads (keep as dev/debug panel, hidden behind a flag)
  • Coordinate mapping correctness (zoom/rotation/DPR) — the redaction y-flip math in App.tsx:392 is fragile; cover before refactor.

Contracts that must not change without backend coordination: the EditOperation envelope shape, DocumentInfo shape, and gateway URLs in gatewayService.ts. Redesign is presentation-layer; keep gatewayService as the stable seam.


7. Effort & sequencing summary

Phase Theme Rel. size User-visible payoff
0 Tokens + rename + de-gimmick S Instantly looks less toy-like
1 App shell, undo/redo, save-state M Feels like a real editor
2 Tool rail + contextual strip + pickers M Pro tool ergonomics
3 Tabbed inspector (props, fonts, comments, search) M Surfaces hidden power
4 Real text selection/copy (engine Done; wiring) ML Kills the biggest "fake" feeling
5 Visual signature / text box / stamp (engine Done) ML Major new capabilities
6 Polish + light up engine features as they land ongoing Differentiation

Every phase touches presentation or wires an engine-Done capability. Nothing here waits on unbuilt engine work except the explicitly-stubbed tabs (Outline, Forms) and the Phase-6 engine-gated list.


8. Locked decisions (confirmed)

  1. Theme: Light neutral workspace (Acrobat/Foxit-like). Tokens architected so a dark theme is a later toggle, but dark mode itself is deferred to Phase 6.
  2. Layout: Left tool-rail + contextual tool strip under the top bar (per §4.1).
  3. Scope: Full redesign, Phases 06 (everything — sophisticated shell and flagship features and polish).
  4. Components: Hand-built primitives on Tailwind — zero new dependencies, full control, consistent with the current zero-dep frontend.

Next step: detailed component-by-component build spec for Phase 0, then begin implementation phase-by-phase with a smoke-check of the §6 regression list after each phase.