Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ MarkDoc is a lightweight, cross-platform desktop application for **viewing** Mar
- `tauri-plugin-opener` — External links
- `tauri-plugin-os` — OS/theme detection
- `tauri-plugin-single-instance` — Routes second-instance file-open requests into the live process
- `tauri-plugin-clipboard-manager` — Clipboard read (New from Clipboard); accessed Rust-side only, no frontend capability

## Versioning and Build Numbers

Expand Down Expand Up @@ -67,14 +68,14 @@ When recents change, the frontend calls `invoke('refresh_menus', { recents })` s

Built in `src-tauri/src/lib.rs::build_menu()` using Tauri's MenuBuilder API.

| Menu | Items |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **MarkDoc** (macOS) | About, Services, Hide / Hide Others / Show All, Quit |
| **File** | Open… (⌘O), Open Recent ▸ _(dynamic)_, Close Window (⌘W), Export ▸ (HTML ⌘⇧H, PDF ⌘⇧P) |
| **Edit** | Copy, Select All (native roles only) |
| **View** | Zoom In / Out / Actual Size, Theme ▸ (Default / Cobalt / Sage / Amber / Slate), Toggle Sidebar (⌘\\), Toggle Auto-resize |
| **Window** | Minimize, Maximize, _(dynamic list of open file windows)_ |
| **Help** | User Guide |
| Menu | Items |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **MarkDoc** (macOS) | About, Services, Hide / Hide Others / Show All, Quit |
| **File** | New from Clipboard… (⌘N), Open… (⌘O), Open Recent ▸ _(dynamic)_, Reveal in Finder _(platform label)_, Close Window (⌘W), Export ▸ (HTML ⌘⇧H, PDF ⌘⇧P) |
| **Edit** | Copy, Select All (native roles only) |
| **View** | Zoom In / Out / Actual Size, Theme ▸ (Default / Cobalt / Sage / Amber / Slate), Toggle Sidebar (⌘\\), Toggle Auto-resize |
| **Window** | Minimize, Maximize, _(dynamic list of open file windows)_ |
| **Help** | User Guide |

Menu items emit `menu://<area>/<action>` events that the React windows subscribe to. Window-menu clicks call `set_focus()` directly on the target window.

Expand All @@ -95,6 +96,9 @@ Kept minimal. See `src-tauri/src/lib.rs`.
- `close_file_window(label)` — destroy a window by label.
- `refresh_menus(recents)` — frontend→backend sync for Open Recent submenu.
- `get_file_modified_time(path)` — millis since epoch; used for external-change detection.
- `read_clipboard_text()` — OS clipboard as plain text (`""` when empty/non-text). Backs the New-from-Clipboard flow.
- `write_text_file(path, contents)` — Rust-side write mirroring `read_file_as_text` (paths are user-authorised via the save dialog, so no fs-plugin write scopes are advertised).
- `reveal_in_dir(path)` — reveal a file in Finder / Explorer / file manager via the opener plugin.
- `export_html_command`, `export_pdf_command`, `cancel_export` — export flow driven by `src-tauri/src/export.rs` (PDF goes through `headless_chrome`).

### Window registry (Rust)
Expand Down Expand Up @@ -155,6 +159,7 @@ markdoc/
│ │ └── usePreferences.ts # Global prefs (localStorage-backed)
│ ├── utils/
│ │ ├── openFileInWindow.ts # Central file-open router
│ │ ├── newFileFromClipboard.ts # Clipboard → save dialog → open flow
│ │ ├── recentFiles.ts # Recents store + native-menu sync
│ │ ├── pdfExport.ts # HTML generation for PDF export
│ │ ├── linkHandler.ts # External link routing + XSS guards
Expand Down Expand Up @@ -265,9 +270,9 @@ git tag v0.1.6 && git push origin main --tags

### Agent / UI testing workflow

The app ships a **web-mode** harness for fast UI e2e without Tauri. `npm run dev:web` swaps in `src/platform/web.ts` — a full in-memory `MockBackend` that records invoke calls and emits events. The mock handles `open_file_in_window`, `list_open_file_windows`, `get_app_version`, `export_html_command`, `refresh_menus`, and the theme/zoom/sidebar event bus.
The app ships a **web-mode** harness for fast UI e2e without Tauri. `npm run dev:web` swaps in `src/platform/web.ts` — a full in-memory `MockBackend` that records invoke calls and emits events. The mock handles `open_file_in_window`, `list_open_file_windows`, `get_app_version`, `export_html_command`, `refresh_menus`, `read_clipboard_text` (seed via `backend.clipboardText`), `write_text_file`, `reveal_in_dir`, and the theme/zoom/sidebar event bus. Message dialogs are recorded in `backend.calls` as `message_dialog` entries.

