# maCopy A lightweight macOS clipboard manager that lives in your menu bar. Built with Tauri 2, React, TypeScript, and SQLite. ![macOS](https://img.shields.io/badge/macOS-10.15+-black?logo=apple) ![Tauri](https://img.shields.io/badge/Tauri-2-blue?logo=tauri) ![License](https://img.shields.io/badge/license-MIT-green) ## Features - **Menu bar app** — no dock icon, stays out of your way - **Global hotkey** — `Cmd+Shift+V` opens 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+1` through `Cmd+9` to 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](https://rustup.rs) - **Node.js** 18+ and npm - **Xcode Command Line Tools** — `xcode-select --install` ## Quick Start ```bash git clone 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](https://v2.tauri.app) | | Frontend | React 18, TypeScript, Tailwind CSS v4 | | Backend | Rust, rusqlite (bundled SQLite) | | Clipboard | [arboard](https://crates.io/crates/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) ```bash 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) ```bash 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 ```bash npm run test:all ``` ## Building for Release ```bash npm run tauri build ``` The built `.app` bundle will be in `src-tauri/target/release/bundle/macos/`. ## License MIT