mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
1bf90a2357
* feat(editor): focus-mode shortcut to toggle both sidebars (#1276) Keyboard-first reviewers had to reach for the mouse to collapse the Contents sidebar and the right-hand panel every time they wanted to read a document. Bind that to one key. Mod+. now toggles the existing `focus` view mode from the keyboard, on both the plan review and annotate surfaces. The first press remembers whatever was open and closes both panels; the next press restores that exact arrangement, so a session with only one panel open comes back the same way. Any manual open (a sidebar tab, the annotation panel, the agent terminal) already exits the view mode and clears the memory, so the shortcut cannot leave the layout stuck. The binding was picked after auditing every plan-review and annotate binding: Mod+B / Mod+Shift+B are the sidebar toggles, Mod+S, Mod+P, Mod+Enter, Mod+C and Mod+Z are taken, and code review already uses Mod+. for its own "collapse the chrome" toggle. It is unshifted on every keyboard layout and claimed by no browser or OS default. The dispatcher gate is shared with the annotate sidebar shortcuts, so the key is inert while a dialog, an overlay, a submission, or a text field owns the keystroke. HTML surfaces are excluded because they own their own persisted chrome and never render the Focus control. * fix(editor): keep focus-mode exit reachable on HTML surfaces; note the HTML caveat in help
130 lines
3.5 KiB
TypeScript
130 lines
3.5 KiB
TypeScript
import { describe, expect, test } from 'bun:test';
|
|
import {
|
|
canUseAnnotateWideMode,
|
|
resolveFocusShortcutAction,
|
|
resolveWideModeExitLayout,
|
|
type WideModeLayoutSnapshot,
|
|
} from './wideMode';
|
|
|
|
const snapshot: WideModeLayoutSnapshot = {
|
|
sidebarIsOpen: true,
|
|
sidebarTab: 'files',
|
|
panelOpen: true,
|
|
};
|
|
|
|
describe('canUseAnnotateWideMode', () => {
|
|
test('enables wide mode outside archive and diff', () => {
|
|
expect(canUseAnnotateWideMode({
|
|
archiveMode: false,
|
|
isPlanDiffActive: false,
|
|
})).toBe(true);
|
|
|
|
expect(canUseAnnotateWideMode({
|
|
archiveMode: true,
|
|
isPlanDiffActive: false,
|
|
})).toBe(false);
|
|
|
|
expect(canUseAnnotateWideMode({
|
|
archiveMode: false,
|
|
isPlanDiffActive: true,
|
|
})).toBe(false);
|
|
|
|
expect(canUseAnnotateWideMode({
|
|
archiveMode: true,
|
|
isPlanDiffActive: true,
|
|
})).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('resolveFocusShortcutAction', () => {
|
|
test('enters focus mode from the ordinary layout', () => {
|
|
expect(resolveFocusShortcutAction({
|
|
canUseWideMode: true,
|
|
wideModeType: null,
|
|
})).toBe('enter-focus');
|
|
});
|
|
|
|
test('restores the remembered layout on the second press', () => {
|
|
expect(resolveFocusShortcutAction({
|
|
canUseWideMode: true,
|
|
wideModeType: 'focus',
|
|
})).toBe('exit');
|
|
});
|
|
|
|
// A press while `wide` is active must restore, not swap wide -> focus: the
|
|
// panels are already hidden, so re-hiding them would read as a dead key.
|
|
test('restores from wide mode instead of switching to focus', () => {
|
|
expect(resolveFocusShortcutAction({
|
|
canUseWideMode: true,
|
|
wideModeType: 'wide',
|
|
})).toBe('exit');
|
|
});
|
|
|
|
test('does nothing where the view modes are unavailable', () => {
|
|
expect(resolveFocusShortcutAction({
|
|
canUseWideMode: false,
|
|
wideModeType: null,
|
|
})).toBe('none');
|
|
});
|
|
|
|
// Availability can drop while a view mode is still active (opening the plan
|
|
// diff); the shortcut must still be able to give the panels back.
|
|
test('still restores when availability drops mid-focus', () => {
|
|
expect(resolveFocusShortcutAction({
|
|
canUseWideMode: false,
|
|
wideModeType: 'focus',
|
|
})).toBe('exit');
|
|
});
|
|
});
|
|
|
|
describe('resolveWideModeExitLayout', () => {
|
|
test('restores the saved sidebar tab and panel by default', () => {
|
|
expect(resolveWideModeExitLayout(snapshot)).toEqual({
|
|
sidebarOpen: true,
|
|
sidebarTab: 'files',
|
|
panelOpen: true,
|
|
});
|
|
});
|
|
|
|
test('opens an explicit sidebar target and can keep the panel closed', () => {
|
|
expect(resolveWideModeExitLayout(snapshot, {
|
|
restore: false,
|
|
sidebarTab: 'toc',
|
|
panelOpen: false,
|
|
})).toEqual({
|
|
sidebarOpen: true,
|
|
sidebarTab: 'toc',
|
|
panelOpen: false,
|
|
});
|
|
});
|
|
|
|
test('honors an explicit panel reopen without restoring the sidebar snapshot', () => {
|
|
expect(resolveWideModeExitLayout(snapshot, {
|
|
restore: false,
|
|
panelOpen: true,
|
|
})).toEqual({
|
|
sidebarOpen: false,
|
|
sidebarTab: null,
|
|
panelOpen: true,
|
|
});
|
|
});
|
|
|
|
test('keeps the panel closed when leaving wide mode without restore', () => {
|
|
expect(resolveWideModeExitLayout(snapshot, {
|
|
restore: false,
|
|
})).toEqual({
|
|
sidebarOpen: false,
|
|
sidebarTab: null,
|
|
panelOpen: undefined,
|
|
});
|
|
});
|
|
|
|
test('falls back to a closed layout when the snapshot is missing', () => {
|
|
expect(resolveWideModeExitLayout(null)).toEqual({
|
|
sidebarOpen: false,
|
|
sidebarTab: null,
|
|
panelOpen: false,
|
|
});
|
|
});
|
|
});
|