feat: resizeable sidebar

This commit is contained in:
2026-02-11 15:11:05 +01:00
parent 692e874594
commit ac6f07b9fe
5 changed files with 83 additions and 12 deletions

View File

@@ -1,5 +1,5 @@
import React, { useEffect } from 'react';
import { ActivityBar, Sidebar, Editor, StatusBar, Panel, TabBar, ToastContainer, showToast } from './components';
import { ActivityBar, Sidebar, Editor, StatusBar, Panel, TabBar, ToastContainer, showToast, ResizablePanel } from './components';
import { useAppStore, PostData, MediaData, TaskProgress, TabState } from './store';
import './App.css';
@@ -357,11 +357,24 @@ const App: React.FC = () => {
};
}, []);
const { sidebarVisible } = useAppStore();
return (
<div className="app">
<div className="app-main">
<ActivityBar />
<Sidebar />
{sidebarVisible && (
<ResizablePanel
direction="horizontal"
initialSize={280}
minSize={200}
maxSize={500}
storageKey="sidebar-width"
resizerPosition="end"
>
<Sidebar />
</ResizablePanel>
)}
<div className="app-content">
<TabBar />
<Editor />

View File

@@ -35,7 +35,7 @@ const SyncIcon = () => (
);
export const ActivityBar: React.FC = () => {
const { activeView, setActiveView, syncStatus, pendingChanges, openTab, tabs, activeTabId } = useAppStore();
const { activeView, setActiveView, sidebarVisible, toggleSidebar, syncStatus, pendingChanges, openTab, tabs, activeTabId } = useAppStore();
const totalPending = pendingChanges.posts + pendingChanges.media;
@@ -45,6 +45,23 @@ export const ActivityBar: React.FC = () => {
// Check if tags tab is currently active
const isTagsTabActive = tabs.some(t => t.type === 'tags' && t.id === activeTabId);
// Handle view click - toggle sidebar if clicking on active view, otherwise switch view
const handleViewClick = (view: 'posts' | 'media') => {
if (activeView === view && sidebarVisible) {
// Clicking on active view toggles sidebar off
toggleSidebar();
} else if (activeView === view && !sidebarVisible) {
// Clicking on active view when hidden shows it
toggleSidebar();
} else {
// Switching to a different view - ensure sidebar is visible
if (!sidebarVisible) {
toggleSidebar();
}
setActiveView(view);
}
};
const handleSettingsClick = () => {
// Open settings as a dedicated (non-transient) tab
openTab({ type: 'settings', id: 'settings', isTransient: false });
@@ -59,16 +76,16 @@ export const ActivityBar: React.FC = () => {
<div className="activity-bar">
<div className="activity-bar-top">
<button
className={`activity-bar-item ${activeView === 'posts' ? 'active' : ''}`}
onClick={() => setActiveView('posts')}
title="Posts"
className={`activity-bar-item ${activeView === 'posts' && sidebarVisible ? 'active' : ''}`}
onClick={() => handleViewClick('posts')}
title="Posts (click again to toggle sidebar)"
>
<PostsIcon />
</button>
<button
className={`activity-bar-item ${activeView === 'media' ? 'active' : ''}`}
onClick={() => setActiveView('media')}
title="Media"
className={`activity-bar-item ${activeView === 'media' && sidebarVisible ? 'active' : ''}`}
onClick={() => handleViewClick('media')}
title="Media (click again to toggle sidebar)"
>
<MediaIcon />
</button>

View File

@@ -1,5 +1,5 @@
.sidebar {
width: 280px;
width: 100%;
height: 100%;
background-color: var(--vscode-sideBar-background);
border-right: 1px solid var(--vscode-sideBar-border);

View File

@@ -45,6 +45,29 @@
background-color: var(--vscode-toolbar-hoverBackground, rgba(90, 93, 94, 0.31));
}
/* Sidebar toggle button */
.tab-bar-toggle-sidebar {
display: flex;
align-items: center;
justify-content: center;
width: 35px;
height: 100%;
background-color: transparent;
border: none;
border-right: 1px solid var(--vscode-tab-border, #252526);
color: var(--vscode-icon-foreground, #c5c5c5);
cursor: pointer;
flex-shrink: 0;
}
.tab-bar-toggle-sidebar:hover {
background-color: var(--vscode-toolbar-hoverBackground, rgba(90, 93, 94, 0.31));
}
.tab-bar-toggle-sidebar:active {
background-color: var(--vscode-toolbar-activeBackground, rgba(99, 102, 103, 0.31));
}
.tab-scroll-left {
border-right: 1px solid var(--vscode-tab-border, #252526);
}

View File

@@ -84,6 +84,8 @@ export const TabBar: React.FC = () => {
posts,
media,
dirtyPosts,
sidebarVisible,
toggleSidebar,
setActiveTab,
closeTab,
pinTab,
@@ -138,7 +140,7 @@ export const TabBar: React.FC = () => {
}
}, [activeTabId]);
// Keyboard shortcut handler (Ctrl+W to close active tab)
// Keyboard shortcut handler (Ctrl+W to close active tab, Ctrl+B to toggle sidebar)
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.key === 'w') {
@@ -147,11 +149,15 @@ export const TabBar: React.FC = () => {
closeTab(activeTabId);
}
}
if ((e.ctrlKey || e.metaKey) && e.key === 'b') {
e.preventDefault();
toggleSidebar();
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [activeTabId, closeTab]);
}, [activeTabId, closeTab, toggleSidebar]);
if (tabs.length === 0) {
return null;
@@ -197,6 +203,18 @@ export const TabBar: React.FC = () => {
return (
<div className="tab-bar">
<button
className="tab-bar-toggle-sidebar"
onClick={toggleSidebar}
title={`${sidebarVisible ? 'Hide' : 'Show'} Sidebar (Ctrl+B)`}
>
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<path d="M0 1h16v14H0V1zm1 1v12h4V2H1zm5 0v12h9V2H6z"/>
{!sidebarVisible && <path d="M2 4h2v1H2V4zm0 2h2v1H2V6zm0 2h2v1H2V8z" opacity="0.5"/>}
{sidebarVisible && <path d="M2 4h2v1H2V4zm0 2h2v1H2V6zm0 2h2v1H2V8z"/>}
</svg>
</button>
{showLeftArrow && (
<button
className="tab-scroll-button tab-scroll-left"