Merge pull request #274 from jordan8037310/fix/run-menu-recent-sessions

fix(run-menu): make Recent Sessions rows legible on macOS (home-prefix regex + width + worktree)
This commit is contained in:
Ark0N
2026-08-10 13:09:18 +02:00
committed by GitHub
2 changed files with 85 additions and 8 deletions
+37 -8
View File
@@ -490,26 +490,55 @@ Object.assign(CodemanApp.prototype, {
const timeStr = date.toLocaleDateString('en', { month: 'short', day: 'numeric' })
+ ' ' + date.toLocaleTimeString('en', { hour: '2-digit', minute: '2-digit', hour12: false });
// Shared helper, not a local regex: the copy that used to live here
// matched `/home/<user>/` only, so on macOS every row rendered the same
// unabbreviated `/Users/<user>/…` prefix and ellipsized away the tail
// that identifies it (#273).
// matched `/home/<user>/` only, so on macOS (`/Users/<user>/`) nothing was
// stripped and every row spent its first ~19 characters on an identical
// prefix — with the tail ellipsized, all rows rendered as
// `/Users/jordanryan/co…` and became indistinguishable (#273).
const shortDir = this._shortenHomePath(s.workingDir);
// Lead with the folder that identifies the row; the parent path trails and
// is what gets truncated. Truncation must never eat the identity.
const lastSlash = shortDir.lastIndexOf('/');
const leafName = lastSlash === -1 ? shortDir : shortDir.slice(lastSlash + 1);
// `<repo>/.claude/worktrees` in the parent path is pure noise once the pill
// says which worktree it is — drop it so the repo stays visible instead.
const parentDir = (lastSlash === -1 ? '' : shortDir.slice(0, lastSlash)).replace(/\/\.claude\/worktrees$/, '');
const btn = document.createElement('button');
btn.className = 'run-mode-option';
btn.className = 'run-mode-option run-mode-hist-row';
btn.title = s.workingDir;
btn.dataset.sessionId = s.sessionId;
btn.dataset.workingDir = s.workingDir;
const dirSpan = document.createElement('span');
dirSpan.className = 'hist-dir';
dirSpan.textContent = shortDir;
const nameSpan = document.createElement('span');
nameSpan.className = 'hist-name';
nameSpan.textContent = leafName;
const parts = [nameSpan];
// Worktree pill, same data the session rows use (#266). A worktree's
// directory basename is often just the worktree name, so without this two
// worktrees of one repo still read alike.
const wt = this._worktreeLabel ? this._worktreeLabel(s) : '';
if (wt) {
const wtSpan = document.createElement('span');
wtSpan.className = 'hist-wt';
wtSpan.textContent = wt;
parts.push(wtSpan);
}
if (parentDir) {
const dirSpan = document.createElement('span');
dirSpan.className = 'hist-dir';
dirSpan.textContent = parentDir;
parts.push(dirSpan);
}
const metaSpan = document.createElement('span');
metaSpan.className = 'hist-meta';
metaSpan.textContent = timeStr;
parts.push(metaSpan);
btn.append(dirSpan, metaSpan);
btn.append(...parts);
btn.addEventListener('click', (e) => {
e.stopPropagation();
this.resumeHistorySession(s.sessionId, s.workingDir, s.name);
+48
View File
@@ -4455,6 +4455,24 @@ body.touch-device .terminal-container .xterm .xterm-helper-textarea {
max-width: 250px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.3);
}
/* Above phone width the menu becomes a full-width drawer across the bottom of the
window. The 250px cap above was sized for a `~/<dir>/<repo>` row, which assumed
the home prefix had been abbreviated — it never was on macOS, so real rows blew
straight through it and ellipsized into `/Users/<user>/co…`, identical on every
line. Width is what buys room for the worktree + branch, so the cap is lifted
rather than nudged. Phones keep the compact popover: mobile.css positions this
menu itself and a viewport-wide drawer there would cover the composer. */
@media (min-width: 769px) {
.run-mode-menu {
max-width: none;
width: calc(100vw - 24px);
}
.run-mode-history {
/* More rows are worth showing once each one is legible. */
max-height: 320px;
}
}
.run-mode-menu.active {
display: flex;
flex-direction: column;
@@ -4525,6 +4543,31 @@ body.touch-device .terminal-container .xterm .xterm-helper-textarea {
.run-mode-history .run-mode-option {
max-width: 100%;
}
/* Recent-session row: identity first, path last.
The row reads <folder> [⑂ worktree · branch] <parent path> <time>
with only the parent path allowed to shrink, so truncation can never hide
which project (or which worktree) a row refers to. */
.run-mode-hist-row {
align-items: baseline;
gap: 8px;
}
.run-mode-option .hist-name {
flex: 0 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 600;
}
.run-mode-option .hist-wt {
flex: 0 0 auto;
font-size: 0.78em;
padding: 0 5px;
border-radius: 3px;
background: color-mix(in srgb, var(--accent) 16%, transparent);
color: var(--accent);
white-space: nowrap;
}
.run-mode-option .hist-dir {
flex: 1;
/* A flex item's default min-width is auto, so without this the path refuses to
@@ -4534,6 +4577,11 @@ body.touch-device .terminal-container .xterm .xterm-helper-textarea {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
/* The parent path is context, not identity — dim it and let it be the part
that loses characters first. */
color: var(--text-muted);
font-size: 0.85em;
text-align: right;
}
.run-mode-option .hist-meta {
font-size: 0.85em;