ilia f62c1d6ba7
CI / skip-ci-check (push) Successful in 4s
CI / secret-scan (push) Successful in 3s
CI / node-ci (push) Successful in 22s
Merge pull request 'Tray icon, click fix, and Settings gear' (#13) from feature/tray-icon-settings-gear into main
2026-09-04 21:05:14 -05:00

maCopy

macOS clipboard manager in the menu bar. Built with Tauri 2, React, TypeScript, and SQLite.

macOS Tauri License

Features

Area Behavior
Menu bar No dock icon; tray glyph is a clipboard with ∞
Global hotkey Ctrl+` opens the window (does not steal macOS Cmd+` window-cycle); configurable in Settings
Clipboard monitoring Watches pasteboard changeCount; captures text, images, and file paths
List performance Truncated previews in list API; image blobs stay in SQLite until paste
Search Full-text filtering via SQLite FTS5
Quick paste Cmd+1 through Cmd+9 paste the Nth item into the previous app
Paste and return Click copies, hides window, auto-pastes into the previously focused app
Multi-select Cmd+Click toggle; Shift+Arrow or Shift+Click range; Cmd+A all; Enter to paste
Pin Pinned items stay at top and skip auto-delete
Context menu Right-click: Paste, Pin/Unpin, Delete (multi-select aware)
Window Resizable; size remembered; position: near cursor, center, or corner
Auto-trim Up to 50K entries (1K/5K/10K/50K); skips oversized images
Appearance Dark/light follows macOS
Privacy Ignores whitespace-only entries; redacts password/card previews; pause monitoring from tray
Transforms Option-click or right-click: plain text, trim, case, JSON, etc.
Copy only Right-click Copy puts content on clipboard without auto-paste
Color swatches Hex/rgb/hsl entries show a color chip in the list
Launch at login Settings toggle registers a macOS Login Item
Image thumbnails Small thumbs in list; full image loaded on paste

Docs

Doc
docs/GUIDE.md Install and usage guide — start here to use the app
docs/README.md Docs index
docs/TESTING.md Automated tests
docs/LAUNCH-AT-LOGIN.md Start when Mac logs in
docs/PRODUCT.md Professional / shipping checklist
docs/SHARING.md Where the app lives + how to share it with others
CHANGELOG.md Version history
ROADMAP.md Next features + brainstorm
  • macOS 10.15+
  • Rust 1.77+ — install via rustup
  • Node.js 18+ and npm
  • Xcode Command Line Toolsxcode-select --install
  • Accessibility permission — required for auto-paste (System Settings → Privacy & Security → Accessibility → add maCopy)

Quick start

git clone gitea@git.levkin.ca:ilia/maCopy.git
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.

Usage

Action How
Open/close window Click tray icon or press Ctrl+` (configurable in Settings)
Paste an entry Click it, or press Enter
Paste plain (no formatting) /Alt+click, or right-click → Paste plain
Copy without pasting Right-click → Copy
Transforms Right-click → Transform (trim, case, JSON, …)
Quick paste Cmd+1 through Cmd+9
Search Just start typing
Select multiple Cmd+Click or Shift+Arrow
Select all Cmd+A
Delete Backspace or Delete (on selected items)
Pin/unpin Right-click → Pin/Unpin
Settings Tray icon → Settings…
Change hotkey Settings → Global hotkey → press new shortcut
Launch at login Settings → Launch at login (see docs/LAUNCH-AT-LOGIN.md)
Dismiss Escape or click outside

Development

Project structure

maCopy/
├── src/                        # React + TypeScript frontend
│   ├── main.tsx                # Entry point
│   ├── App.tsx                 # Main app: state, keyboard nav, multi-select
│   ├── App.test.tsx            # App integration tests
│   ├── index.css               # Tailwind v4 + custom theme tokens
│   ├── types.ts                # Shared TypeScript interfaces
│   ├── test/                   # Test setup and factories
│   │   ├── setup.ts            # Tauri API mocks for jsdom
│   │   └── factories.ts        # makeEntry(), makeSettings()
│   └── components/
│       ├── SearchBar.tsx
│       ├── ClipboardList.tsx   # Entry list with multi-select, type badges
│       ├── ContextMenu.tsx     # Right-click menu with multi-select labels
│       └── SettingsPanel.tsx   # Toggles, max history, window position
├── 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 management
│       ├── clipboard.rs        # Background polling thread (500ms, SHA-256 dedup)
│       ├── db.rs               # SQLite CRUD + FTS5 + settings + auto-trim
│       └── commands.rs         # Tauri IPC commands
├── .cursor/rules/              # Cursor AI rules for this project
├── package.json
├── vite.config.ts
├── vitest.config.ts
└── tsconfig.json

Scripts

Command Description
npm run tauri dev Run in development mode with hot reload
npm run tauri build Build a release .app bundle
npm test Run frontend tests (Vitest, ~72 tests)
npm run test:rust Run Rust backend tests (~67 tests)
npm run test:all Run all tests (frontend + backend)
npm run lint TypeScript type-check
npm run check Lint + all tests

Tech stack

Layer Technology
Framework Tauri 2
Frontend React 18, TypeScript, Tailwind CSS v4
Backend Rust, rusqlite (bundled SQLite)
Clipboard arboard for system clipboard access
Mouse position core-graphics for global cursor coordinates
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 monitoring

A background Rust thread watches the macOS pasteboard changeCount and only reads the clipboard when it changes. Text, images (full PNG + thumbnail), and file paths are captured. List IPC returns truncated / redacted previews and image thumbnails — not multiMB blobs.

Paste and return

When you select an entry, maCopy writes it to the system clipboard (text or image), hides its window, waits briefly for macOS to refocus the previous app, then simulates Cmd+V via AppleScript. This requires Accessibility permission. Optional transforms (plain, trim, JSON, …) run before the write.

SQLite + FTS5

The database uses a content-synced FTS5 virtual table with triggers that automatically keep the full-text index in sync with the clipboard_entries table. This enables instant prefix search as you type. User queries are tokenized before MATCH so path punctuation (/…, .) does not trip FTS5 syntax. Opened with journal_mode=WAL + synchronous=NORMAL so the UI can read while the background poller writes, without blocking on full fsyncs.

Window behavior

The window uses titleBarStyle: "overlay" for native resize handles while keeping the frameless aesthetic. It's always-on-top and hides on blur (with a short delay so clicks register). Position is determined by the user's setting (near cursor via CoreGraphics, center, or a screen corner).

Data storage

The SQLite database is stored at:

~/Library/Application Support/maCopy/clipboard.db

Testing

See docs/TESTING.md for the full map.

npm test           # ~72 frontend tests
npm run test:rust  # ~67 Rust tests
npm run check      # lint + all tests (~139)

Building for Release

npm run tauri build

The built .app bundle will be in src-tauri/target/release/bundle/macos/.

Copy it to /Applications, then enable Launch at login in Settings — details in docs/LAUNCH-AT-LOGIN.md.

Roadmap & product readiness

License

MIT

S
Description
macOS menu-bar clipboard manager — Tauri 2, React, TypeScript
Readme MIT
927 KiB
v0.2.0
Latest
2026-07-14 21:13:22 -05:00
Languages
Rust 47.5%
TypeScript 45.7%
JavaScript 4%
Shell 1.7%
CSS 0.8%
Other 0.3%