From 8a09b16c260961157b81e05f8181bdddcc7bef50 Mon Sep 17 00:00:00 2001 From: Developing-Gamer Date: Wed, 27 May 2026 12:47:45 -0700 Subject: [PATCH] Add account settings sidebar layout for dashboard. Co-authored-by: Cursor --- .../sidebar-layout.tsx | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 apps/dashboard/src/components/dashboard-account-settings/sidebar-layout.tsx diff --git a/apps/dashboard/src/components/dashboard-account-settings/sidebar-layout.tsx b/apps/dashboard/src/components/dashboard-account-settings/sidebar-layout.tsx new file mode 100644 index 000000000..ad905e9ac --- /dev/null +++ b/apps/dashboard/src/components/dashboard-account-settings/sidebar-layout.tsx @@ -0,0 +1,144 @@ +'use client'; + +import { useHash } from '@stackframe/stack-shared/dist/hooks/use-hash'; +import { Button } from '@/components/ui/button'; +import { cn } from '@/lib/utils'; +import { X } from '@phosphor-icons/react'; +import React, { ReactNode } from 'react'; +import { useStackApp } from '@stackframe/stack'; + +export type SidebarItem = { + title: React.ReactNode, + type: 'item' | 'divider', + description?: React.ReactNode, + id?: string, + icon?: React.ReactNode, + content?: React.ReactNode, + contentTitle?: React.ReactNode, +} + +export function SidebarLayout(props: { items: SidebarItem[], title?: ReactNode, className?: string }) { + const hash = useHash(); + const selectedIndex = props.items.findIndex(item => item.id && (item.id === hash)); + return ( + <> +
+ +
+
+ +
+ + ); +} + +function Items(props: { items: SidebarItem[], selectedIndex: number }) { + const app = useStackApp(); + const navigate = app.useNavigate(); + + const activeItemIndex = props.selectedIndex === -1 ? 0 : props.selectedIndex; + + return props.items.map((item, index) => ( + item.type === 'item' ? ( + + ) : ( +
+ {item.title} +
+ ) + )); +} + +function DesktopLayout(props: { items: SidebarItem[], title?: ReactNode, selectedIndex: number }) { + const selectedItem = props.items[props.selectedIndex === -1 ? 0 : props.selectedIndex]; + + return ( +
+
+ {props.title && ( +
+

+ {props.title} +

+
+ )} + + +
+
+
+
+

+ {selectedItem.contentTitle || selectedItem.title} +

+ {selectedItem.description && ( +

+ {selectedItem.description} +

+ )} +
+
+ {selectedItem.content} +
+
+
+
+ ); +} + +function MobileLayout(props: { items: SidebarItem[], title?: ReactNode, selectedIndex: number }) { + const selectedItem = props.items[props.selectedIndex]; + const app = useStackApp(); + const navigate = app.useNavigate(); + + if (props.selectedIndex === -1) { + return ( +
+ {props.title && ( +
+

{props.title}

+
+ )} + + +
+ ); + } else { + return ( +
+
+
+

{selectedItem.title}

+ +
+ {selectedItem.description &&

{selectedItem.description}

} +
+
+ {selectedItem.content} +
+
+ ); + } +}