"use client" import { useCallback, useEffect, useState, type ComponentType, type ReactNode, } from "react" import { Bot, BookOpenText, GitBranch, Globe, Keyboard, Menu, SendHorizontal, Palette, PlugZap, Server, Settings, Sparkles, } from "lucide-react" import { useTranslations } from "next-intl" import { usePathname } from "next/navigation" import { useRouter } from "next/navigation" import { Button } from "@/components/ui/button" import { AppToaster } from "@/components/ui/app-toaster" import { cn } from "@/lib/utils" import { detectEnvironment } from "@/lib/transport/detect" import { AppTitleBar } from "@/components/layout/app-title-bar" import { useIsMobile } from "@/hooks/use-mobile" import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet" interface SettingsNavItem { href: string labelKey: | "appearance" | "agents" | "model_providers" | "mcp" | "skills" | "experts" | "shortcuts" | "version_control" | "chat_channels" | "system" | "web_service" icon: ComponentType<{ className?: string }> } const SETTINGS_NAV_ITEMS: SettingsNavItem[] = [ { href: "/settings/appearance", labelKey: "appearance", icon: Palette, }, { href: "/settings/mcp", labelKey: "mcp", icon: PlugZap, }, { href: "/settings/skills", labelKey: "skills", icon: BookOpenText, }, { href: "/settings/experts", labelKey: "experts", icon: Sparkles, }, { href: "/settings/agents", labelKey: "agents", icon: Bot, }, { href: "/settings/model-providers", labelKey: "model_providers", icon: Server, }, { href: "/settings/shortcuts", labelKey: "shortcuts", icon: Keyboard, }, { href: "/settings/version-control", labelKey: "version_control", icon: GitBranch, }, { href: "/settings/chat-channels", labelKey: "chat_channels", icon: SendHorizontal, }, { href: "/settings/web-service", labelKey: "web_service", icon: Globe, }, { href: "/settings/system", labelKey: "system", icon: Settings, }, ] interface SettingsShellProps { children: ReactNode } function normalizePath(path: string): string { const noSuffix = path.replace(/\/index\.html$/, "").replace(/\.html$/, "") const noTrailingSlash = noSuffix.replace(/\/+$/, "") return noTrailingSlash || "/" } function isWindowsRuntime(): boolean { if (typeof navigator === "undefined") return false const platform = navigator.platform.toLowerCase() const userAgent = navigator.userAgent.toLowerCase() return platform.includes("win") || userAgent.includes("windows") } export function SettingsShell({ children }: SettingsShellProps) { const t = useTranslations("SettingsShell") const pathname = usePathname() const router = useRouter() const normalizedPathname = normalizePath(pathname) const isMobile = useIsMobile() const [navOpen, setNavOpen] = useState(false) useEffect(() => { document.title = `${t("title")} - codeg` }, [t]) const navigateTo = useCallback( (href: string) => { if (typeof window === "undefined") return const target = normalizePath(href) const current = normalizePath(window.location.pathname) if (current === target) { setNavOpen(false) return } if (isWindowsRuntime()) { window.location.assign(target) return } router.push(target) setNavOpen(false) }, [router, setNavOpen] ) const filteredNavItems = SETTINGS_NAV_ITEMS.filter( (item) => !(item.labelKey === "web_service" && detectEnvironment() === "web") ) const navContent = ( <>
{t("preferences")}
) return (
setNavOpen(true)} > ) : undefined } center={
{t("title")}
} />
{/* Desktop sidebar */} {!isMobile && ( )} {/* Mobile navigation Sheet */} {isMobile && ( {t("title")} {navContent} )}
{children}
) }