74 lines
3.7 KiB
Markdown
74 lines
3.7 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
## Commands
|
||
|
||
```bash
|
||
npm start # Run the Electron app in development
|
||
npm run build # Build macOS app bundle (no DMG, arm64 + x64)
|
||
npm run dist # Build and package as DMG for distribution
|
||
./setup.sh # First-time setup: npm install + npm start
|
||
```
|
||
|
||
There are no tests or linting configured.
|
||
|
||
## Architecture
|
||
|
||
This is a macOS Electron desktop app for batch-renaming photo files. It follows strict Electron security practices: `contextIsolation: true`, `nodeIntegration: false`.
|
||
|
||
**Process boundary:** All filesystem access lives exclusively in `src/main/` (main process). The renderer never touches `fs` directly.
|
||
|
||
### File structure
|
||
|
||
```
|
||
src/
|
||
├── main/
|
||
│ ├── index.js # Main process entry point; creates BrowserWindow, calls registerAll()
|
||
│ └── ipc/
|
||
│ ├── index.js # registerAll(mainWindow) — delegates to folder and files modules
|
||
│ ├── folder.js # select-folder, reveal-folder
|
||
│ └── files.js # list-images, read-image, rename-files
|
||
├── preload/
|
||
│ └── index.js # Bridges IPC to window.api via contextBridge (isolated context)
|
||
└── renderer/
|
||
├── index.html # App shell (dark theme, CSS variables in :root)
|
||
├── style.css # All CSS
|
||
├── renderer.js # Main renderer logic; imports state and handlers
|
||
├── state.js # Shared mutable state: files[], currentFolder, selectedIdxs, sortMode
|
||
└── handlers/
|
||
├── drag-drop.js # Card drag-and-drop reorder (single and multi-card)
|
||
├── selection.js # Rubber-band selection, Shift-click, Cmd+click
|
||
├── pinch-zoom.js # Trackpad pinch to resize thumbnails (CSS --thumb-size, 150–400px)
|
||
└── hover-preview.js # Hover preview overlay
|
||
```
|
||
|
||
### IPC surface
|
||
|
||
Defined in `src/main/ipc/`, bridged via `src/preload/index.js` as `window.api`:
|
||
|
||
| Channel | Direction | Description |
|
||
|---|---|---|
|
||
| `select-folder` | invoke | Opens native folder picker, returns path or null |
|
||
| `list-images` | invoke | Reads directory, returns `{name, path, mtime, size}[]` filtered to image extensions, sorted by filename |
|
||
| `read-image` | invoke | Reads file, returns base64 data URL for display |
|
||
| `rename-files({folderPath, files, prefix, digits})` | invoke | Two-phase rename: temp names first, then final names to avoid collisions |
|
||
| `reveal-folder` | invoke | Opens folder in Finder via `shell.openPath` |
|
||
| `fullscreen-change` | push (main→renderer) | Sent on `enter-full-screen` / `leave-full-screen` window events |
|
||
|
||
### Renderer (`src/renderer/`)
|
||
|
||
Uses ES module imports (`type="module"`). No framework.
|
||
|
||
**State** (`src/renderer/state.js`):
|
||
- `files[]` — ordered array of file objects; order determines rename sequence
|
||
- `selectedIdxs` — `Set<number>` of selected card indices
|
||
- `currentFolder` — active directory path
|
||
- `sortMode` — `'name'` | `'date'` | `null`
|
||
|
||
**Thumbnail loading:** Uses `IntersectionObserver` with `rootMargin: '400px 0px'` — images load lazily as cards enter the viewport. DOM card elements are created immediately without `src`; the observer fills in `img.src` on entry. Drag-and-drop reorder remaps existing card elements via `card.dataset.filepath` to avoid re-fetching images.
|
||
|
||
**Styling:** All CSS lives in `src/renderer/index.html`. Dark theme with CSS variables defined in `:root`. The macOS traffic-light buttons sit in `#titlebar` with `-webkit-app-region: drag`.
|
||
|
||
**Build output:** `electron-builder` targets DMG for arm64 and x64. The app icon must be at `assets/icon.icns`.
|