"use client" import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode, } from "react" import { PanelLeftCloseIcon, ServerIcon } from "lucide-react" import { Button } from "@/components/ui/button" import { Sheet, SheetContent, SheetHeader, SheetTitle, } from "@/components/ui/sheet" import { ALL_SERVERS_ID, ServerTileRail, hostnameOf, type ServerTileItem, } from "@/components/server-tile-rail" import { cn } from "@/lib/utils" /** Preview: https://reui.io/preview/base/app-shell-12 · https://reui.io/preview/base/list-9 */ const STORAGE_KEY = "mm:server-rail-collapsed" const DESKTOP_MQ = "(min-width: 768px)" function readCollapsed(): boolean { try { return window.localStorage.getItem(STORAGE_KEY) === "1" } catch { return false } } function writeCollapsed(value: boolean) { try { window.localStorage.setItem(STORAGE_KEY, value ? "1" : "0") } catch { // quota / private mode } } interface ServerRailContextValue { openRail: () => void expandRail: () => void collapsed: boolean selectedLabel: string } const ServerRailContext = createContext(null) function useServerRail() { const ctx = useContext(ServerRailContext) if (!ctx) { throw new Error("ServerRailMobileButton must be used inside ServerRailLayout") } return ctx } function ServerRailMobileButton() { const { openRail, expandRail, collapsed, selectedLabel } = useServerRail() return ( ) } function ServerRailLayout({ items, selectedId, onSelect, showAll = true, allCount = 0, showCount = true, showType = true, headerRight, loading = false, extra, header, banner, contentClassName, children, }: { items: ServerTileItem[] selectedId: string onSelect: (id: string) => void showAll?: boolean allCount?: number showCount?: boolean showType?: boolean headerRight?: ReactNode loading?: boolean extra?: ReactNode header?: ReactNode banner?: ReactNode contentClassName?: string children: ReactNode }) { const [railOpen, setRailOpen] = useState(false) const [collapsed, setCollapsed] = useState(false) const [hydrated, setHydrated] = useState(false) useEffect(() => { setCollapsed(readCollapsed()) setHydrated(true) }, []) useEffect(() => { if (!hydrated) return writeCollapsed(collapsed) }, [collapsed, hydrated]) const handleSelect = useCallback( (id: string) => { onSelect(id) setRailOpen(false) }, [onSelect], ) const expandRail = useCallback(() => { setCollapsed(false) }, []) const selectedLabel = useMemo(() => { if (showAll && selectedId === ALL_SERVERS_ID) return "Все серверы" const item = items.find((entry) => entry.id === selectedId) return item ? hostnameOf(item) : "Сервер" }, [items, selectedId, showAll]) const ctx = useMemo( () => ({ openRail: () => setRailOpen(true), expandRail, collapsed, selectedLabel, }), [collapsed, expandRail, selectedLabel], ) const railHeaderRight = ( <> {headerRight} ) const rail = ( ) return (
{header} {banner}
{!collapsed ? ( ) : null}
{children}
Серверы
{extra}
) } export { ServerRailLayout, ServerRailMobileButton }