Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e5f9f89
docs(design): terminal redesign direction, mockups, spec and plan
Maxaubert Oct 4, 2026
74d66d1
feat(main): dark window defaults, 1440x900 clamp, userData test hook,…
Maxaubert Oct 4, 2026
a8252ba
feat(engine): report remaining seconds from the estimated-progress ti…
Maxaubert Oct 4, 2026
e76b107
feat(engine): optional output folder with unchanged collision safety
Maxaubert Oct 4, 2026
7f88e68
feat(state): link sources to results, ordered range, selectIds, clear…
Maxaubert Oct 4, 2026
d3302a8
feat(queue): pure row model for result, status, actions and totals
Maxaubert Oct 4, 2026
6159d56
feat(queue): sort cycle, group-scoped select-all and table key map
Maxaubert Oct 4, 2026
580bc86
feat(shared): conservative output-size estimator with batch extrapola…
Maxaubert Oct 4, 2026
8c509c8
feat(theme): monochrome dark tokens, bundled IBM Plex, workbench CSS;…
Maxaubert Oct 4, 2026
a96f097
feat(ui): 16px stroke icon registry with typed icon names
Maxaubert Oct 4, 2026
e4802e6
feat(ui): monochrome primitives (buttons, select, segmented, chips, r…
Maxaubert Oct 4, 2026
21a4be2
feat(shell): title bar with breadcrumb, collapsible sidebar, status b…
Maxaubert Oct 4, 2026
19bd81c
feat(queue): details table with result arrow, compact progress, row a…
Maxaubert Oct 4, 2026
f84fe50
feat(inspector): grouped options per verb, estimate card, output loca…
Maxaubert Oct 4, 2026
53ea342
feat(inspector): preview wipe and info grid for the focused file
Maxaubert Oct 4, 2026
56eeb81
feat(views): generate, tools, completed and settings in the workbench…
Maxaubert Oct 4, 2026
2f20d02
refactor(ui): enforce strict monochrome, drop verb and group colours …
Maxaubert Oct 4, 2026
ccb90cd
test(e2e): scoped selectors, sidebar and inspector behaviour, redesig…
Maxaubert Oct 4, 2026
78787fc
test(unit): give each vitest worker its own userData root
Maxaubert Oct 4, 2026
351ec32
fix(ui): full-width location select, no false -100% saving
Maxaubert Oct 4, 2026
fc9f2b1
fix(ui): two-column style chips, full-width output path, hide empty t…
Maxaubert Oct 4, 2026
61feb81
Merge remote-tracking branch 'origin/main' into feat/22-terminal-rede…
Maxaubert Oct 4, 2026
0188380
chore: 0.5.0 and docs for the terminal redesign
Maxaubert Oct 4, 2026
7a12549
fix(ui): grey Add files button, no white selection bars, plain sideba…
Maxaubert Oct 4, 2026
56e33d7
docs(design): record post-build feedback
Maxaubert Oct 4, 2026
d186d3b
fix(ui): Add files uses the same toolbar button background as the others
Maxaubert Oct 4, 2026
236bf68
fix(ui): grey fills instead of white, rename Tools to PDF Tools, drop…
Maxaubert Oct 4, 2026
be0ef83
docs(design): record grey fills and PDF Tools feedback
Maxaubert Oct 4, 2026
f2d6fb0
feat(ui): Run becomes a red Stop while work runs; toolbar loses Retry…
Maxaubert Oct 4, 2026
3352b0b
feat(ui): right-click menu for file actions, single-file preview
Maxaubert Oct 4, 2026
13766ed
docs(design): record right-click menu and Stop rules
Maxaubert Oct 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 10 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ Remove BG / Generate / Tools, each owning one queue that may hold several
convert groups at once. A selection never spans two convert groups, because one
options panel can only describe one target set. See `src/shared/tabs.ts`.

**Signed-off redesign (2026-10-04):** `docs/mockups/terminal-v5/10-s2-vscode-grouped.html`, dark-only,
strict monochrome. Rules and feedback trail: `docs/design/redesign-direction.md`.

**The look is designed collaboratively with the owner. Make NO visual assumptions.**
Before building or restyling any UI, present mockups (self-contained browser HTML, like the
RCMM Show/Hide exploration), offer options, and iterate to explicit sign-off. This covers
layout, components, palette, typography, motion, empty/loading states, and the file-preview
experience. The current renderer is a deliberately plain placeholder until that design work
happens. Engineering/plumbing (main process, tool modules, IPC, tests, packaging) moves fast
experience. The renderer implements the signed-off terminal design (rules in
`docs/design/redesign-direction.md`): dark only, strict monochrome, every colour is a token in
`src/renderer/src/theme/tokens.css`, and `test/monochrome-source.test.ts` fails on any other colour
literal. New screens still go through mockups first. Engineering/plumbing (main process, tool modules, IPC, tests, packaging) moves fast
without design ceremony.

## Scope (v1, built in phases)
Expand Down Expand Up @@ -57,7 +62,9 @@ src/
(planned) output.ts collision-safe output naming (ported from RCMM Get-UniqueOutPath)
(planned) ipc.ts renderer <-> engine wiring
preload/ contextBridge — the typed `window.filesmith` API
renderer/ React UI (placeholder until designed)
renderer/ React UI: shell/ (title bar, sidebar, status bar), queue/ (files table),
inspector/ (Options, Preview, Info), options/ (one settings file per verb),
views/ (Generate, Tools, Completed, Settings), ui/ (primitives), icons/, theme/ (tokens, CSS)
shared/ types.ts — Job, ToolId, FileKind, Options, progress events
tabs.ts — the VERB-first navigation model (rail tabs + Tools cards)
resources/bin/ bundled CLI binaries (gitignored; fetched by scripts, packed by electron-builder)
Expand Down
34 changes: 34 additions & 0 deletions docs/design/redesign-direction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Redesign direction (owner feedback, 2026-10-04)

**LOCKED IN (2026-10-04): `docs/mockups/terminal-v5/10-s2-vscode-grouped.html`** is the target design.
Build the renderer to match it. The rest of this file is the feedback trail that led there.

Mockup rounds live in `docs/mockups/terminal*/` (each has an `index.html` gallery and `shots/`).

- **Dark only.** Light mode is being removed. Black or near-black background. Themes come later.
- **Strict monochrome.** Greys only (r=g=b). Errors use a glyph and weight, never red.
- **Round 1** (`terminal/`): rejected. Too cluttered, too much information, too colourful.
- **Round 2** (`terminal-v2/`): better, but too minimal. Wants icons on tabs and controls.
- **Round 3** (`terminal-v3/`): "more the look", but a straight copy of Wind's settings page. Do our own thing.
- **Round 4** (`terminal-v4/`): IDE-inspired (VS Code settings editor, JetBrains settings/tool windows, Zed,
Xcode). Keep round 3's density, icons everywhere, simple and easy to navigate.
- **Pick from round 4:** `terminal-v4/10-explorer-details` (details table + right inspector). Wanted changes:
left sidebar collapsible, expanded shows icon + label; no "Drop files here" row (files are added from the
top). Variations in `terminal-v5/`.
- **Pick from v5:** `terminal-v5/05-e-flush-panels` (flush, square, mono). Controls must clearly read as
buttons: plain words with an underline or dotted link styling were not obvious enough.
- Running rows: no progress line under the row. Show progress compactly as `62%(4s)`, not "about 4 s left",
in the status column.
- Result column: the arrow sits on the size/result split. Done = actual result, running = grey `~estimate`,
queued/failed = empty. The batch estimate shows in the right panel before you press Convert.
- Post-build feedback (2026-10-04): Add files is grey (not white); no white left bars on selected rows or the
active sidebar item; the active item's count is a plain number, not an inverted box. Add files has no fill,
like the other toolbar buttons. No white fills anywhere: selected segments, chips, checkboxes and the primary
button use grey `#2a2a2a` with light text (the `--inv-*` tokens). The Tools tab is "PDF Tools", with no
divider line above it.
- Files toolbar is only Add files + count. Row actions live in a right-click menu (Open, Show in File
Explorer, Retry, Stop, Clear finished, Remove from list, Delete); destructive ones confirm first. While work
runs, the run button becomes a red Stop (`--stop-*`, the app's one hue). Preview/Info show nothing for a
multi-selection ("Select one file to preview").
- Wind is a reference, not a template. Avoid its signatures: the floating progress+button pill, the icon-tile
header band, and big rounded cards of right-aligned setting rows.
174 changes: 174 additions & 0 deletions docs/mockups/terminal-v2/01-wind-plain.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
<!doctype html>
<!--
Filesmith round 2, mockup 01: "Wind, plain"
Wind's Settings shell with nothing extra added. A left rail, a title, four lines
and one white pill. It looks like Wind's sibling app.
-->
<html lang="en">
<head>
<meta charset="utf-8">
<title>Filesmith</title>
<style>
:root {
--bg: #000;
--line: #151515;
--fg: #f2f2f2;
--fg2: #d0d0d0;
--fg3: #8f8f8f;
--glyph: #b0b0b0;
--hover: #121212;
--pill: #1d1d1d;
--track: #303030;
--s: "Segoe UI Variable", "Segoe UI", system-ui, sans-serif;
--m: "Cascadia Mono", Consolas, monospace;
--ease: cubic-bezier(.2,.7,.2,1);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { background: #000; }
body {
width: 1440px; height: 900px; overflow: hidden;
color: var(--fg); font: 13px/1.4 var(--s);
-webkit-font-smoothing: antialiased;
}
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; }

/* window chrome */
.bar {
height: 38px; display: flex; align-items: center;
padding-left: 16px; -webkit-app-region: drag;
}
.mark { width: 14px; height: 14px; color: var(--glyph); }
.app { margin-left: 10px; font-size: 12px; color: var(--fg3); }
.win { margin-left: auto; display: flex; height: 100%; }
.win button {
width: 46px; height: 100%; display: grid; place-items: center;
color: var(--fg3); transition: background-color .15s var(--ease), color .15s var(--ease);
}
.win button:hover { background: var(--hover); color: var(--fg); }
.win svg { width: 10px; height: 10px; }

.shell { display: flex; height: 862px; }

/* rail */
nav {
width: 240px; flex: none; padding: 12px 10px;
border-right: 1px solid var(--line);
display: flex; flex-direction: column; gap: 2px;
}
nav button {
height: 36px; padding: 0 14px; border-radius: 8px; text-align: left;
font: 500 12.5px/1 var(--m); color: var(--fg3);
transition: background-color .15s var(--ease), color .15s var(--ease), transform .12s var(--ease);
}
nav button:hover { background: var(--hover); color: var(--fg2); }
nav button[aria-current="page"] { background: var(--pill); color: var(--fg); }
nav button:active { transform: scale(.97); }

/* content */
main { padding: 32px 40px; flex: 1; }
h1 { font: 600 34px/1.15 var(--s); letter-spacing: -.01em; }

.drop {
display: block; margin-top: 28px; width: 560px; height: 36px; padding: 0 12px;
margin-left: -12px; border-radius: 6px; text-align: left;
font: 12.5px/36px var(--m); color: var(--fg3);
transition: background-color .15s var(--ease), color .15s var(--ease);
}
.drop:hover { background: var(--hover); color: var(--fg2); }

.queue { list-style: none; width: 560px; margin-top: 12px; }
.queue li {
height: 36px; display: flex; align-items: center; justify-content: space-between;
font: 12.5px/1 var(--m); font-variant-numeric: tabular-nums;
}
.name { color: var(--fg2); }
.st { color: var(--fg3); }
.st.run { color: var(--fg); font-weight: 400; }
.st.fail { color: var(--fg); font-weight: 700; }

.opts { margin-top: 48px; display: grid; grid-template-columns: 96px auto; row-gap: 22px; align-items: center; }
.label { color: var(--fg3); font-size: 13px; }

.seg { display: flex; gap: 4px; }
.seg button {
height: 30px; padding: 0 14px; border-radius: 6px;
font: 500 12.5px/1 var(--m); color: var(--fg3);
transition: background-color .15s var(--ease), color .15s var(--ease), transform .12s var(--ease);
}
.seg button:hover { background: var(--hover); color: var(--fg2); }
.seg button[aria-pressed="true"] { background: var(--pill); color: var(--fg); }
.seg button:active { transform: scale(.97); }

.slider { display: flex; align-items: center; gap: 16px; }
.track { position: relative; width: 240px; height: 3px; background: var(--track); border-radius: 2px; }
.fill { position: absolute; inset: 0 20% 0 0; background: var(--fg); border-radius: 2px; }
.thumb {
position: absolute; left: 80%; top: 50%; width: 12px; height: 12px;
margin: -6px 0 0 -6px; border-radius: 50%; background: var(--fg);
}
.val { font: 12.5px/1 var(--m); color: var(--fg2); font-variant-numeric: tabular-nums; width: 24px; text-align: right; }

.go {
margin-top: 44px; height: 38px; padding: 0 22px; border-radius: 999px;
background: #fff; color: #000; font: 600 13px/1 var(--s);
transition: background-color .15s var(--ease), transform .12s var(--ease);
}
.go:hover { background: #d0d0d0; }
.go:active { transform: scale(.97); }
</style>
</head>
<body>
<header class="bar">
<svg class="mark" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square" stroke-linejoin="miter" aria-hidden="true"><path d="M2 2h10M2 7h7M2 2v10"/></svg>
<span class="app">Filesmith</span>
<div class="win">
<button aria-label="Minimise"><svg viewBox="0 0 10 10" stroke="currentColor"><path d="M0 5.5h10"/></svg></button>
<button aria-label="Maximise"><svg viewBox="0 0 10 10" fill="none" stroke="currentColor"><rect x=".5" y=".5" width="9" height="9"/></svg></button>
<button aria-label="Close"><svg viewBox="0 0 10 10" stroke="currentColor"><path d="M0 0l10 10M10 0L0 10"/></svg></button>
</div>
</header>

<div class="shell">
<nav aria-label="Operations">
<button aria-current="page">Convert</button>
<button>Compress</button>
<button>Resize</button>
<button>Upscale</button>
<button>Remove BG</button>
<button>Generate</button>
<button>Tools</button>
</nav>

<main>
<h1>Convert</h1>

<button class="drop">+ drop files</button>

<ul class="queue">
<li><span class="name">IMG_4821.HEIC</span><span class="st">done</span></li>
<li><span class="name">screenshot.png</span><span class="st run">62%</span></li>
<li><span class="name">hero-banner.png</span><span class="st">queued</span></li>
<li><span class="name">scan_0091.tiff</span><span class="st fail">✕ failed</span></li>
</ul>

<div class="opts">
<span class="label">Format</span>
<div class="seg" role="group" aria-label="Format">
<button aria-pressed="true">WebP</button>
<button aria-pressed="false">JPG</button>
<button aria-pressed="false">PNG</button>
<button aria-pressed="false">AVIF</button>
</div>
<span class="label">Quality</span>
<div class="slider" role="slider" aria-label="Quality" aria-valuemin="0" aria-valuemax="100" aria-valuenow="80" tabindex="0">
<div class="track"><div class="fill"></div><div class="thumb"></div></div>
<span class="val">80</span>
</div>
</div>

<button class="go">Convert 4 files</button>
</main>
</div>
</body>
</html>
Loading
Loading