Tauri 2 + React 18 + TypeScript + Tailwind CSS v4 + SQLite (rusqlite) Features: - Menu bar app with tray icon (no dock icon) - Global hotkey Cmd+Shift+V - Clipboard polling every 500ms (text, images, file paths) - SQLite FTS5 full-text search - Pin/unpin entries, auto-trim, context menu - Settings panel (launch at login, show images, max history, clear all) - Dark/light mode following macOS system preference - Frameless floating window, closes on blur Testing: - 27 Rust unit tests (db, clipboard, FTS5, trim, settings) - 31 TypeScript component tests (vitest + @testing-library/react) Co-authored-by: Cursor <cursoragent@cursor.com>
maCopy
A lightweight macOS clipboard manager that lives in your menu bar. Built with Tauri 2, React, TypeScript, and SQLite.
Features
- Menu bar app — no dock icon, stays out of your way
- Global hotkey —
Cmd+Shift+Vopens the window from anywhere - Clipboard monitoring — polls every 500ms for text, images, and file paths
- Full-text search — instant filtering via SQLite FTS5
- Quick paste —
Cmd+1throughCmd+9to paste the Nth item - Pin entries — pinned items stay at the top and are never auto-deleted
- Context menu — right-click for Copy, Pin/Unpin, Delete
- Auto-trim — keeps the last 500 entries by default (configurable: 100/500/1000)
- Dark/light mode — follows macOS system appearance
- Privacy — whitespace-only entries are ignored; pause monitoring from the tray
Prerequisites
- macOS 10.15+
- Rust 1.77+ — install via rustup
- Node.js 18+ and npm
- Xcode Command Line Tools —
xcode-select --install
Quick Start
git clone <your-repo-url> maCopy
cd maCopy
npm install
npm run tauri dev
The app will compile the Rust backend, start the Vite dev server, and launch the menu bar app.
Development
Project Structure
maCopy/
├── src/ # React + TypeScript frontend
│ ├── main.tsx # Entry point
│ ├── App.tsx # Main app: routing, keyboard nav, polling
│ ├── index.css # Tailwind v4 + custom theme tokens
│ ├── types.ts # Shared TypeScript types
│ ├── test/ # Test setup and factories
│ │ ├── setup.ts
│ │ └── factories.ts
│ └── components/
│ ├── SearchBar.tsx # Auto-focused search input
│ ├── ClipboardList.tsx # Entry list with time-ago, pin badges
│ ├── ContextMenu.tsx # Right-click: Copy / Pin / Delete
│ └── SettingsPanel.tsx # Toggles + max history + clear all
├── src-tauri/ # Rust backend
│ ├── Cargo.toml
│ ├── tauri.conf.json # Tauri config, permissions, window
│ └── src/
│ ├── main.rs # Binary entry point
│ ├── lib.rs # App setup: tray, hotkey, window behavior
│ ├── clipboard.rs # Background polling thread (500ms)
│ ├── db.rs # SQLite CRUD + FTS5 + auto-trim
│ └── commands.rs # Tauri IPC commands
├── package.json
├── vite.config.ts
├── vitest.config.ts
└── tsconfig.json
Scripts
| Command | Description |
|---|---|
npm run tauri dev |
Run the app in development mode with hot reload |
npm run tauri build |
Build a release .app bundle |
npm test |
Run frontend tests (vitest) |
npm run test:watch |
Run frontend tests in watch mode |
npm run test:rust |
Run Rust backend tests |
npm run test:all |
Run all tests (frontend + backend) |
Tech Stack
| Layer | Technology |
|---|---|
| Framework | Tauri 2 |
| Frontend | React 18, TypeScript, Tailwind CSS v4 |
| Backend | Rust, rusqlite (bundled SQLite) |
| Clipboard | arboard for cross-platform access |
| Search | SQLite FTS5 with content-sync triggers |
| Hotkey | tauri-plugin-global-shortcut |
| Autostart | tauri-plugin-autostart |
| Testing | vitest + @testing-library/react (frontend), cargo test (backend) |
Architecture
Clipboard Polling
A dedicated Rust thread polls the system clipboard every 500ms using the arboard crate. Each new clipboard value is hashed (SHA-256) and compared against the last known hash to avoid duplicates. Text, images (stored as base64 PNG data URIs), and file paths are all captured.
SQLite + FTS5
The database uses a content-synced FTS5 virtual table with triggers that automatically keep the full-text index in sync with the main clipboard_entries table. This enables instant prefix search as you type.
Window Behavior
The window is frameless, always-on-top, and hides when it loses focus — behaving like a native macOS popover. Clicking the tray icon or pressing Cmd+Shift+V toggles visibility.
Data Storage
The SQLite database is stored at:
~/Library/Application Support/maCopy/clipboard.db
Testing
Frontend (31 tests)
npm test
Tests cover all four UI components: SearchBar, ClipboardList, ContextMenu, and SettingsPanel. Tauri APIs are mocked so tests run in jsdom without the native runtime.
Backend (27 tests)
npm run test:rust
Tests use in-memory SQLite databases and cover: CRUD operations, FTS5 search, auto-trim with pin preservation, settings persistence, SHA-256 hashing, and PNG encoding.
All tests
npm run test:all
Building for Release
npm run tauri build
The built .app bundle will be in src-tauri/target/release/bundle/macos/.
License
MIT