import React, { useEffect, useState, useTransition } from "react"; import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.tsx"; import { Subtle } from "@components/UI/Typography/Subtle.tsx"; import { useDevice } from "@core/stores/deviceStore.ts"; import type { Page } from "@core/stores/deviceStore.ts"; import { Spinner } from "@components/UI/Spinner.tsx"; import { Avatar } from "@components/UI/Avatar.tsx"; import { CircleChevronLeft, CpuIcon, LayersIcon, type LucideIcon, MapIcon, MessageSquareIcon, PenLine, SearchIcon, SettingsIcon, UsersIcon, ZapIcon, } from "lucide-react"; import { cn } from "@core/utils/cn.ts"; import { useSidebar } from "@core/stores/sidebarStore.tsx"; import ThemeSwitcher from "@components/ThemeSwitcher.tsx"; import { useAppStore } from "@core/stores/appStore.ts"; import BatteryStatus from "@components/BatteryStatus.tsx"; import { SidebarButton } from "@components/UI/Sidebar/SidebarButton.tsx"; import { useTranslation } from "react-i18next"; export interface SidebarProps { children?: React.ReactNode; } interface NavLink { name: string; icon: LucideIcon; page: Page; count?: number; } const CollapseToggleButton = () => { const { isCollapsed, toggleSidebar } = useSidebar(); const { t } = useTranslation("ui"); const buttonLabel = isCollapsed ? t("sidebar.collapseToggle.button.open") : t("sidebar.collapseToggle.button.close"); return ( ); }; export const Sidebar = ({ children }: SidebarProps) => { const { hardware, getNode, getNodesLength, metadata, activePage, unreadCounts, setActivePage, setDialogOpen, } = useDevice(); const { setCommandPaletteOpen } = useAppStore(); const myNode = getNode(hardware.myNodeNum); const { isCollapsed } = useSidebar(); const { t } = useTranslation("ui"); const myMetadata = metadata.get(0); const numUnread = [...unreadCounts.values()].reduce((sum, v) => sum + v, 0); const [displayedNodeCount, setDisplayedNodeCount] = useState(() => Math.max(getNodesLength() - 1, 0) ); const [_, startNodeCountTransition] = useTransition(); const currentNodeCountValue = Math.max(getNodesLength() - 1, 0); useEffect(() => { if (currentNodeCountValue !== displayedNodeCount) { startNodeCountTransition(() => { setDisplayedNodeCount(currentNodeCountValue); }); } }, [currentNodeCountValue, displayedNodeCount, startNodeCountTransition]); const pages: NavLink[] = [ { name: t("navigation.messages"), icon: MessageSquareIcon, page: "messages", count: numUnread ? numUnread : undefined, }, { name: t("navigation.map"), icon: MapIcon, page: "map" }, { name: t("navigation.config"), icon: SettingsIcon, page: "config", }, { name: t("navigation.channels"), icon: LayersIcon, page: "channels", }, { name: `${t("navigation.nodes")} (${displayedNodeCount})`, icon: UsersIcon, page: "nodes", }, ]; return (
{t("app.logo")}

{t("app.title")}

{pages.map((link) => ( { if (myNode !== undefined) { setActivePage(link.page); } }} active={link.page === activePage} disabled={myNode === undefined} /> ))}
{children}
{myNode === undefined ? (
{t("loading")}
) : ( <>

{myNode.user?.longName}

{t("sidebar.deviceInfo.volts", { voltage: myNode.deviceMetrics?.voltage?.toPrecision(3) ?? t("unknown.shortName"), })}
{t("sidebar.deviceInfo.firmwareVersion", { version: myMetadata?.firmwareVersion ?? t("unknown.shortName"), })}
)}
); };