Files
markdown-converter/CLAUDE.md
T
amitwh bb4e874809 docs(claude-md): add tailored CLAUDE.md for react-electron branch
Documents the React 19 + TypeScript + Tailwind/shadcn rewrite: dual
Vite+Electron dev workflow, modular main process, Zustand stores,
typed IPC via preload whitelist, two-stage build pipeline, and
dual test runners (Jest main, Vitest renderer).

Amit Haridas
2026-06-19 23:18:22 +05:30

9.4 KiB

CLAUDE.md — MarkdownConverter (react-electron)

General code-quality, TypeScript, git, security, and testing standards are in the global CLAUDE.md. This file holds project- and branch-specific notes.

Project Overview

Electron desktop app for Markdown editing and universal file conversion powered by Pandoc. Cross-platform (Win/macOS/Linux). Features: multi-tab editor with live preview, 25+ themes, PDF viewer/editor (merge/split/compress/rotate/watermark/password), export to 20+ formats (PDF/DOCX/ODT/EPUB/HTML/LaTeX/RTF/PPTX), batch conversion, syntax highlighting, diagram support (Mermaid), Git integration, plugin system, and auto-updater.

  • Version: 5.0.1
  • License: MIT
  • App ID: com.concreteinfo.markdownconverter

Branch Specifics

This is the React rewrite branch — the renderer has been rebuilt with React 19 + TypeScript + Tailwind CSS + shadcn/ui, replacing the vanilla JS renderer from master. The main process remains vanilla CommonJS JavaScript. A dual dev workflow runs Vite (renderer) and Electron (main) concurrently.

