nested sidebar

This commit is contained in:
miloschwartz
2025-04-12 21:35:17 -04:00
parent 2398931cc1
commit b731a50cc9
8 changed files with 255 additions and 144 deletions

View File

@@ -1,4 +1,3 @@
import ProfileIcon from "@app/components/ProfileIcon";
import { verifySession } from "@app/lib/auth/verifySession";
import UserProvider from "@app/providers/UserProvider";
import { cache } from "react";
@@ -8,6 +7,8 @@ import { internal } from "@app/lib/api";
import { AxiosResponse } from "axios";
import { authCookieHeader } from "@app/lib/api/cookies";
import { redirect } from "next/navigation";
import { Layout } from "@app/components/Layout";
import { orgNavItems } from "../navigation";
type OrgPageProps = {
params: Promise<{ orgId: string }>;
@@ -20,6 +21,10 @@ export default async function OrgPage(props: OrgPageProps) {
const getUser = cache(verifySession);
const user = await getUser();
if (!user) {
redirect("/");
}
let redirectToSettings = false;
let overview: GetOrgOverviewResponse | undefined;
try {
@@ -39,14 +44,11 @@ export default async function OrgPage(props: OrgPageProps) {
}
return (
<>
<div className="p-3">
{user && (
<UserProvider user={user}>
<ProfileIcon />
</UserProvider>
)}
<UserProvider user={user}>
<Layout
orgId={orgId}
navItems={orgNavItems}
>
{overview && (
<div className="w-full max-w-4xl mx-auto md:mt-32 mt-4">
<OrganizationLandingCard
@@ -65,7 +67,7 @@ export default async function OrgPage(props: OrgPageProps) {
/>
</div>
)}
</div>
</>
</Layout>
</UserProvider>
);
}

View File

@@ -8,6 +8,7 @@ import OrgProvider from "@app/providers/OrgProvider";
import UserProvider from "@app/providers/UserProvider";
import { verifySession } from "@app/lib/auth/verifySession";
import AccessPageHeaderAndNav from "../AccessPageHeaderAndNav";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
type InvitationsPageProps = {
params: Promise<{ orgId: string }>;
@@ -72,13 +73,15 @@ export default async function InvitationsPage(props: InvitationsPageProps) {
return (
<>
<AccessPageHeaderAndNav hasInvitations={hasInvitations}>
<UserProvider user={user!}>
<OrgProvider org={org}>
<InvitationsTable invitations={invitationRows} />
</OrgProvider>
</UserProvider>
</AccessPageHeaderAndNav>
<SettingsSectionTitle
title="Open Invitations"
description="Manage your invitations to other users"
/>
<UserProvider user={user!}>
<OrgProvider org={org}>
<InvitationsTable invitations={invitationRows} />
</OrgProvider>
</UserProvider>
</>
);
}

View File

@@ -17,6 +17,7 @@ import { cache } from "react";
import { GetOrgUserResponse } from "@server/routers/user";
import UserProvider from "@app/providers/UserProvider";
import { Layout } from "@app/components/Layout";
import { SidebarNavItem, SidebarNavProps } from "@app/components/SidebarNav";
export const dynamic = "force-dynamic";
@@ -25,25 +26,32 @@ export const metadata: Metadata = {
description: ""
};
const navItems = [
const navItems: SidebarNavItem[] = [
{
title: "Sites",
href: "/{orgId}/settings/sites",
href: "/{orgId}/settings/sites"
// icon: <Combine className="h-4 w-4" />
},
{
title: "Resources",
href: "/{orgId}/settings/resources",
href: "/{orgId}/settings/resources"
// icon: <Waypoints className="h-4 w-4" />
},
{
title: "Access Control",
href: "/{orgId}/settings/access",
// icon: <Users className="h-4 w-4" />,
autoExpand: true,
children: [
{
title: "Users",
href: "/{orgId}/settings/access/users"
href: "/{orgId}/settings/access/users",
children: [
{
title: "Invitations",
href: "/{orgId}/settings/access/invitations"
}
]
},
{
title: "Roles",
@@ -53,12 +61,12 @@ const navItems = [
},
{
title: "Shareable Links",
href: "/{orgId}/settings/share-links",
href: "/{orgId}/settings/share-links"
// icon: <LinkIcon className="h-4 w-4" />
},
{
title: "General",
href: "/{orgId}/settings/general",
href: "/{orgId}/settings/general"
// icon: <Settings className="h-4 w-4" />
}
];

View File

@@ -19,7 +19,7 @@
--accent-foreground: hsl(24 9.8% 10%);
--destructive: hsl(0 84.2% 60.2%);
--destructive-foreground: hsl(60 9.1% 97.8%);
--border: hsl(20 5.9% 80%);
--border: hsl(20 5.9% 90%);
--input: hsl(20 5.9% 75%);
--ring: hsl(24.6 95% 53.1%);
--radius: 0.50rem;

52
src/app/navigation.tsx Normal file
View File

@@ -0,0 +1,52 @@
import { Home, Settings, Users, Link as LinkIcon, Waypoints, Combine } from "lucide-react";
export const rootNavItems = [
{
title: "Home",
href: "/",
icon: <Home className="h-4 w-4" />
}
];
export const orgNavItems = [
{
title: "Overview",
href: "/{orgId}",
icon: <Home className="h-4 w-4" />
},
{
title: "Sites",
href: "/{orgId}/settings/sites",
icon: <Combine className="h-4 w-4" />
},
{
title: "Resources",
href: "/{orgId}/settings/resources",
icon: <Waypoints className="h-4 w-4" />
},
{
title: "Access Control",
href: "/{orgId}/settings/access",
icon: <Users className="h-4 w-4" />,
children: [
{
title: "Users",
href: "/{orgId}/settings/access/users"
},
{
title: "Roles",
href: "/{orgId}/settings/access/roles"
}
]
},
{
title: "Shareable Links",
href: "/{orgId}/settings/share-links",
icon: <LinkIcon className="h-4 w-4" />
},
{
title: "Settings",
href: "/{orgId}/settings/general",
icon: <Settings className="h-4 w-4" />
}
];

View File

@@ -1,17 +1,16 @@
import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
import ProfileIcon from "@app/components/ProfileIcon";
import { verifySession } from "@app/lib/auth/verifySession";
import UserProvider from "@app/providers/UserProvider";
import { ListOrgsResponse } from "@server/routers/org";
import { AxiosResponse } from "axios";
import { ArrowUpRight } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { cache } from "react";
import OrganizationLanding from "./components/OrganizationLanding";
import { pullEnv } from "@app/lib/pullEnv";
import { cleanRedirect } from "@app/lib/cleanRedirect";
import { Layout } from "@app/components/Layout";
import { rootNavItems } from "./navigation";
export const dynamic = "force-dynamic";
@@ -71,16 +70,12 @@ export default async function Page(props: {
}
return (
<>
<div className="p-3">
{user && (
<UserProvider user={user}>
<div>
<ProfileIcon />
</div>
</UserProvider>
)}
<UserProvider user={user}>
<Layout
orgs={orgs}
navItems={rootNavItems}
showBreadcrumbs={false}
>
<div className="w-full max-w-md mx-auto md:mt-32 mt-4">
<OrganizationLanding
disableCreateOrg={env.flags.disableUserCreateOrg && !user.serverAdmin}
@@ -90,7 +85,7 @@ export default async function Page(props: {
}))}
/>
</div>
</div>
</>
</Layout>
</UserProvider>
);
}