87 lines
3.6 KiB
TypeScript
87 lines
3.6 KiB
TypeScript
import Link from "next/link";
|
|
import { Stethoscope } from "lucide-react";
|
|
|
|
import type { AccountOrganizationOption, Organization, Permission, PublicAccount } from "@/modules/core/types";
|
|
import { SignOutButton } from "@/modules/auth/components/SignOutButton";
|
|
import { AccountMenu } from "@/modules/shared/components/AccountMenu";
|
|
import { AppBreadcrumbs } from "@/modules/shared/components/AppBreadcrumbs";
|
|
import { AppSidebarNav } from "@/modules/shared/components/AppSidebarNav";
|
|
import { ThemeToggle } from "@/modules/shared/components/ThemeToggle";
|
|
import { UserAvatar } from "@/modules/shared/components/UserAvatar";
|
|
import { navItems } from "@/modules/shared/lib/navigation";
|
|
import { getWorkspaceHref } from "@/modules/shared/lib/workspace-routing";
|
|
|
|
type AppShellProps = {
|
|
children: React.ReactNode;
|
|
account: PublicAccount;
|
|
organization?: Organization;
|
|
organizations: AccountOrganizationOption[];
|
|
permissions: Permission[];
|
|
};
|
|
|
|
export function AppShell({
|
|
children,
|
|
account,
|
|
organization,
|
|
organizations,
|
|
permissions,
|
|
}: AppShellProps): React.ReactElement {
|
|
const organizationSlug = organization?.slug;
|
|
const dashboardHref = getWorkspaceHref(organizationSlug, "/dashboard");
|
|
|
|
return (
|
|
<div className="flex h-svh items-stretch overflow-hidden bg-background text-foreground">
|
|
<aside className="hidden h-svh w-64 shrink-0 border-r bg-card/78 backdrop-blur xl:block">
|
|
<div className="flex h-full min-h-0 flex-col">
|
|
<Link href={dashboardHref} className="flex h-16 shrink-0 items-center gap-3 border-b px-5">
|
|
<span className="inline-flex size-10 items-center justify-center rounded-md bg-primary text-primary-foreground">
|
|
<Stethoscope className="size-5" aria-hidden="true" />
|
|
</span>
|
|
<span>
|
|
<span className="block text-base font-semibold">TeaTea 康护</span>
|
|
</span>
|
|
</Link>
|
|
|
|
<AppSidebarNav organizationSlug={organizationSlug} permissions={permissions} />
|
|
|
|
<div className="border-t p-3">
|
|
<AccountMenu
|
|
account={account}
|
|
organization={organization}
|
|
organizations={organizations}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<div className="flex min-h-0 min-w-0 flex-1 flex-col">
|
|
<header className="sticky top-0 z-20 flex h-16 shrink-0 items-center justify-between border-b bg-background/88 px-4 backdrop-blur md:px-8">
|
|
<div className="flex items-center gap-3">
|
|
<span className="inline-flex size-10 items-center justify-center rounded-md bg-primary text-primary-foreground xl:hidden">
|
|
<Stethoscope className="size-5" aria-hidden="true" />
|
|
</span>
|
|
<AppBreadcrumbs />
|
|
</div>
|
|
<div className="flex min-w-0 items-center gap-2">
|
|
<ThemeToggle />
|
|
<div className="hidden min-w-0 items-center gap-2 sm:flex xl:hidden">
|
|
<p className="min-w-0 max-w-[min(52vw,24rem)] truncate whitespace-nowrap text-right text-sm leading-tight">
|
|
<span className="font-medium">{account.name}</span>
|
|
<span className="ml-2 text-muted-foreground">{account.email}</span>
|
|
</p>
|
|
<UserAvatar avatarUrl={account.avatarUrl} name={account.name} size="sm" />
|
|
</div>
|
|
<div className="xl:hidden">
|
|
<SignOutButton />
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main className="page-enter min-h-0 flex-1 overflow-y-auto px-4 py-5 md:px-8">{children}</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export { navItems };
|