Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion extension/sidepanel-terminal.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,18 @@
ended: document.getElementById('terminal-ended'),
restart: document.getElementById('terminal-restart'),
restartNow: document.getElementById('terminal-restart-now'),
fontSize: document.getElementById('terminal-fontsize'),
};

// Sidebar text-size selector. sm = 13px is the shipped default (do not change it — it is
// what every existing session renders at); the others step around it. Persisted per user
// in chrome.storage.local and applied to the live xterm.
const FONT_SIZES = { xs: 11, sm: 13, md: 15, lg: 17, xl: 20 };
const FONT_SIZE_DEFAULT = 'sm';
const FONT_SIZE_KEY = 'terminalFontSize';
let fontSizeKey = FONT_SIZE_DEFAULT; // the chosen T-shirt size; px comes from FONT_SIZES
const fontPx = () => FONT_SIZES[fontSizeKey] || FONT_SIZES[FONT_SIZE_DEFAULT];

/** State machine. */
const STATE = {
IDLE: 'idle',
Expand Down Expand Up @@ -392,7 +402,7 @@
if (term) return;
term = new Terminal({
fontFamily: '"JetBrains Mono", "SF Mono", Menlo, "Noto Sans Mono CJK KR", "Malgun Gothic", monospace',
fontSize: 13,
fontSize: fontPx(), // the persisted size (default 13 = sm); see FONT_SIZES
theme: { background: '#0a0a0a', foreground: '#e5e5e5' },
cursorBlink: true,
scrollback: 5000,
Expand Down Expand Up @@ -931,6 +941,40 @@
els.restart?.addEventListener('click', forceRestart);
els.restartNow?.addEventListener('click', forceRestart);

// Re-measure the terminal and tell the PTY its new size. Same body the first-fit and the
// ResizeObserver use — a bare fitAddon.fit() is not enough: without the resize message
// claude keeps wrapping to the old cols/rows.
const refitTerminal = () => {
try {
fitAddon && fitAddon.fit();
if (term && ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'resize', cols: term.cols, rows: term.rows }));
}
} catch {}
};

// Sidebar text-size selector: restore the saved size, then apply on change. Changing the
// font is asynchronous inside xterm — it re-measures the character cell on the next render
// frame, so fitting in the same tick reads the OLD cell and leaves the grid clipped (the
// bug that made a live change need a close/reopen). Two rAFs let the new metrics land
// before we fit + resize. If the terminal isn't up yet, ensureXterm reads fontPx() at
// creation, so no refit is needed then.
const applyFontSize = (key, persist) => {
fontSizeKey = FONT_SIZES[key] ? key : FONT_SIZE_DEFAULT;
if (els.fontSize) els.fontSize.value = fontSizeKey;
if (term) {
term.options.fontSize = fontPx();
requestAnimationFrame(() => requestAnimationFrame(refitTerminal));
}
if (persist) { try { chrome.storage.local.set({ [FONT_SIZE_KEY]: fontSizeKey }); } catch {} }
};
els.fontSize?.addEventListener('change', (e) => applyFontSize(e.target.value, true));
try {
chrome.storage.local.get([FONT_SIZE_KEY], (r) => applyFontSize(r?.[FONT_SIZE_KEY] || FONT_SIZE_DEFAULT, false));
} catch {
applyFontSize(FONT_SIZE_DEFAULT, false);
}


// Live browser-tab state. background.js → sidepanel.js → us. We
// forward over the live PTY WebSocket; terminal-agent.ts writes
Expand Down
32 changes: 32 additions & 0 deletions extension/sidepanel.css
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,38 @@ body::after {
color: #f59e0b;
border-color: #f59e0b;
}
/* Right cluster: text-size selector + Restart, kept together on the toolbar's right end. */
.terminal-toolbar-right {
display: flex;
align-items: center;
gap: 6px;
flex-shrink: 0;
}
.terminal-fontsize {
display: flex;
align-items: center;
gap: 3px;
color: #a1a1aa;
}
/* The glyph is a size hint, not decoration — a small 'A' beside the picker. */
.terminal-fontsize-icon {
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
line-height: 1;
}
.terminal-fontsize select {
background: #0a0a0a;
color: #a1a1aa;
border: 1px solid #27272a;
border-radius: 3px;
padding: 3px 4px;
font-size: 11px;
font-family: 'JetBrains Mono', monospace;
cursor: pointer;
color-scheme: dark; /* keep the native option list dark, not a white flash over the panel */
}
.terminal-fontsize select:hover { color: #f59e0b; border-color: #f59e0b; }
.terminal-fontsize select:focus-visible { outline: 2px solid #f59e0b; outline-offset: 1px; }
.terminal-bootstrap {
flex: 1;
display: flex;
Expand Down
14 changes: 13 additions & 1 deletion extension/sidepanel.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,19 @@
<button id="chat-screenshot-btn" class="terminal-toolbar-btn" title="Take a screenshot">📸 Screenshot</button>
<button id="chat-cookies-btn" class="terminal-toolbar-btn" title="Import cookies from your browser">🍪 Cookies</button>
</div>
<button class="terminal-toolbar-btn" id="terminal-restart-now" title="Restart Claude Code session">↻ Restart</button>
<div class="terminal-toolbar-right">
<label class="terminal-fontsize" title="Sidebar text size">
<span class="terminal-fontsize-icon" aria-hidden="true">A</span>
<select id="terminal-fontsize" aria-label="Sidebar text size">
<option value="xs">XS</option>
<option value="sm">SM</option>
<option value="md">MD</option>
<option value="lg">LG</option>
<option value="xl">XL</option>
</select>
</label>
<button class="terminal-toolbar-btn" id="terminal-restart-now" title="Restart Claude Code session">↻ Restart</button>
</div>
</div>
<div class="terminal-bootstrap" id="terminal-bootstrap">
<div class="terminal-bootstrap-icon">▸</div>
Expand Down