"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useSearchParams } from "next/navigation";
import {
useCallback,
useEffect,
useLayoutEffect,
useRef,
useState,
} from "react";
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
import { Toaster } from "@/components/ui/sonner";
import { CommandPalette } from "@/components/workspace/command-palette";
import { WorkspaceSidebar } from "@/components/workspace/workspace-sidebar";
import { BrandProvider, useBrand } from "@/core/brand/provider";
import { BrandSessionInitializer } from "@/core/brand/provider-client";
import { getLocalSettings, useLocalSettings } from "@/core/settings";
import { cn } from "@/lib/utils";
const queryClient = new QueryClient();
export default function WorkspaceLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
{children}
);
}
function WorkspaceBrandShell({
children,
}: Readonly<{ children: React.ReactNode }>) {
const [settings, setSettings] = useLocalSettings();
const [open, setOpen] = useState(false); // SSR default: open (matches server render)
const [showWorkspaceSidebar, setShowWorkspaceSidebar] = useState(false);
const pressedKeysRef = useRef>(new Set());
const comboTriggeredRef = useRef(false);
const searchParams = useSearchParams();
// iframe 技能模式(mode=skill)时隐藏侧边栏
const isSkillMode = searchParams.get("mode") === "skill";
useLayoutEffect(() => {
// Runs synchronously before first paint on the client — no visual flash
setOpen(!getLocalSettings().layout.sidebar_collapsed);
}, []);
useEffect(() => {
setOpen(!settings.layout.sidebar_collapsed);
}, [settings.layout.sidebar_collapsed]);
useEffect(() => {
const resetComboTrigger = () => {
comboTriggeredRef.current = false;
};
const handleKeyDown = (event: KeyboardEvent) => {
const target = event.target as HTMLElement | null;
if (
target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement ||
target?.isContentEditable
) {
return;
}
pressedKeysRef.current.add(event.key.toLowerCase());
const hasCtrlOrMeta = event.ctrlKey || event.metaKey;
const hasShift = event.shiftKey;
const hasL = pressedKeysRef.current.has("l");
const hasD = pressedKeysRef.current.has("d");
if (
hasCtrlOrMeta &&
hasShift &&
hasL &&
hasD &&
!comboTriggeredRef.current
) {
event.preventDefault();
comboTriggeredRef.current = true;
setShowWorkspaceSidebar((prev) => !prev);
}
};
const handleKeyUp = (event: KeyboardEvent) => {
pressedKeysRef.current.delete(event.key.toLowerCase());
if (
!pressedKeysRef.current.has("l") ||
!pressedKeysRef.current.has("d") ||
(!event.ctrlKey && !event.metaKey) ||
!event.shiftKey
) {
resetComboTrigger();
}
};
const handleBlur = () => {
pressedKeysRef.current.clear();
resetComboTrigger();
};
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);
window.addEventListener("blur", handleBlur);
return () => {
window.removeEventListener("keydown", handleKeyDown);
window.removeEventListener("keyup", handleKeyUp);
window.removeEventListener("blur", handleBlur);
};
}, []);
const handleOpenChange = useCallback(
(open: boolean) => {
setOpen(open);
setSettings("layout", { sidebar_collapsed: !open });
},
[setSettings],
);
return (
{!isSkillMode && showWorkspaceSidebar && (
)}
{children}
[data-icon]]:hidden",
].join(" "),
title:
"text-primary-foreground! text-sm font-normal text-center w-full leading-snug",
description: "hidden",
icon: "hidden",
},
}}
/>
);
}