Stable `data-testid` selectors are present across Welcome (`welcome-root`, `welcome-open-button`, `welcome-recent-item`, …) and Viewer (`viewer-root`, `viewer-toolbar`, `viewer-zoom-in`, `viewer-theme-select`, `viewer-help-button`, …).
Stable `data-testid` selectors are present across Welcome (`welcome-root`, `welcome-open-button`, `welcome-new-from-clipboard`, `welcome-recent-item`, …) and Viewer (`viewer-root`, `viewer-toolbar`, `viewer-zoom-in`, `viewer-theme-select`, `viewer-reveal-button`, `viewer-help-button`, …).

Drive menu events from Playwright via:

Expand All @@ -283,14 +288,16 @@ const calls = await page.evaluate(() => window.__MARKDOC_MOCK__?.backend.calls);

### Test coverage

- **Unit (Vitest)** — 93 tests across 9 files. `src/hooks` 99% lines, `src/utils` 96% lines.
- **E2E (Playwright)** — 16 tests across 8 specs (welcome, viewer-open, theme, zoom, sidebar, export, help, autoresize).
- **Unit (Vitest)** — 107 tests across 10 files. `src/hooks` 99% lines, `src/utils` 96% lines.
- **E2E (Playwright)** — 22 tests across 10 specs (welcome, viewer-open, theme, zoom, sidebar, export, help, autoresize, new-from-clipboard, reveal).
- **Rust** — 10 tests in `window_registry` covering register/lookup/release/canonical-path collapsing.

### Pre-release smoke checklist

- [ ] Fresh launch shows Welcome with empty or persisted recents
- [ ] Welcome "Open File…" transitions the same window into viewer mode
- [ ] "New from Clipboard" (⌘N / welcome button) suggests a filename from the content, saves, and opens the file; empty clipboard shows an info dialog
- [ ] File > Reveal in Finder (and the viewer toolbar folder icon) selects the open file in the OS file manager; hidden/no-op for the user guide
- [ ] Opening a second file spawns a new `viewer-<N>` window
- [ ] Opening an already-open file focuses the existing window
- [ ] File > Open via Cmd+O works from both Welcome and Viewer
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ A lightweight, cross-platform desktop application for **viewing** Markdown files
- **Welcome screen**
- Shown when the app launches with no file, or when you open the app with no arguments via the dock/taskbar.
- Lists recent files (up to 20) with title + path, click-to-open, remove-one, and clear-all.
- "Open File…" and "Help" actions alongside the current version + build-hash.
- "Open File…", "New from Clipboard", and "User Guide" actions alongside the current version + build-hash.

- **New from Clipboard** (`Cmd/Ctrl+N`)
- Saves the clipboard's text as a new Markdown file and opens it in a window.
- Suggests a filename from the first heading (or first line) of the content.

- **Reveal in file manager**
- File → Reveal in Finder / Show in File Explorer (or the toolbar folder icon) selects the open file in the OS file manager.

- **Native experience**
- True native menus (File, Edit, View, Window, Help — plus the MarkDoc app menu on macOS).
Expand Down Expand Up @@ -107,6 +114,7 @@ chmod +x MarkDoc_*.AppImage

### Keyboard shortcuts

- `Cmd/Ctrl+N` — New from Clipboard
- `Cmd/Ctrl+O` — Open file
- `Cmd/Ctrl+W` — Close window
- `Cmd/Ctrl+Shift+H` — Export to HTML
Expand All @@ -118,7 +126,7 @@ chmod +x MarkDoc_*.AppImage

### Menus

**File** — Open…, Open Recent ▸ _(dynamic)_, Close Window, Export ▸ (HTML / PDF)
**File** — New from Clipboard…, Open…, Open Recent ▸ _(dynamic)_, Reveal in Finder _(platform label)_, Close Window, Export ▸ (HTML / PDF)

**Edit** — Copy, Select All (native roles)

Expand Down
Loading
Loading