183 lines
6.6 KiB
TypeScript
183 lines
6.6 KiB
TypeScript
import { Button } from "@repo/shadcn-ui/components/button";
|
|
import {
|
|
BoxIcon,
|
|
Building2Icon,
|
|
ChevronRightIcon,
|
|
DatabaseIcon,
|
|
HomeIcon,
|
|
KeyRoundIcon,
|
|
LayersIcon,
|
|
LayoutTemplateIcon,
|
|
SettingsIcon,
|
|
TicketIcon,
|
|
WrenchIcon,
|
|
} from "@repo/shadcn-ui/lib/icons";
|
|
import type { ComponentProps } from "react";
|
|
import { useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import type { WorkspaceContent } from "./workspace-content";
|
|
import type { WorkspaceLocation } from "./workspace-location";
|
|
export function WorkspaceSidebar({
|
|
companies,
|
|
current,
|
|
catalog,
|
|
onNavigate,
|
|
onSelectCompany,
|
|
onSelectCatalog,
|
|
onSettings,
|
|
}: {
|
|
companies: readonly { id: string; name: string }[];
|
|
onNavigate: (location: WorkspaceLocation) => void;
|
|
onSelectCompany: (id: string) => void;
|
|
current: WorkspaceLocation;
|
|
catalog: ComponentProps<typeof WorkspaceContent>["catalog"];
|
|
onSelectCatalog: (catalog: ComponentProps<typeof WorkspaceContent>["catalog"]) => void;
|
|
onSettings: () => void;
|
|
}) {
|
|
const { t } = useTranslation("companies");
|
|
const { t: coreTranslation } = useTranslation("core");
|
|
const { t: resourceTranslation } = useTranslation("resources");
|
|
const { t: assetTranslation } = useTranslation("assets");
|
|
const { t: accessTranslation } = useTranslation("access");
|
|
const [collapsed, setCollapsed] = useState(false);
|
|
return (
|
|
<aside className="desk-sidebar" data-collapsed={collapsed}>
|
|
<div aria-label="Metis Desk" className="desk-brand" role="img">
|
|
<svg aria-hidden="true" viewBox="0 0 36 30">
|
|
<path
|
|
d="M5 24 13 7l9 17 9-18"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth="7"
|
|
/>
|
|
</svg>
|
|
<span>Metis Desk</span>
|
|
</div>
|
|
<nav aria-label={t("companySpaces")} className="desk-company-rail">
|
|
{(
|
|
[
|
|
["home", "dashboard.title", HomeIcon],
|
|
["directory", "title", Building2Icon],
|
|
["catalogs", "shell.catalogs", DatabaseIcon],
|
|
["tickets", "shell.tickets", TicketIcon],
|
|
["interventions", "shell.interventions", WrenchIcon],
|
|
] as const
|
|
).map(([area, label, Icon]) => (
|
|
<Button
|
|
aria-label={t(label)}
|
|
aria-pressed={current.area === area}
|
|
className="desk-space-button"
|
|
key={area}
|
|
onClick={() => onNavigate({ area })}
|
|
title={t(label)}
|
|
variant="ghost"
|
|
>
|
|
<Icon aria-hidden="true" />
|
|
<span>{t(label)}</span>
|
|
{area === "catalogs" && (
|
|
<ChevronRightIcon aria-hidden="true" className="desk-nav-chevron" />
|
|
)}
|
|
</Button>
|
|
))}
|
|
{current.area === "catalogs" && (
|
|
<nav aria-label={t("globalCatalogs")} className="desk-catalog-navigation">
|
|
<>
|
|
<Button
|
|
aria-label={accessTranslation("catalogTitle")}
|
|
aria-pressed={catalog === "access"}
|
|
onClick={() => onSelectCatalog("access")}
|
|
title={accessTranslation("catalogTitle")}
|
|
variant="ghost"
|
|
>
|
|
<KeyRoundIcon aria-hidden="true" />
|
|
<span>{accessTranslation("catalogTitle")}</span>
|
|
</Button>
|
|
<Button
|
|
aria-label={assetTranslation("title")}
|
|
aria-pressed={catalog === "assets"}
|
|
onClick={() => onSelectCatalog("assets")}
|
|
title={assetTranslation("title")}
|
|
variant="ghost"
|
|
>
|
|
<BoxIcon aria-hidden="true" />
|
|
<span>{assetTranslation("title")}</span>
|
|
</Button>
|
|
<Button
|
|
aria-label={t("interventionTemplates.title")}
|
|
aria-pressed={catalog === "intervention-templates"}
|
|
onClick={() => onSelectCatalog("intervention-templates")}
|
|
title={t("interventionTemplates.title")}
|
|
variant="ghost"
|
|
>
|
|
<LayoutTemplateIcon aria-hidden="true" />
|
|
<span>{t("interventionTemplates.title")}</span>
|
|
</Button>
|
|
<Button
|
|
aria-label={assetTranslation("brands.title")}
|
|
aria-pressed={catalog === "brands"}
|
|
onClick={() => onSelectCatalog("brands")}
|
|
title={assetTranslation("brands.title")}
|
|
variant="ghost"
|
|
>
|
|
<LayersIcon aria-hidden="true" />
|
|
<span>{assetTranslation("brands.title")}</span>
|
|
</Button>
|
|
<Button
|
|
aria-label={resourceTranslation("title")}
|
|
aria-pressed={catalog === "resources"}
|
|
onClick={() => onSelectCatalog("resources")}
|
|
title={resourceTranslation("title")}
|
|
variant="ghost"
|
|
>
|
|
<DatabaseIcon aria-hidden="true" />
|
|
<span>{resourceTranslation("title")}</span>
|
|
</Button>
|
|
</>
|
|
</nav>
|
|
)}
|
|
<div className="desk-rail-separator" />
|
|
{companies.map((company) => (
|
|
<Button
|
|
aria-label={company.name}
|
|
aria-pressed={current.area === "company" && current.id === company.id}
|
|
className="desk-space-button"
|
|
key={company.id}
|
|
onClick={() => onSelectCompany(company.id)}
|
|
title={company.name}
|
|
variant="ghost"
|
|
>
|
|
<Building2Icon aria-hidden="true" />
|
|
<span>{company.name}</span>
|
|
</Button>
|
|
))}
|
|
</nav>
|
|
<footer className="desk-sidebar-footer">
|
|
<Button
|
|
aria-label={coreTranslation("shell.settings")}
|
|
className="desk-space-button"
|
|
onClick={onSettings}
|
|
title={coreTranslation("shell.settings")}
|
|
variant="ghost"
|
|
>
|
|
<SettingsIcon aria-hidden="true" />
|
|
<span>{coreTranslation("shell.settings")}</span>
|
|
</Button>
|
|
<Button
|
|
aria-expanded={!collapsed}
|
|
aria-label={coreTranslation(collapsed ? "shell.expandSidebar" : "shell.collapseSidebar")}
|
|
className="desk-space-button desk-sidebar-toggle"
|
|
onClick={() => setCollapsed((value) => !value)}
|
|
title={coreTranslation(collapsed ? "shell.expandSidebar" : "shell.collapseSidebar")}
|
|
variant="ghost"
|
|
>
|
|
<ChevronRightIcon aria-hidden="true" />
|
|
<span>{coreTranslation("shell.collapseSidebar")}</span>
|
|
</Button>
|
|
</footer>
|
|
</aside>
|
|
);
|
|
}
|