A markdown file viewer that doesn't feel like a Word doc or like an IDE. Just a quiet place to read .md files, with Mermaid graphs that actually work and code highlighting that doesn't hurt your eyes.
Cross-platform desktop app built with Tauri v2, so it ships as a native ~10 MB binary that starts instantly on macOS, Windows and Linux.
- Open
.md/.markdown/.mdxfiles via native dialog or drag-and-drop on the window - GitHub Flavored Markdown rendering: tables, task lists, strikethrough, autolinks, footnotes
- Live Mermaid graphs: flowcharts, sequence, class, ER, gantt, journey, C4, state, gitGraph
- Syntax highlighting via highlight.js
- In-document search (
Cmd/Ctrl+F): case-insensitive, current/total counter, Enter / Shift+Enter to navigate, Esc to close - Light / dark toggle, theme persisted to local storage
- Read / edit toggle with split-pane live preview
- Direct save or Save As (toolbar button)
- Keyboard shortcuts:
Cmd/Ctrl+Oopen,Cmd/Ctrl+Ssave,Cmd/Ctrl+Etoggle edit,Cmd/Ctrl+Ffind,Cmd/Ctrl+Dtoggle theme
| Layer | Choice |
|---|---|
| Desktop shell | Tauri v2 |
| Backend | Rust 1.95 + tauri-plugin-fs/dialog |
| Frontend | Vite 5 + React 18 + TypeScript 5.6 |
| Markdown engine | react-markdown + remark-gfm |
| Code highlight | rehype-highlight (highlight.js 11) |
| Diagrams | mermaid 11 |
| Styling | Tailwind v3 + custom CSS variables |
| Icons | @phosphor-icons/react |
Prerequisites:
- Node 18+ and npm
- Rust stable (
rustuprecommended) - macOS: Xcode Command Line Tools
git clone <repo> mdora && cd mdora
npm installnpm run tauri devThis starts Vite on localhost:1420 and opens a Tauri window pointing to it. Frontend hot-reloads, Rust recompiles automatically on change.
npm run tauri buildGenerates a macOS .app and .dmg, a Windows .exe, or a Linux AppImage depending on the platform. For just the raw binary without the installer:
npm run tauri build -- --no-bundleThe binary lands in src-tauri/target/release/mdora (~10 MB).
mdora/
├── src/
│ ├── App.tsx Shell, toolbar, shortcuts, search
│ ├── components/
│ │ ├── MarkdownView.tsx Markdown rendering pipeline
│ │ ├── MermaidBlock.tsx Mermaid render + theme reactivity
│ │ ├── SearchBar.tsx Find-in-document overlay
│ │ └── EmptyState.tsx Welcome screen
│ ├── styles.css Theme tokens + prose CSS + search highlights
│ └── main.tsx
├── src-tauri/
│ ├── src/
│ │ ├── lib.rs Tauri builder + native menu
│ │ └── main.rs
│ ├── capabilities/
│ │ └── default.json ACL: dialog + scoped fs
│ ├── icons/
│ │ ├── source/ SVG + 1024px master, regenerate platform set with `npx tauri icon`
│ │ └── ... generated PNG / ICO / ICNS / iOS / Android assets
│ ├── tauri.conf.json
│ └── Cargo.toml
├── tailwind.config.js
└── vite.config.ts
Mermaid runs with securityLevel: "strict" and the rendered SVG is parsed in an isolated document via DOMParser before being attached to the live tree, so a malicious .md file cannot inject script through node labels, tooltips, or foreignObject. react-markdown is configured without rehype-raw so raw HTML inside markdown is rendered as text, not live DOM. A strict Content-Security-Policy is enforced at the Tauri level (default-src 'self', no remote connect-src).
Mermaid is re-initialized on every theme switch so existing SVGs are regenerated with the right palette. Mermaid blocks are identified by the ```mermaid fence, so you can freely mix code and diagrams in the same document.
In-document search uses the CSS Custom Highlight API (CSS.highlights + Highlight ranges) instead of mutating the DOM. No fight with React's reconciler, no extra wrapper elements injected into the rendered Markdown. Requires WebKit 17.2+ / Chromium 105+, which is well within Tauri's modern WebView baseline.
The filesystem scope is limited to paths the user explicitly picks via the open / save dialog (Tauri grants ephemeral scopes for those). The static fs:scope is intentionally empty so a malicious .md file cannot reach anything else. If you need to widen it, edit src-tauri/capabilities/default.json.
MIT. See LICENSE.