mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-03 02:11:07 +05:30
362 lines
24 KiB
Markdown
362 lines
24 KiB
Markdown
# MarkdownConverter — React + shadcn/ui UI Redesign
|
||
|
||
**Date:** 2026-06-05
|
||
**Status:** Design (awaiting user approval)
|
||
**Branch:** `react-electron`
|
||
**Author:** Brainstormed with user via superpowers:brainstorming
|
||
|
||
## Summary
|
||
|
||
Replace the legacy vanilla JS renderer (`src/renderer.js` is 213 KB; `src/styles.css` is 74 KB) with a modern React 19 + Vite + TypeScript + shadcn/ui renderer that achieves visual feature parity while delivering a Polished + Glassy (Raycast/Arc-style) aesthetic. The Electron main process, preload bridge, and IPC contracts stay unchanged. Work proceeds via vertical slices — each PR ships a demoable feature.
|
||
|
||
## Goals
|
||
|
||
1. Replace every render-time feature of the legacy renderer with an idiomatic React + shadcn/ui implementation.
|
||
2. Adopt the "Polished + Glassy" visual language (subtle shadows, 8–12 px radii, gradient accents, gentle depth) on top of the existing ConcreteInfo brand tokens and design system.
|
||
3. Use a single component foundation (shadcn/ui) and a single motion library (Motion / Framer Motion) to keep the dependency surface narrow and the design coherent.
|
||
4. Keep the main process, preload, and IPC contracts untouched. The renderer is the only surface being rewritten.
|
||
5. Keep the app runnable at every commit. No "big bang" merge.
|
||
|
||
## Non-Goals
|
||
|
||
- Migrating the main process to TypeScript (out of scope for this spec).
|
||
- Adding new features the legacy renderer does not have (plugin system, AI features, etc. — those are future specs).
|
||
- Replacing Pandoc/FFmpeg/ImageMagick orchestration.
|
||
- Changing the packaging pipeline (electron-builder config stays).
|
||
- Replacing the CodeMirror 6 editor — it is the right tool and is already wired up.
|
||
|
||
## Decisions Locked During Brainstorming
|
||
|
||
| Decision | Choice | Why |
|
||
|---|---|---|
|
||
| Scope | Full feature parity with legacy renderer | User-selected option. Renderer is one cohesive surface; splitting it across specs would force premature contracts. |
|
||
| Visual style | **B — Polished + Glassy** (Raycast/Arc aesthetic) | "Fancy" comes from elevation, gradient accents, and material depth — not over-designed visuals. |
|
||
| Layout | **2 — IDE-style** (equal editor/preview, draggable divider, collapsible sidebar) | Power-user markdown apps converge on this. Draggable divider + keyboard reset. |
|
||
| Modal patterns | **A (Centered Dialog), B (Right Side-Sheet), D (Toasts)** | No command palette. |
|
||
| Command palette | **No** — full menus, no ⌘K | Power users can use the OS-level launcher. App stays focused on writing. |
|
||
| Animation | **Motion (Framer Motion)** | Best for layout transitions, modal/drawer enter/exit, drag. Sparingly used. |
|
||
| Component library | **shadcn/ui** | Tailwind + Radix primitives, copy-paste ownership, perfect fit for the "glassy" aesthetic and the HSL-CSS-variable foundation that is already in place. |
|
||
| Implementation strategy | **Vertical slices** — one feature end-to-end per PR | App stays runnable. Each PR is reviewable. |
|
||
|
||
## Defaults (Used Unless Overridden Later)
|
||
|
||
| Item | Default | Why |
|
||
|---|---|---|
|
||
| State management | Zustand (already in deps) + Immer for nested patches | Already in `package.json`; perfect for editor state. |
|
||
| Theming | shadcn `next-themes`, dark default + light, system-aware | shadcn canonical pattern. Brand colors already in CSS vars. |
|
||
| Icons | `lucide-react` (already in deps) | 1000+ tree-shakable icons. |
|
||
| Forms | `react-hook-form` + `zod` | Standard for shadcn forms. |
|
||
| Drag/drop (sortable lists) | `@dnd-kit/core` | De facto React drag lib (file tree reordering, plugin list reorder). |
|
||
| Pane resize (split layout) | `react-resizable-panels` | Canonical React lib for resizable pane groups; handles drag, arrow keys, snap, persisted sizes. |
|
||
| Testing | Vitest + RTL + Playwright (E2E + visual regression) | Standard for React + Electron. |
|
||
| TypeScript | Strict mode (already wired) | Already in deps and `vite.renderer.config.ts`. |
|
||
|
||
## Architecture
|
||
|
||
The Electron app keeps its existing process model. Only the renderer is rewritten.
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────┐
|
||
│ Electron Main (UNCHANGED) │
|
||
│ - BrowserWindow, IPC handlers, file/fs ops │
|
||
│ - Pandoc, FFmpeg, ImageMagick orchestration │
|
||
└────────────┬─────────────────────────────────────────────┘
|
||
│ contextBridge (UNCHANGED preload.js)
|
||
┌────────────▼─────────────────────────────────────────────┐
|
||
│ React Renderer (REWRITTEN) │
|
||
│ ┌────────────────────────────────────────────────────┐ │
|
||
│ │ AppShell (layout) │ │
|
||
│ │ ├─ MenuBar (native) │ │
|
||
│ │ ├─ AppHeader (logo, breadcrumbs, theme toggle) │ │
|
||
│ │ ├─ TabBar (open files) │ │
|
||
│ │ ├─ Toolbar (formatting) │ │
|
||
│ │ ├─ ResizablePaneGroup (sidebar | editor | preview) │ │
|
||
│ │ │ ├─ Sidebar (file tree, outline) │ │
|
||
│ │ │ ├─ EditorPane (CodeMirror 6) │ │
|
||
│ │ │ └─ PreviewPane (marked + KaTeX + Mermaid) │ │
|
||
│ │ ├─ StatusBar (word count, encoding, cursor pos) │ │
|
||
│ │ └─ ModalLayer (Dialog, SideSheet, Toaster) │ │
|
||
│ └────────────────────────────────────────────────────┘ │
|
||
│ ┌────────────────────────────────────────────────────┐ │
|
||
│ │ Feature Modules (each owns UI + state slice) │ │
|
||
│ │ ├─ editor/ CodeMirror wrapper, syntax, themes │ │
|
||
│ │ ├─ preview/ markdown→html, KaTeX, Mermaid │ │
|
||
│ │ ├─ tabs/ open files, dirty state │ │
|
||
│ │ ├─ sidebar/ file tree, outline, search results │ │
|
||
│ │ ├─ modals/ export, settings, about, etc. │ │
|
||
│ │ ├─ tools/ zen, repl, ascii-gen, table-gen │ │
|
||
│ │ └─ export/ pdf, docx, html, image batch │ │
|
||
│ └────────────────────────────────────────────────────┘ │
|
||
│ ┌────────────────────────────────────────────────────┐ │
|
||
│ │ Shared Infrastructure │ │
|
||
│ │ ├─ stores/ Zustand slices per feature │ │
|
||
│ │ ├─ hooks/ useFile, useEditor, useTheme, etc. │ │
|
||
│ │ ├─ lib/ cn, ipc, formatters, validators │ │
|
||
│ │ ├─ ui/ shadcn primitives: button, dialog… │ │
|
||
│ │ └─ types/ shared TS types │ │
|
||
│ └────────────────────────────────────────────────────┘ │
|
||
└──────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Architectural Rules
|
||
|
||
- **Shell components** (`AppHeader`, `TabBar`, `StatusBar`) subscribe only to `useAppStore`.
|
||
- **Feature components** subscribe to their own feature's store.
|
||
- **Cross-feature access** goes through hooks, not direct store imports (e.g., `useFileTree()` wraps `useFileStore`).
|
||
- **Feature modules are self-contained** — each owns its components, its Zustand slice, and its types. Safe to develop in parallel later.
|
||
- **No direct `window.electronAPI` calls** from feature code. All IPC goes through `lib/ipc.ts` for type safety and error normalization.
|
||
|
||
## State Management
|
||
|
||
```
|
||
stores/
|
||
├─ useAppStore // global UI: theme, sidebar, pane sizes, modals open
|
||
├─ useFileStore // file system: tree, open files, active tab
|
||
├─ useEditorStore // editor: per-file content, cursor, selection, dirty
|
||
├─ usePreviewStore // preview: scroll sync, zoom, theme
|
||
├─ useSettingsStore // user prefs (persisted to electron-store)
|
||
└─ useCommandStore // menu actions registry, recent actions
|
||
```
|
||
|
||
**Why slices instead of one mega-store?** Editor content can be megabytes. Keeping it in its own slice lets React avoid re-rendering the preview when only the editor changes — components subscribe with selectors.
|
||
|
||
**Persistent state** (auto-saved to electron-store via Zustand `persist` middleware): theme, sidebar visibility, last open files, pane divider positions, settings.
|
||
|
||
**Ephemeral state** (lost on quit): active modal, hover states, search query, current file content (saved to disk on idle).
|
||
|
||
## Visual Design System
|
||
|
||
### Color Tokens
|
||
|
||
The existing `globals.css` HSL variables stay. Additions for the "glassy" aesthetic:
|
||
|
||
```css
|
||
--shadow-sm: 0 1px 2px rgba(13, 11, 9, 0.06);
|
||
--shadow-md: 0 4px 12px rgba(13, 11, 9, 0.08), 0 0 0 1px rgba(13, 11, 9, 0.04);
|
||
--shadow-lg: 0 12px 32px rgba(13, 11, 9, 0.12), 0 0 0 1px rgba(13, 11, 9, 0.06);
|
||
--shadow-glow-brand: 0 0 24px rgba(229, 70, 31, 0.25);
|
||
|
||
--glass-bg-light: rgba(255, 255, 255, 0.72);
|
||
--glass-bg-dark: rgba(13, 11, 9, 0.72);
|
||
--glass-border-light: rgba(255, 255, 255, 0.4);
|
||
--glass-border-dark: rgba(255, 255, 255, 0.08);
|
||
```
|
||
|
||
### shadcn Components
|
||
|
||
Install via `npx shadcn@latest add`:
|
||
|
||
**Primitives** (need all of these): `button`, `dialog`, `sheet`, `popover`, `tooltip`, `select`, `dropdown-menu`, `tabs`, `separator`, `scroll-area`, `toggle`, `switch`, `slider`, `input`, `textarea`, `label`, `form`, `skeleton`, `sonner`, `command`.
|
||
|
||
**Composite** (custom-built on top of primitives): `file-tree`, `pane-group`, `divider`, `status-bar`, `menu-bar`, `toast`.
|
||
|
||
### Typography
|
||
|
||
- Body: Plus Jakarta Sans 15 px / line-height 1.6
|
||
- Code: JetBrains Mono 13.5 px
|
||
- Display: Barlow Condensed 700/800 — used sparingly (page titles, big metrics)
|
||
- Headings: Plus Jakarta Sans 600/700 with tight letter-spacing
|
||
- Labels (`.label`): Plus Jakarta Sans 500, 12 px, uppercase, 0.05 em letter-spacing
|
||
|
||
### Motion Choreography
|
||
|
||
| Element | Motion | Duration | Easing |
|
||
|---|---|---|---|
|
||
| Modal (Dialog A) | Scale 0.96→1, opacity 0→1 | 200 ms | `ease-out` |
|
||
| Side sheet (B) | TranslateX 100%→0, opacity 0→1 | 300 ms | `cubic-bezier(0.16, 1, 0.3, 1)` |
|
||
| Toast | TranslateY 100%→0, opacity | 250 ms | spring(stiffness: 300, damping: 30) |
|
||
| Sidebar toggle | Width 264 px↔72 px, content fade | 250 ms | `ease-in-out` |
|
||
| Divider drag | Live width update | 0 ms | none (instant) |
|
||
| Theme switch | CSS variables, opacity overlay | 300 ms | `ease-in-out` |
|
||
| Tab switch | Underline slide | 200 ms | `ease-out` |
|
||
| Hover (buttons) | `bg` + `shadow` shift | 150 ms | `ease-out` |
|
||
| Focus ring | Outline grow | 100 ms | `ease-out` |
|
||
|
||
**Rules:** Every motion has a purpose. No gratuitous animation. Respects `prefers-reduced-motion` (Motion handles this automatically).
|
||
|
||
### Empty / Loading / Error States
|
||
|
||
Every async surface ships all three. Sonner toasts for ephemeral feedback. Skeleton screens for content areas. Empty-state components with icon + message + primary CTA.
|
||
|
||
## Modal/Overlay Patterns
|
||
|
||
| Use case | Pattern | Why |
|
||
|---|---|---|
|
||
| Export (PDF/DOCX/HTML) | A — Centered Dialog | Focused decision, ~3–5 fields, "do one thing" |
|
||
| Settings | B — Right Side-Sheet | Long form, tabbed sections, stays open while editing |
|
||
| Find/Replace | Inline toolbar (not modal) | Always-visible utility |
|
||
| About | A — Centered Dialog | Tiny info dump |
|
||
| Confirm destructive (delete, close unsaved) | A — Centered Dialog | Forces attention |
|
||
| File save error | D — Toast | Non-blocking info |
|
||
| Pandoc/FFmpeg progress | D — Toast → sticky on >3 s | Background work feedback |
|
||
| Plugin manager | B — Right Side-Sheet | Lists + per-item actions |
|
||
| ASCII/Table generators | A — Centered Dialog | Tool-style focused input → output |
|
||
| Print preview | A — Centered Dialog | Full-screen-ish modal overlay |
|
||
| Welcome (first launch) | A — Centered Dialog | One-time onboarding |
|
||
| Word export | A — Centered Dialog | Template selection |
|
||
| Zen mode | Full-viewport toggle (no modal) | Replaces the editor entirely |
|
||
| REPL | Bottom-pinned panel (split-pane) | Persistent terminal-like UI |
|
||
| Quick file open | B — Right Side-Sheet | File tree, search, recent |
|
||
|
||
### Dialog A Anatomy (Export as example)
|
||
|
||
```
|
||
┌─ Backdrop (rgba(13,11,9,0.45) + backdrop-blur 4px) ─────────┐
|
||
│ │
|
||
│ ┌──── Modal (max-w-md, rounded-2xl, shadow-lg) ─────┐ │
|
||
│ │ ┌── Header ────────────────────────────────────┐ │ │
|
||
│ │ │ [Icon] Export as PDF [×] │ │ │
|
||
│ │ │ Choose format options │ │ │
|
||
│ │ └─────────────────────────────────────────────┘ │ │
|
||
│ │ ┌── Body ──────────────────────────────────────┐ │ │
|
||
│ │ │ Format: [Letter] [A4] [Legal] │ │ │
|
||
│ │ │ Margins: ────●──── │ │ │
|
||
│ │ │ ☐ Include table of contents │ │ │
|
||
│ │ │ ☐ Embed fonts │ │ │
|
||
│ │ └─────────────────────────────────────────────┘ │ │
|
||
│ │ ┌── Footer ────────────────────────────────────┐ │ │
|
||
│ │ │ [Cancel] [Export →] │ │ │
|
||
│ │ └─────────────────────────────────────────────┘ │ │
|
||
│ └──────────────────────────────────────────────────┘ │
|
||
│ │
|
||
└────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Side-Sheet B Anatomy (Settings as example)
|
||
|
||
Slides in from right, ~50 % width (max 560 px). Backdrop is `rgba(13,11,9,0.2)` with `backdrop-blur(2 px)` (lighter than dialog — the sheet is the focus). Tab navigation in the sheet header (Editor / Theme / Export / Plugins / About).
|
||
|
||
### Toast D Anatomy (Sonner)
|
||
|
||
Stacked bottom-right, max 3 visible. Glass background. Color-coded 3 px left border — success `#1a7a56`, error `#ef4444`, info `#0ea5e9`, warning `#eab308`. Icon + title + description. Optional action button. Auto-dismiss 4 s for success, sticky for error.
|
||
|
||
## Data Flow (Editor → Preview Pipeline)
|
||
|
||
```
|
||
User types
|
||
↓
|
||
CodeMirror onChange
|
||
↓
|
||
useEditorStore.updateContent(tabId, content) ← debounced 50 ms
|
||
↓
|
||
┌─ Persist to electron-store on idle (1 s) ─┐
|
||
│ │
|
||
└─ Publish to usePreviewStore (subscribed) ─┘
|
||
↓
|
||
marked(content) → sanitized HTML
|
||
↓
|
||
PreviewPane renders HTML
|
||
KaTeX post-processes $...$
|
||
Mermaid post-processes ```mermaid
|
||
Highlight.js post-processes ```lang
|
||
↓
|
||
useEffect: scroll-sync editor cursor → preview position
|
||
```
|
||
|
||
**Bidirectional scroll sync:** editor scroll → preview (primary), preview click → editor cursor (secondary). Throttled to 60 fps via `requestAnimationFrame`.
|
||
|
||
## IPC Contract
|
||
|
||
The preload bridge stays unchanged. A new `src/renderer/lib/ipc.ts` wraps every channel with TypeScript types and normalizes errors to a discriminated union:
|
||
|
||
```ts
|
||
type IpcResult<T> =
|
||
| { ok: true; data: T }
|
||
| { ok: false; error: { code: string; message: string } };
|
||
|
||
export const ipc = {
|
||
file: {
|
||
open: (): Promise<IpcResult<FileResult>>,
|
||
read: (path: string): Promise<IpcResult<string>>,
|
||
write: (path: string, content: string): Promise<IpcResult<void>>,
|
||
list: (dir: string): Promise<IpcResult<FileEntry[]>>,
|
||
onChange: (cb: (path: string) => void) => () => void,
|
||
},
|
||
export: {
|
||
pdf: (opts: PdfOptions): Promise<IpcResult<ExportResult>>,
|
||
docx: (opts: DocxOptions): Promise<IpcResult<ExportResult>>,
|
||
html: (opts: HtmlOptions): Promise<IpcResult<ExportResult>>,
|
||
batch: (items: BatchItem[], opts: BatchOptions): Promise<IpcResult<BatchResult>>,
|
||
},
|
||
app: {
|
||
getVersion: (): Promise<IpcResult<string>>,
|
||
openExternal: (url: string): Promise<IpcResult<void>>,
|
||
showItemInFolder: (path: string): Promise<IpcResult<void>>,
|
||
},
|
||
};
|
||
```
|
||
|
||
## Error Handling
|
||
|
||
Layered defense — no single failure can crash the app:
|
||
|
||
1. **IPC errors** → caught in `lib/ipc.ts` wrapper, returned as `IpcResult<T>` discriminated union. Components show toast on error.
|
||
2. **Component errors** → React error boundary per feature area (one for editor, one for preview, one for modals). On error: show inline error UI with "Reload this panel" + "Copy details" actions.
|
||
3. **Async operations** (export, file ops) → loading state on button + toast on completion. Long ops (>2 s) get a sticky toast with cancel.
|
||
4. **Validation errors** (settings, export options) → inline form errors via `react-hook-form` + `zod`. shadcn `Form` component for consistent error display.
|
||
5. **Pandoc/FFmpeg missing** → detected at startup, banner + disable export menu items. Don't surprise-fail at export time.
|
||
|
||
## Testing Strategy
|
||
|
||
- **Unit (Vitest):** stores, hooks, lib utilities, formatters, validators
|
||
- **Component (Vitest + RTL):** shadcn wrappers, dialog interactions, sidebar toggle, divider drag, theme toggle
|
||
- **Integration (Vitest + RTL):** editor ↔ preview flow, file open → tab add → content display, settings change persists
|
||
- **E2E (Playwright):** app launches, file opens, markdown renders, export to PDF works
|
||
- **Visual regression (Playwright snapshots):** locked-in screenshots for header, sidebar, dialogs, toasts — catch accidental style drift
|
||
- **Target coverage:** stores/hooks/lib ≥ 90 %, components ≥ 75 %, E2E covers all critical paths
|
||
|
||
## Accessibility (WCAG 2.1 AA)
|
||
|
||
Baked in via shadcn + Radix:
|
||
|
||
- All dialogs focus-trap, Esc to close, return focus to trigger
|
||
- All interactive elements keyboard-reachable
|
||
- Visible focus rings (2 px brand ring)
|
||
- 4.5:1 contrast minimum (already met by brand colors)
|
||
- `aria-label` on icon buttons, `role="alert"` on toasts
|
||
- Respects `prefers-reduced-motion` (Motion handles this automatically)
|
||
|
||
## Implementation Phases (Vertical Slices)
|
||
|
||
Each phase is a shippable PR that keeps the app runnable. The legacy `renderer.js` is gradually replaced; until each phase is complete, the old renderer code still runs the missing parts.
|
||
|
||
| # | Phase | Output | Acceptance |
|
||
|---|---|---|---|
|
||
| 1 | **Foundation** | shadcn installed; `next-themes`, `motion`, `react-hook-form`, `zod`, `@dnd-kit/core`, `react-resizable-panels`, `sonner` installed; design tokens finalized; `lib/utils.ts` (`cn`), `lib/ipc.ts` typed wrappers, `lib/motion.ts` preset transitions, `App.tsx` shell skeleton renders | `npm run build` succeeds; dev server shows the new shell with theme toggle working |
|
||
| 2 | **App shell + layout** | `AppHeader`, `TabBar`, `Toolbar`, `Breadcrumb`, `StatusBar`, `ResizablePaneGroup` with sidebar toggle and draggable divider. Empty editor/preview panes. | Resize divider with mouse and arrow keys; sidebar collapses; pane sizes persist. |
|
||
| 3 | **Editor pane** | CodeMirror 6 wrapped, dark/light themes wired to shadcn theme, syntax highlighting, line numbers, search, autocomplete | Open `.md` file → renders in editor; can edit and save. |
|
||
| 4 | **Preview pane** | marked + DOMPurify + KaTeX + Mermaid + highlight.js. Bidirectional scroll sync with editor. | Open file → preview renders, follows cursor. |
|
||
| 5 | **File tree + tabs** | Sidebar file tree (read directory on demand, lazy-expand children only on click). Tabs for open files. Dirty state indicator. File content is read from disk only when the tab is activated. | Open folder → root populates; click folder → children load; click file → opens in tab; close tab reverts dirty. |
|
||
| 6 | **Native menus + toolbar** | Replace the legacy `CommandPalette` with full menus (File / Edit / View / Insert / Format / Tools / Help) bound to keyboard shortcuts. Toolbar buttons. | All menu items invoke the right action; shortcuts work; toolbar reflects active state. |
|
||
| 7 | **Modals** | Export dialog (PDF/DOCX/HTML/batch), Settings side-sheet (Editor/Theme/Export/Plugins/About tabs), About dialog, Confirm-destructive dialog | All dialogs and sheet render with proper motion; settings persist; export works end-to-end. |
|
||
| 8 | **Toasts** | Sonner wired into all async operations (save, export, errors, tool missing) | All operations give appropriate feedback; no silent failures. |
|
||
| 9 | **Advanced tools** | Zen mode (full-viewport toggle), REPL (bottom-pinned panel), ASCII generator, Table generator, Word export template picker, Print preview | Each tool is feature-complete vs. legacy version. |
|
||
| 10 | **Polish + delete legacy** | Visual regression snapshots locked; remove `renderer.js` and old `styles*.css` references from build; `npm run build:linux` produces a working installer | Final PR ships an installer with no legacy code paths. |
|
||
|
||
## Risks and Mitigations
|
||
|
||
| Risk | Mitigation |
|
||
|---|---|
|
||
| shadcn CLI requires Vite (not vanilla Electron renderer) | Vite is already configured for the renderer in `vite.renderer.config.ts`; the CLI works against the same project. |
|
||
| shadcn CLI assumes Tailwind is at project root; we have it in renderer/ only | Point the CLI at `src/renderer/components.json` and set `tailwind.css` to the right path. |
|
||
| Marked + KaTeX + Mermaid + highlight.js together is heavy | Lazy-load Mermaid (only when `mermaid` code block encountered). KaTeX is loaded once, cached. |
|
||
| Editor content state can be megabytes → re-render storms | Editor content lives in its own slice; preview subscribes to a derived/cached HTML string; components use `useShallow` / selector subscriptions. |
|
||
| Bidirectional scroll sync loops | `useEffect` debounce + ignore if cursor/selection is the sync source. |
|
||
| CodeMirror 6 doesn't ship a Tailwind theme by default | Use `@codemirror/theme-one-dark` for dark; build a custom theme that pulls from CSS variables for light. |
|
||
| The legacy `renderer.js` and `styles*.css` are referenced from `index.html` (now `src/renderer/index.html`) | Phase 10 deletes the references; until then, both run side-by-side and the new React app sits in a known root div. |
|
||
| Electron `nodeIntegration` is off; we use contextBridge | Already the case. Document the contract clearly in `lib/ipc.ts`. |
|
||
|
||
## Open Questions (to confirm before implementation)
|
||
|
||
None. All major decisions are locked. Defaults will be used unless the user overrides them when reviewing the implementation plan.
|
||
|
||
## References
|
||
|
||
- `src/renderer.js` (213 KB) — legacy renderer being replaced
|
||
- `src/styles.css` (74 KB), `src/styles-modern.css` (71 KB), `src/styles-concreteinfo.css` (21 KB) — legacy styles being replaced
|
||
- `src/renderer/styles/globals.css` — already shadcn-compatible (HSL CSS variables)
|
||
- `src/renderer/App.tsx` — empty skeleton that references components we will build
|
||
- `tailwind.config.js` — brand colors and fonts already defined
|
||
- `vite.renderer.config.ts` — Vite + React plugin already configured
|
||
- `package.json` — CodeMirror 6, TanStack Table, lucide-react, cva, clsx, tailwind-merge, tailwindcss-animate already installed
|