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>
45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
import type { ClipboardEntry } from "../types";
|
|
|
|
interface Props {
|
|
x: number;
|
|
y: number;
|
|
entry: ClipboardEntry;
|
|
onCopy: () => void;
|
|
onPin: () => void;
|
|
onDelete: () => void;
|
|
}
|
|
|
|
export default function ContextMenu({ x, y, entry, onCopy, onPin, onDelete }: Props) {
|
|
// Prevent the menu from going off-screen
|
|
const adjustedX = Math.min(x, window.innerWidth - 160);
|
|
const adjustedY = Math.min(y, window.innerHeight - 120);
|
|
|
|
return (
|
|
<div
|
|
className="fixed z-50 bg-surface border border-border rounded-lg shadow-xl py-1 min-w-[150px]"
|
|
style={{ left: adjustedX, top: adjustedY }}
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
<button
|
|
className="w-full text-left px-3 py-1.5 text-sm text-text-primary hover:bg-surface-hover transition-colors"
|
|
onClick={onCopy}
|
|
>
|
|
Copy
|
|
</button>
|
|
<button
|
|
className="w-full text-left px-3 py-1.5 text-sm text-text-primary hover:bg-surface-hover transition-colors"
|
|
onClick={onPin}
|
|
>
|
|
{entry.pinned ? "Unpin" : "Pin"}
|
|
</button>
|
|
<div className="border-t border-border my-1" />
|
|
<button
|
|
className="w-full text-left px-3 py-1.5 text-sm text-danger hover:bg-surface-hover transition-colors"
|
|
onClick={onDelete}
|
|
>
|
|
Delete
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|