Files
maCopy/README.md
T
ilia e9461ed4f3
CI / skip-ci-check (pull_request) Successful in 4s
CI / secret-scan (pull_request) Successful in 3s
CI / node-ci (pull_request) Successful in 17s
Add copy-only, color swatches, DB speed pragmas, and living docs
- Copy only (right-click -> Copy): write to clipboard without
  auto-pasting or hiding the window
- Color swatches: hex/rgb/hsl entries show a preview chip
- SQLite WAL + synchronous=NORMAL so the UI can read while the
  clipboard poller writes
- Memoize list rows (React.memo) so selection/focus changes don't
  re-render every row's preview
- Add docs/GUIDE.md (living install + usage doc), docs/SHARING.md,
  docs/TESTING.md, docs/LAUNCH-AT-LOGIN.md, docs/PRODUCT.md,
  CHANGELOG.md, ROADMAP.md
- Add homelab Gitea Actions CI (.gitea/workflows/ci.yml) + gitleaks
  allowlist
- Bump version to 0.2.0
2026-07-14 21:58:31 -04:00

198 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# maCopy
A fast, native 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** — `` Ctrl+` `` opens the window (doesnt steal macOS Cmd+` window-cycle); configurable in Settings
- **Clipboard monitoring** — watches the macOS pasteboard changeCount (no busy hashing while idle); captures text, images, and file paths
- **Fast picker** — list API returns truncated previews only (image blobs stay in SQLite until paste); refreshes on copy / window focus instead of reloading everything every second
- **Full-text search** — instant filtering via SQLite FTS5
- **Quick paste** — `Cmd+1` through `Cmd+9` to paste the Nth item directly into the previous app
- **Paste & return** — clicking an entry copies it to clipboard, hides the window, and auto-pastes into the previously-focused app
- **Multi-select** — `Cmd+Click` to toggle, `Shift+Arrow` or `Shift+Click` to range-select, `Cmd+A` for all, `Enter` to paste selected
- **Pin entries** — pinned items stay at the top and are never auto-deleted
- **Context menu** — right-click for Paste, Pin/Unpin, Delete (with multi-select support)
- **Resizable window** — drag edges to resize; size is remembered between sessions
- **Window positioning** — choose where the window appears: near cursor, center, or any corner (configurable in Settings)
- **Auto-trim** — keeps up to 50K entries (configurable: 1K/5K/10K/50K); oversized images are skipped
- **Dark/light mode** — follows macOS system appearance
- **Privacy** — whitespace-only entries are ignored; password/card/banking previews are redacted (full value still pastes); pause monitoring from the tray
- **Paste plain / transforms** — ⌥-click or right-click for plain text and transforms (trim, case, JSON, …)
- **Copy only** — right-click → Copy puts content on the clipboard without auto-pasting or hiding the window
- **Color swatches** — hex/rgb/hsl entries (e.g. `#3366ff`) show a small color chip in the list
- **Launch at login** — Settings toggle registers a macOS Login Item (use the built `.app`)
- **Image thumbnails** — list shows small thumbs; full images stay in the DB until paste
## Docs
| Doc | |
|---|---|
| [docs/GUIDE.md](docs/GUIDE.md) | **Install + usage guide** (the living doc — start here if you just want to use the app) |
| [docs/README.md](docs/README.md) | Docs index |
| [docs/TESTING.md](docs/TESTING.md) | Automated tests |
| [docs/LAUNCH-AT-LOGIN.md](docs/LAUNCH-AT-LOGIN.md) | Start when Mac logs in |
| [docs/PRODUCT.md](docs/PRODUCT.md) | Professional / shipping checklist |
| [docs/SHARING.md](docs/SHARING.md) | Where the app lives + how to share it with others |
| [CHANGELOG.md](CHANGELOG.md) | Version history |
| [ROADMAP.md](ROADMAP.md) | Next features + brainstorm |
- **macOS** 10.15+
- **Rust** 1.77+ — [install via rustup](https://rustup.rs)
- **Node.js** 18+ and npm
- **Xcode Command Line Tools** — `xcode-select --install`
- **Accessibility permission** — required for auto-paste (System Settings → Privacy & Security → Accessibility → add maCopy)
## Quick Start
```bash
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](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, ~60 tests) |
| `npm run test:rust` | Run Rust backend tests (~52 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](https://v2.tauri.app) |
| Frontend | React 18, TypeScript, Tailwind CSS v4 |
| Backend | Rust, rusqlite (bundled SQLite) |
| Clipboard | [arboard](https://crates.io/crates/arboard) for system clipboard access |
| Mouse position | [core-graphics](https://crates.io/crates/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 & 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. 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](docs/TESTING.md)** for the full map.
```bash
npm test # ~60 frontend tests
npm run test:rust # ~52 Rust tests
npm run check # lint + all tests (~112)
```
## Building for Release
```bash
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](docs/LAUNCH-AT-LOGIN.md).
## Roadmap & product readiness
- Feature backlog: [ROADMAP.md](ROADMAP.md)
- Professional shipping checklist: [docs/PRODUCT.md](docs/PRODUCT.md)
## License
MIT