A fast, local-first markdown note-taking application built as a personal alternative to Inkdrop — with exactly the features you want, nothing more.
- Pure Markdown editor powered by CodeMirror with syntax highlighting, line numbers, and custom keybindings
- Live preview with math (KaTeX), syntax highlighting (highlight.js), GFM tables, task lists, and local image support
- Synchronized scrolling between editor and preview in split mode
- Notebooks with nested hierarchy (notebooks inside notebooks) and a tree view in the sidebar
- Tags with color support, filterable from the sidebar
- Pinned notes section for quick access
- Full-text search powered by SQLite FTS5
- Interactive checkboxes — clickable in both editor and preview
- Custom title bar with minimize, maximize, and close controls (no native decorations)
- Last opened note restored on relaunch via persistent storage
- Trash with restore and permanent delete
- Sort notes by title, creation date, or last updated
- Context menu on notes (rename, pin/unpin, trash)
- Keyboard shortcuts centralized and CodeMirror-aware
- Dark / Light theme toggle
- Animated UI with smooth transitions on sidebar and note list
| Layer | Technology |
|---|---|
| Framework | Tauri v2 |
| Frontend | SolidJS + TypeScript |
| Styling | Tailwind CSS v4 |
| Build tool | Vite |
| Package manager | Bun |
| Database | SQLite via rusqlite (bundled) |
| Editor | CodeMirror 6 |
| Markdown | remark / rehype ecosystem |
| Animations | solid-motionone + solid-transition-group |
boundnotes/
├── src/ # Frontend (SolidJS)
│ ├── components/
│ │ ├── layout/
│ │ │ ├── Sidebar.tsx # Notebooks, tags, navigation
│ │ │ ├── NoteList.tsx # Note list with search and sort
│ │ │ ├── MainPanel.tsx # Editor + preview panel
│ │ │ └── TitleBar.tsx # Custom window controls
│ │ ├── editor/
│ │ │ ├── MarkdownEditor.tsx # CodeMirror editor
│ │ │ └── MarkdownPreview.tsx # Remark/rehype renderer
│ │ ├── modals/ # Modal Components
│ │ └── ui/ # Reusable UI components
│ ├── stores/
│ │ ├── notesStore.ts # Notes, notebooks, tags state
│ │ └── uiStore.ts # UI state (theme, sidebar, editor mode)
│ ├── hooks/
│ │ ├── useAutoSave.ts # Debounced auto-save (800ms)
│ │ └── useKeyboardShortcuts.ts # Global shortcut manager
│ ├── lib/
│ │ ├── tauri.ts # Typed Tauri invoke wrappers
│ │ ├── persistence.ts # Last note persistence via plugin-store
│ │ ├── notebookTree.ts # Flat → tree structure builder
│ │ └── citation.ts # Random citations
│ ├── styles/ # Styles container
│ ├── utils/
│ │ ├── rehypePlugins.ts # Custom rehype plugins
│ │ ├── codemirrorPlugins.ts # Custom CodeMirror plugins
│ │ ├── colorTag.ts # Random color tag
│ │ └── keymapCodeMirror.ts # Custom CodeMirror keybindings
│ └── types/
│ └── index.ts # Shared TypeScript types
│
└── src-tauri/ # Backend (Rust)
├── src/
│ ├── lib.rs # Tauri builder + plugin setup
│ ├── error.rs # AppError with thiserror
│ ├── db/
│ │ ├── mod.rs # SQLite pool initialization
│ │ └── migrations.rs # Schema versioning system
│ ├── models/
│ │ ├── note.rs
│ │ ├── notebook.rs
│ │ └── tag.rs
│ └── commands/
│ ├── notes.rs # CRUD + FTS5 search
│ ├── notebooks.rs # Nested notebooks CRUD
│ └── tags.rs # Tags + note-tag relations
└── Cargo.toml
SQLite with WAL mode, FTS5 full-text search, and a migration versioning system.
notes — metadata (title, excerpt, word_count, is_pinned, is_trashed...)
note_contents — content separated for performance (loaded only when a note is opened)
notebooks — hierarchical via parent_id
tags — with color and position
note_tags — many-to-many relation
notes_fts — FTS5 virtual table with auto-sync triggers
schema_migrations — version tracking
| Shortcut | Action |
|---|---|
Ctrl + B |
Toggle sidebar |
Ctrl + L |
Toggle note list |
Ctrl + N |
New note |
Ctrl + Shift + E |
Editor mode |
Ctrl + Shift + P |
Preview mode |
Ctrl + Shift + S |
Split mode |
Ctrl + Delete |
Trash active note |
Ctrl + , |
Show shortcuts panel |
Ctrl + B |
Bold (in editor) |
Ctrl + I |
Italic (in editor) |
Ctrl + 1-4 |
Heading 1–4 (in editor) |
Ctrl + K |
Insert link (in editor) |
Ctrl + E |
Inline code (in editor) |
Ctrl + Alt + G |
Code block (in editor) |
- Bun >= 1.0
- Rust stable toolchain
- Tauri v2 prerequisites for your OS → tauri.app/start/prerequisites
# Install dependencies
bun install
# Start in development mode
bun run dev:tauri# Build for production
bun run build:tauriThe output binary will be in src-tauri/target/release/.
rusqlite over sqlx — sqlx's compile-time query verification requires a DATABASE_URL at build time and a cargo sqlx prepare step that adds friction. rusqlite with the bundled feature embeds SQLite directly in the binary with zero configuration.
SolidJS over React — Fine-grained reactivity without a virtual DOM makes it a natural fit for a Tauri app where startup time and memory usage matter. createStore with produce and reconcile enables surgical updates to the note list without full re-renders.
Content separated from metadata — note_contents is a separate table from notes. The note list only loads metadata (title, excerpt, word count, tags), and the full content is fetched only when a note is opened. This keeps the list fast regardless of note size.
FTS5 with triggers — Full-text search is maintained automatically via SQLite triggers on note_contents inserts, updates, and deletes. No manual index management needed.
Oxlint & Eslint - Format and search error in differents files.
MIT