Key differences from master:

  • Renderer: React 19 + TypeScript (TSX) instead of vanilla JS DOM manipulation
  • Bundler: Vite for the renderer (vite.renderer.config.ts)
  • UI: shadcn/ui (Radix primitives + Tailwind) instead of hand-rolled CSS
  • State: Zustand 5 stores instead of global mutable state
  • Security: contextIsolation: true + nodeIntegration: false (preload with channel whitelisting) instead of master's open renderer
  • Build: two-stage (Vite build renderer, then electron-builder packages) instead of single electron-builder pass
  • Testing: dual test runners — Vitest (renderer/React/TS) + Jest (main process/JS)
  • Main process is now in src/main/ (modular) instead of flat src/main.js
  • Adds auto-updater via electron-updater with GitHub Releases + self-hosted feed support
  • Adds React Hook Form + Zod for form validation, Lucide React icons, Motion for animations
  • Legacy sidebar modules (src/sidebar/*.js) still exist alongside new React sidebar (src/renderer/components/sidebar/)

Architecture

Main Process (src/main/)

Modular structure (improvement over master's monolith):

  • src/main/index.js — IPC handlers, Pandoc invocation, export logic (~3,500 lines)
  • src/main/PDFOperations.js — PDF manipulation via pdf-lib
  • src/main/GitOperations.js — Git operations via simple-git
  • src/main/store.js — Custom JSON settings store (NOT electron-store)
  • src/main/window/index.js — BrowserWindow creation with three-mode loading (dev/prod/packaged)
  • src/main/menu/ — Application menu definitions
  • src/main/ipc/ — Crash handlers, updater handlers
  • src/main/updater/ — Auto-update service, feed config, migration runner
  • src/main/files/ — File operation modules
  • src/main/word-template/ — Word template export

Preload (src/preload.js)

Properly isolated. Uses contextBridge with channel whitelisting (ALLOWED_SEND_CHANNELS, ALLOWED_RECEIVE_CHANNELS arrays). The renderer has no direct Node access.

Renderer (src/renderer/)

React 19 + TypeScript application bundled by Vite:

  • src/renderer/App.tsx — Root component: assembles AppShell, modals, command palette, toaster
  • src/renderer/components/layout/AppShell.tsx — Three-panel resizable layout (sidebar | editor | preview)
  • src/renderer/stores/ — Zustand stores: app-store, editor-store, file-store, preview-store, settings-store, command-store
  • src/renderer/hooks/ — Custom hooks: use-shortcut, use-file-shortcuts, use-menu-action, use-scroll-sync, use-zen-mode, use-export-source
  • src/renderer/components/modals/ — 30+ modal dialogs as React components
  • src/renderer/components/editor/ — CodeMirror 6 editor React wrapper
  • src/renderer/components/preview/ — Markdown renderer with Mermaid lazy loading
  • src/renderer/components/sidebar/ — React sidebar panels (FileTree, GitStatus, Outline, Snippets, Templates)
  • src/renderer/components/ui/ — shadcn/ui primitives (button, dialog, sheet, select, tabs, etc.)
  • src/renderer/lib/ — Utilities: typed IPC wrapper (ipc.ts), export modules, validators
  • src/renderer/types/ — TypeScript declarations: electron.d.ts (window.electronAPI), ipc.ts (IPC types)

Security Model

  • contextIsolation: true + nodeIntegration: false (properly secured, unlike master)
  • Preload with explicit channel whitelisting
  • TypeScript declarations ensure type-safe IPC
  • Pandoc invoked via execFile (not exec)
  • Permission handler: only clipboard-read/clipboard-write allowed
  • ESLint enforces no-eval, no-implied-eval, no-new-func
  • CSP in index.html restricts script/style/img/font/connect sources

Plugin System (src/plugins/)

Unchanged from master. Manifest-based discovery, built-in writing-studio plugin.

System Dependencies

Dependency Required Notes
Node.js >= 20 Electron 41 bundles Node 20.x; Vite 8 requires Node 18+
Pandoc Yes (for exports) Downloaded to bin/<platform>/pandoc via scripts/download-tools.js (v3.9.0.2). Falls back to system PATH.
FFmpeg Bundled ffmpeg-static npm package; asarUnpacked
MiKTeX / TeX Live Optional LaTeX PDF export; MiKTeX PATH injected on Windows
ImageMagick Optional Linux image conversion; deb dependency
LibreOffice Optional Enhanced document conversion; deb dependency

Development Commands

npm run dev                # Start dev mode: Vite dev server (port 5173) + Electron (concurrently)
npm run dev:renderer       # Vite dev server only (port 5173)
npm run dev:electron       # Electron only (waits for Vite on tcp:5173)
npm start                  # Launch Electron app (prod mode, requires built renderer)
npm run preview            # Build renderer then launch Electron
npm test                   # Jest — main process tests (vanilla JS)
npm run test:renderer      # Vitest — renderer tests (React/TS)
npm run lint               # ESLint check
npm run lint:fix           # ESLint auto-fix
npm run format             # Prettier write
npm run format:check       # Prettier check
npm run download-tools     # Download Pandoc binaries
npm run generate-icons     # Generate app icons

Dev workflow: npm run dev starts Vite (renderer HMR on :5173) and Electron concurrently. The main process loads from http://localhost:5173 in dev mode.

Build & Package

Two-stage build process:

  1. npm run build:renderer — Vite builds renderer to dist/renderer/
  2. npm run build — electron-builder packages main process + preload + built renderer

Tool: electron-builder (v26.0.12), config inline in package.json.

Target Platforms
npm run build:win Windows: NSIS + portable + zip (x64)
npm run build:mac macOS: dmg + zip (x64 + arm64)
npm run build:linux Linux: deb + AppImage + snap

Packaged files: src/main/**, src/preload.js, src/plugins/**, package.json. Renderer built output copied to resources as renderer/.

Bundled with builds: Pandoc binary per platform, FFmpeg (asarUnpacked).

Output: dist/ directory.

Auto-updater: electron-updater with GitHub Releases (default) and optional ConcreteInfo self-hosted feed.

CI: GitHub Actions workflows in .github/workflows/ (ci.yml, release.yml).

Project Conventions / Gotchas

  • Dual-process architecture. Main process is vanilla CommonJS JavaScript (src/main/). Renderer is React 19 + TypeScript + Tailwind (src/renderer/). They are separate build targets.
  • Vite for renderer only. Main process is NOT bundled — Electron loads src/main/index.js directly. Do not add TypeScript to main process files.
  • Tailwind + shadcn/ui. Use shadcn/ui components (src/renderer/components/ui/) for all UI primitives. Custom theme in tailwind.config.js. Path alias @ maps to src/renderer/. Brand color: #e5461f.
  • Zustand for state. All renderer state lives in src/renderer/stores/. Each store is a separate file. Use immer for immutable updates.
  • Typed IPC. src/renderer/types/electron.d.ts declares window.electronAPI. src/renderer/lib/ipc.ts provides type-safe wrappers. When adding new IPC channels, update both the preload whitelist AND the TypeScript declarations.
  • Legacy + new sidebar. src/sidebar/*.js (vanilla JS) and src/renderer/components/sidebar/ (React TSX) both exist. New sidebar features go in the React version.
  • Pandoc is external. Must be present for non-HTML/PDF exports. Download via npm run download-tools or install system-wide.
  • PDF export fallback chain: xelatex -> pdflatex -> lualatex -> Electron built-in printToPDF().
  • PDF rendering: pdfjs-dist (viewer). PDF manipulation: pdf-lib in main process.
  • Editor: CodeMirror 6, configured in src/editor/codemirror-setup.js, wrapped as React component in src/renderer/components/editor/CodeMirrorEditor.tsx.
  • Tests: Jest (main process, tests/**/*.test.js, 15% threshold) + Vitest (renderer, tests/**/*.{test,spec}.{ts,tsx}, v8 coverage on src/renderer/).
  • ESLint flat config with ECMAScript 2022. Prettier: 2-space, single quotes, semicolons, 100-char width.
  • No tsconfig.json at root — TypeScript is renderer-only, handled by Vite. Do not add tsconfig.json for the main process.
  • File associations: .md, .markdown, .pdf registered at install.
  • Single instance lock via app.requestSingleInstanceLock().