metis-desk/modules/companies/src/web/components/workspace-sidebar.tsx

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>
);
}