feat(renderer): AppShell with resizable panes, sidebar/preview toggle, persisted sizes

This commit is contained in:
2026-06-05 12:02:35 +05:30
parent 1999a7716e
commit 567726022c
4 changed files with 116 additions and 8 deletions
@@ -0,0 +1,53 @@
import { AppHeader } from './AppHeader';
import { TabBar } from './TabBar';
import { Toolbar } from './Toolbar';
import { Breadcrumb } from './Breadcrumb';
import { StatusBar } from './StatusBar';
import { useAppStore } from '@/stores/app-store';
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '@/components/ui/resizable';
export function AppShell() {
const { sidebarVisible, previewVisible, paneSizes, setPaneSizes } = useAppStore();
return (
<div className="flex h-screen flex-col bg-background text-foreground">
<AppHeader />
<TabBar />
<Toolbar />
<Breadcrumb />
<main className="flex-1 overflow-hidden">
<ResizablePanelGroup
direction="horizontal"
onLayout={(sizes) => setPaneSizes({ sidebar: sizes[0], editor: sizes[1], preview: sizes[2] })}
>
{sidebarVisible && (
<>
<ResizablePanel defaultSize={paneSizes.sidebar} minSize={15} maxSize={40}>
<aside className="h-full border-r border-border bg-card/10 p-3 text-sm text-muted-foreground">
File tree placeholder
</aside>
</ResizablePanel>
<ResizableHandle />
</>
)}
<ResizablePanel defaultSize={previewVisible ? paneSizes.editor : 100} minSize={20}>
<section className="h-full bg-background p-4 text-sm text-muted-foreground">
Editor placeholder
</section>
</ResizablePanel>
{previewVisible && (
<>
<ResizableHandle />
<ResizablePanel defaultSize={paneSizes.preview} minSize={20}>
<section className="h-full border-l border-border bg-card/10 p-4 text-sm text-muted-foreground">
Preview placeholder
</section>
</ResizablePanel>
</>
)}
</ResizablePanelGroup>
</main>
<StatusBar />
</div>
);
}
+8 -8
View File
@@ -7,10 +7,10 @@ import * as ResizablePrimitive from "react-resizable-panels"
import { cn } from "@/lib/utils"
const ResizablePanelGroup = React.forwardRef<
React.ElementRef<typeof ResizablePrimitive.PanelGroup>,
React.ComponentPropsWithoutRef<typeof ResizablePrimitive.PanelGroup>
React.ElementRef<typeof ResizablePrimitive.Group>,
React.ComponentPropsWithoutRef<typeof ResizablePrimitive.Group>
>(({ className, ...props }, ref) => (
<ResizablePrimitive.PanelGroup
<ResizablePrimitive.Group
ref={ref}
className={cn(
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
@@ -19,7 +19,7 @@ const ResizablePanelGroup = React.forwardRef<
{...props}
/>
))
ResizablePanelGroup.displayName = ResizablePrimitive.PanelGroup.displayName
ResizablePanelGroup.displayName = "ResizablePanelGroup"
const ResizablePanel = React.forwardRef<
React.ElementRef<typeof ResizablePrimitive.Panel>,
@@ -34,16 +34,16 @@ const ResizablePanel = React.forwardRef<
{...props}
/>
))
ResizablePanel.displayName = ResizablePrimitive.Panel.displayName
ResizablePanel.displayName = "ResizablePanel"
const ResizableHandle = ({
withHandle,
className,
...props
}: React.ComponentPropsWithoutRef<typeof ResizablePrimitive.PanelResizeHandle> & {
}: React.ComponentPropsWithoutRef<typeof ResizablePrimitive.Separator> & {
withHandle?: boolean
}) => (
<ResizablePrimitive.PanelResizeHandle
<ResizablePrimitive.Separator
className={cn(
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className
@@ -55,7 +55,7 @@ const ResizableHandle = ({
<GripVertical className="h-2.5 w-2.5" />
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
</ResizablePrimitive.Separator>
)
ResizableHandle.displayName = "ResizableHandle"
+6
View File
@@ -27,3 +27,9 @@ if (typeof window !== 'undefined') {
}),
});
}
// Mock react-resizable-panels for jsdom environment
if (typeof window !== 'undefined') {
Object.defineProperty(window, 'innerWidth', { writable: true, value: 1920 });
Object.defineProperty(window, 'innerHeight', { writable: true, value: 1080 });
}