feat(web): implement full sidebar and header components (MS15-FE-003, MS15-FE-004)
All checks were successful
ci/woodpecker/push/web Pipeline was successful
All checks were successful
ci/woodpecker/push/web Pipeline was successful
Sidebar: collapsible with icon-only mode, 4 nav groups (Overview, Workspace, Operations, System), SVG icons matching reference, badges, user card footer with avatar/initials, SidebarContext for collapse state. Header: search bar, system status indicator, terminal toggle, notification bell with badge, user avatar dropdown with Profile/Settings/Sign Out, breadcrumb navigation. Removes standalone LogoutButton. Layout updated to wrap with SidebarProvider, dynamic --sidebar-w on collapse. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,34 +6,39 @@ import { useAuth } from "@/lib/auth/auth-context";
|
||||
import { IS_MOCK_AUTH_MODE } from "@/lib/config";
|
||||
import { AppHeader } from "@/components/layout/AppHeader";
|
||||
import { AppSidebar } from "@/components/layout/AppSidebar";
|
||||
import { SidebarProvider, useSidebar } from "@/components/layout/SidebarContext";
|
||||
import { ChatOverlay } from "@/components/chat";
|
||||
import { MosaicSpinner } from "@/components/ui/MosaicSpinner";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export default function AuthenticatedLayout({
|
||||
children,
|
||||
}: {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const SIDEBAR_EXPANDED_WIDTH = "240px";
|
||||
const SIDEBAR_COLLAPSED_WIDTH = "60px";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Inner shell — must be a child of SidebarProvider to use useSidebar
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
interface AppShellProps {
|
||||
children: ReactNode;
|
||||
}): React.JSX.Element | null {
|
||||
const router = useRouter();
|
||||
const { isAuthenticated, isLoading } = useAuth();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && !isAuthenticated) {
|
||||
router.push("/login");
|
||||
}
|
||||
}, [isAuthenticated, isLoading, router]);
|
||||
|
||||
if (isLoading) {
|
||||
return <MosaicSpinner size={48} fullPage />;
|
||||
}
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return null;
|
||||
}
|
||||
function AppShell({ children }: AppShellProps): React.JSX.Element {
|
||||
const { collapsed } = useSidebar();
|
||||
|
||||
return (
|
||||
<div className="app-shell">
|
||||
<div
|
||||
className="app-shell"
|
||||
style={
|
||||
{
|
||||
"--sidebar-w": collapsed ? SIDEBAR_COLLAPSED_WIDTH : SIDEBAR_EXPANDED_WIDTH,
|
||||
transition: "grid-template-columns 0.2s var(--ease, ease)",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
{/* Full-width header — grid-column: 1 / -1 via .app-header CSS class */}
|
||||
<AppHeader />
|
||||
|
||||
@@ -62,3 +67,36 @@ export default function AuthenticatedLayout({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Authenticated layout — handles auth guard + provides sidebar context
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export default function AuthenticatedLayout({
|
||||
children,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
}): React.JSX.Element | null {
|
||||
const router = useRouter();
|
||||
const { isAuthenticated, isLoading } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && !isAuthenticated) {
|
||||
router.push("/login");
|
||||
}
|
||||
}, [isAuthenticated, isLoading, router]);
|
||||
|
||||
if (isLoading) {
|
||||
return <MosaicSpinner size={48} fullPage />;
|
||||
}
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<AppShell>{children}</AppShell>
|
||||
</SidebarProvider>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user