From 4ac29a6528192aca705edb71a75f5971a60161ac Mon Sep 17 00:00:00 2001 From: hugo Date: Tue, 17 Feb 2026 11:41:35 +0100 Subject: [PATCH] feat: panel-toggle-button --- .../WindowTitleBar/WindowTitleBar.css | 19 ++++++++++ .../WindowTitleBar/WindowTitleBar.tsx | 12 +++++- .../components/WindowTitleBar.test.tsx | 37 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/WindowTitleBar/WindowTitleBar.css b/src/renderer/components/WindowTitleBar/WindowTitleBar.css index d40b4a3..a855078 100644 --- a/src/renderer/components/WindowTitleBar/WindowTitleBar.css +++ b/src/renderer/components/WindowTitleBar/WindowTitleBar.css @@ -181,6 +181,25 @@ background-color: currentColor; } +.window-titlebar-panel-icon { + width: 14px; + height: 14px; + border: 1.5px solid currentColor; + border-radius: 2px; + display: block; + position: relative; + overflow: hidden; +} + +.window-titlebar-panel-pane { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: 33.3333%; + background-color: currentColor; +} + .window-titlebar-action-button:hover { background-color: var(--vscode-toolbar-hoverBackground, rgba(90, 93, 94, 0.31)); } diff --git a/src/renderer/components/WindowTitleBar/WindowTitleBar.tsx b/src/renderer/components/WindowTitleBar/WindowTitleBar.tsx index 28aa251..bbe21a1 100644 --- a/src/renderer/components/WindowTitleBar/WindowTitleBar.tsx +++ b/src/renderer/components/WindowTitleBar/WindowTitleBar.tsx @@ -11,7 +11,7 @@ type WindowControlsOverlayLike = { }; export const WindowTitleBar: React.FC = () => { - const { sidebarVisible, toggleSidebar } = useAppStore(); + const { sidebarVisible, panelVisible, toggleSidebar, togglePanel } = useAppStore(); const [windowTitle, setWindowTitle] = useState(document.title || 'Blogging Desktop Server'); const [openMenu, setOpenMenu] = useState<{ label: string; left: number } | null>(null); const [showMnemonics, setShowMnemonics] = useState(false); @@ -416,6 +416,16 @@ export const WindowTitleBar: React.FC = () => { + {openMenu && activeMenu && (
{ beforeEach(() => { useAppStore.setState({ sidebarVisible: true, + panelVisible: false, }); }); @@ -37,6 +38,42 @@ describe('WindowTitleBar', () => { expect(iconPane).toHaveAttribute('data-shape', 'left-half'); }); + it('renders a right-side panel toggle button and toggles panel visibility', () => { + render(); + + const toggleButton = screen.getByLabelText('Toggle Panel'); + expect(toggleButton).toBeInTheDocument(); + expect(toggleButton).toHaveAttribute('title', 'Show Panel (Ctrl+J)'); + + fireEvent.click(toggleButton); + + expect(useAppStore.getState().panelVisible).toBe(true); + expect(toggleButton).toHaveAttribute('title', 'Hide Panel (Ctrl+J)'); + }); + + it('uses a VS Code-like panel toggle icon shape', () => { + render(); + + const toggleButton = screen.getByLabelText('Toggle Panel'); + const iconFrame = toggleButton.querySelector('.window-titlebar-panel-icon'); + const iconPane = toggleButton.querySelector('.window-titlebar-panel-pane'); + + expect(iconFrame).not.toBeNull(); + expect(iconPane).not.toBeNull(); + expect(iconFrame).toHaveAttribute('data-shape', 'frame-square'); + expect(iconPane).toHaveAttribute('data-shape', 'bottom-half'); + }); + + it('places panel toggle to the right of sidebar toggle', () => { + render(); + + const actionButtons = Array.from(document.querySelectorAll('.window-titlebar-actions .window-titlebar-action-button')); + + expect(actionButtons).toHaveLength(2); + expect(actionButtons[0]).toHaveAttribute('aria-label', 'Toggle Sidebar'); + expect(actionButtons[1]).toHaveAttribute('aria-label', 'Toggle Panel'); + }); + it('updates overlay inset CSS variables when window controls geometry changes', () => { const geometryListeners = new Set(); let rect = {