feat(ui): make desktop sidebar collapsible

Add a header toggle and a panel close button so the desktop file
sidebar collapses with a width transition, mirroring the journal
panel.

- split onClose (close button) from onNavigate (file selection) so
  clicking a file no longer collapses the sidebar on desktop
- give the aside h-full so the file tree and outline keep bounded
  scroll regions inside the new wrapper
- swap the aside shadow for a gray right border to match the journal
This commit is contained in:
2026-09-13 14:09:18 +08:00
parent 49bed7d279
commit 12f8d8542c
2 changed files with 45 additions and 21 deletions
+13 -14
View File
@@ -18,7 +18,7 @@ interface SidebarContentProps {
pathHeadings: Record<string, TocNode[]>;
currentPath: string;
onClose: () => void;
isDesktop?: boolean;
onNavigate?: () => void;
onDataSourceOpen?: () => void;
}
@@ -60,15 +60,13 @@ const SidebarContent: Component<SidebarContentProps> = (props) => {
>
<TbOutlineFolderOpen class="inline-block align-[-0.125em]" />
</button>
<Show when={!props.isDesktop}>
<button
onClick={props.onClose}
class="text-gray-500 hover:text-gray-700"
title="关闭"
>
<TbOutlineX class="inline-block align-[-0.125em]" />
</button>
</Show>
<button
onClick={props.onClose}
class="text-gray-500 hover:text-gray-700"
title="关闭"
>
<TbOutlineX class="inline-block align-[-0.125em]" />
</button>
</div>
</div>
</div>
@@ -84,7 +82,7 @@ const SidebarContent: Component<SidebarContentProps> = (props) => {
currentPath={props.currentPath}
pathHeadings={props.pathHeadings}
depth={0}
onClose={props.onClose}
onClose={() => props.onNavigate?.()}
isHidden={isFileHidden}
/>
))}
@@ -151,6 +149,7 @@ export const MobileSidebar: Component<SidebarProps> = (props) => {
pathHeadings={pathHeadings()}
currentPath={location.pathname}
onClose={props.onClose}
onNavigate={props.onClose}
onDataSourceOpen={props.onDataSourceOpen}
/>
</aside>
@@ -164,6 +163,7 @@ export const MobileSidebar: Component<SidebarProps> = (props) => {
export const DesktopSidebar: Component<{
fileTree?: FileNode[];
pathHeadings?: Record<string, TocNode[]>;
onClose: () => void;
onDataSourceOpen?: () => void;
}> = (props) => {
const location = useLocation();
@@ -183,13 +183,12 @@ export const DesktopSidebar: Component<{
});
return (
<aside class="hidden md:flex flex-col w-64 shrink-0 bg-white shadow-lg overflow-hidden">
<aside class="hidden md:flex flex-col h-full w-64 shrink-0 bg-white border-r border-gray-200 overflow-hidden">
<SidebarContent
fileTree={fileTree()}
pathHeadings={pathHeadings()}
currentPath={location.pathname}
onClose={() => {}}
isDesktop
onClose={props.onClose}
onDataSourceOpen={props.onDataSourceOpen}
/>
</aside>