Skip to content

Commit cd14a61

Browse files
benvinegarclaude
andauthored
Decouple sidebar visibility from layout mode (#18)
Layout toggles (1/2/0) now only change the diff view between split/stack without collapsing the sidebar. Sidebar visibility is controlled by a new independent toggle: press `s` or use View > Sidebar in the menu. On wide terminals (≥220 cols), the sidebar now stays visible regardless of which layout mode is active. On narrower terminals it remains hidden as before since there isn't enough room. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8cd74fc commit cd14a61

5 files changed

Lines changed: 26 additions & 7 deletions

File tree

src/ui/App.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export function App({
4949
const [showLineNumbers, setShowLineNumbers] = useState(bootstrap.initialShowLineNumbers ?? true);
5050
const [wrapLines, setWrapLines] = useState(bootstrap.initialWrapLines ?? false);
5151
const [showHunkHeaders, setShowHunkHeaders] = useState(bootstrap.initialShowHunkHeaders ?? true);
52+
const [sidebarVisible, setSidebarVisible] = useState(true);
5253
const [showHelp, setShowHelp] = useState(false);
5354
const [focusArea, setFocusArea] = useState<FocusArea>("files");
5455
const [activeMenuId, setActiveMenuId] = useState<MenuId | null>(null);
@@ -83,7 +84,7 @@ export function App({
8384
const bodyPadding = pagerMode ? 0 : BODY_PADDING;
8485
const bodyWidth = Math.max(0, terminal.width - bodyPadding);
8586
const responsiveLayout = resolveResponsiveLayout(layoutMode, terminal.width);
86-
const showFilesPane = pagerMode ? false : responsiveLayout.showFilesPane;
87+
const showFilesPane = pagerMode ? false : responsiveLayout.showFilesPane && sidebarVisible;
8788
const centerWidth = bodyWidth;
8889
const resolvedLayout = responsiveLayout.layout;
8990
const currentHunk = selectedFile?.metadata.hunks[selectedHunkIndex];
@@ -247,6 +248,11 @@ export function App({
247248
setWrapLines((current) => !current);
248249
};
249250

251+
/** Toggle sidebar visibility independently of layout mode. */
252+
const toggleSidebar = () => {
253+
setSidebarVisible((current) => !current);
254+
};
255+
250256
/** Toggle visibility of hunk metadata rows without changing the actual diff lines. */
251257
const toggleHunkHeaders = () => {
252258
setShowHunkHeaders((current) => !current);
@@ -354,6 +360,14 @@ export function App({
354360
action: () => setLayoutMode("auto"),
355361
},
356362
{ kind: "separator" },
363+
{
364+
kind: "item",
365+
label: "Sidebar",
366+
hint: "s",
367+
checked: sidebarVisible,
368+
action: toggleSidebar,
369+
},
370+
{ kind: "separator" },
357371
{
358372
kind: "item",
359373
label: "Agent notes",
@@ -678,6 +692,12 @@ export function App({
678692
return;
679693
}
680694

695+
if (key.name === "s") {
696+
toggleSidebar();
697+
closeMenu();
698+
return;
699+
}
700+
681701
if (key.name === "t") {
682702
const currentIndex = THEMES.findIndex((theme) => theme.id === activeTheme.id);
683703
const nextIndex = (currentIndex + 1) % THEMES.length;

src/ui/components/chrome/StatusBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export function StatusBar({
2525
if (canResizeDivider) {
2626
hintParts.push("drag divider resize");
2727
}
28-
hintParts.push("space/b page", "/ filter", "[ ] hunk nav", "1 2 0 layout", "t theme", "a notes", "l lines", "w wrap", "m meta", "q quit");
28+
hintParts.push("space/b page", "/ filter", "[ ] hunk nav", "1 2 0 layout", "s sidebar", "t theme", "a notes", "l lines", "w wrap", "m meta", "q quit");
2929

3030
return (
3131
<box

src/ui/lib/responsive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ export function resolveResponsiveLayout(requestedLayout: LayoutMode, viewportWid
3232
return {
3333
viewport,
3434
layout: "split",
35-
showFilesPane: false,
35+
showFilesPane: viewport === "full",
3636
};
3737
}
3838

3939
if (requestedLayout === "stack") {
4040
return {
4141
viewport,
4242
layout: "stack",
43-
showFilesPane: false,
43+
showFilesPane: viewport === "full",
4444
};
4545
}
4646

test/app-interactions.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@ describe("App interactions", () => {
313313

314314
frame = setup.captureCharFrame();
315315
expect(frame).not.toContain("Split view");
316-
expect(frame).not.toContain("│");
317316
expect(frame).toContain("1 - export const alpha = 1;");
318317
} finally {
319318
await act(async () => {

test/app-responsive.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,10 @@ describe("responsive shell", () => {
162162
expect(forcedSplit).toMatch(/.*/);
163163
expect(forcedSplit).not.toContain("drag divider resize");
164164

165-
expect(forcedStack).not.toContain("Files");
165+
expect(forcedStack).toContain("M alpha.ts");
166166
expect(forcedStack).not.toContain("Changeset summary");
167167
expect(forcedStack).not.toMatch(/.*/);
168-
expect(forcedStack).not.toContain("drag divider resize");
168+
expect(forcedStack).toContain("drag divider resize");
169169
});
170170

171171
test("pager mode stays responsive while hiding app chrome", async () => {

0 commit comments

Comments
 (0)