-
+
{children}
diff --git a/components/dashboard/Sidebar.tsx b/components/dashboard/Sidebar.tsx
index c4cd017..cf6bed2 100644
--- a/components/dashboard/Sidebar.tsx
+++ b/components/dashboard/Sidebar.tsx
@@ -3,8 +3,15 @@
import { useState, useEffect, useRef } from 'react'
import Link from 'next/link'
import { usePathname, useRouter } from 'next/navigation'
+import { motion } from 'framer-motion'
import { listSites, type Site } from '@/lib/api/sites'
import { useAuth } from '@/lib/auth/context'
+import {
+ Sidebar as SidebarPrimitive,
+ SidebarBody,
+ SidebarLink,
+ useSidebar,
+} from '@/components/ui/sidebar'
import {
LayoutDashboardIcon,
PathIcon,
@@ -14,16 +21,10 @@ import {
CloudUploadIcon,
HeartbeatIcon,
SettingsIcon,
- CollapseLeftIcon,
- CollapseRightIcon,
ChevronUpDownIcon,
PlusIcon,
- XIcon,
- MenuIcon,
} from '@ciphera-net/ui'
-const SIDEBAR_COLLAPSED_KEY = 'pulse_sidebar_collapsed'
-
interface NavItem {
label: string
href: (siteId: string) => string
@@ -63,22 +64,15 @@ const SETTINGS_ITEM: NavItem = {
matchPrefix: true,
}
-function SitePicker({
- sites,
- currentSiteId,
- collapsed,
-}: {
- sites: Site[]
- currentSiteId: string
- collapsed: boolean
-}) {
+function SitePicker({ sites, siteId }: { sites: Site[]; siteId: string }) {
+ const { open: sidebarOpen } = useSidebar()
const [open, setOpen] = useState(false)
const [search, setSearch] = useState('')
const ref = useRef
(null)
const pathname = usePathname()
const router = useRouter()
- const currentSite = sites.find((s) => s.id === currentSiteId)
+ const currentSite = sites.find((s) => s.id === siteId)
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
@@ -97,10 +91,9 @@ function SitePicker({
s.domain.toLowerCase().includes(search.toLowerCase())
)
- const switchSite = (siteId: string) => {
- // Preserve current page type
+ const switchSite = (id: string) => {
const currentPageType = pathname.replace(/^\/sites\/[^/]+/, '')
- router.push(`/sites/${siteId}${currentPageType}`)
+ router.push(`/sites/${id}${currentPageType}`)
setOpen(false)
setSearch('')
}
@@ -108,18 +101,15 @@ function SitePicker({
const initial = currentSite?.name?.charAt(0)?.toUpperCase() || '?'
return (
-
+
{open && (
-
+
switchSite(site.id)}
- className={`w-full flex items-center gap-2.5 px-4 py-2 text-sm transition-colors text-left ${
- site.id === currentSiteId
+ className={`w-full flex items-center gap-2.5 px-4 py-2 text-sm text-left ${
+ site.id === siteId
? 'bg-brand-orange/10 text-brand-orange font-medium'
: 'text-neutral-700 dark:text-neutral-300 hover:bg-neutral-50 dark:hover:bg-neutral-800'
}`}
@@ -167,7 +157,7 @@ function SitePicker({
setOpen(false)}
- className="flex items-center gap-2 px-3 py-1.5 text-sm text-brand-orange hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded-lg transition-colors"
+ className="flex items-center gap-2 px-3 py-1.5 text-sm text-brand-orange hover:bg-neutral-50 dark:hover:bg-neutral-800 rounded-lg"
>
Add new site
@@ -179,186 +169,110 @@ function SitePicker({
)
}
-function NavItemLink({
- item,
- siteId,
- collapsed,
- onClick,
-}: {
- item: NavItem
- siteId: string
- collapsed: boolean
- onClick?: () => void
-}) {
- const pathname = usePathname()
- const href = item.href(siteId)
- const isActive = item.matchPrefix ? pathname.startsWith(href) : pathname === href
-
- return (
-
-
- {!collapsed &&
{item.label}}
-
- )
-}
-
-export default function Sidebar({
- siteId,
- mobileOpen,
- onMobileClose,
-}: {
- siteId: string
- mobileOpen: boolean
- onMobileClose: () => void
-}) {
+function SidebarContent({ siteId }: { siteId: string }) {
const { user } = useAuth()
- const canEdit = user?.role === 'owner' || user?.role === 'admin'
- const [collapsed, setCollapsed] = useState(() => {
- if (typeof window === 'undefined') return false
- return localStorage.getItem(SIDEBAR_COLLAPSED_KEY) === 'true'
- })
- const [sites, setSites] = useState
([])
+ const { open } = useSidebar()
const pathname = usePathname()
-
- // Close mobile drawer on navigation
- useEffect(() => {
- onMobileClose()
- }, [pathname, onMobileClose])
+ const canEdit = user?.role === 'owner' || user?.role === 'admin'
+ const [sites, setSites] = useState([])
useEffect(() => {
- listSites()
- .then(setSites)
- .catch(() => {})
+ listSites().then(setSites).catch(() => {})
}, [])
- const toggleCollapsed = () => {
- const next = !collapsed
- setCollapsed(next)
- localStorage.setItem(SIDEBAR_COLLAPSED_KEY, String(next))
- }
-
- const sidebarContent = (isMobile: boolean) => {
- const isCollapsed = isMobile ? false : collapsed
-
- return (
-
- {/* Site Picker */}
-
-
-
-
- {/* Nav Groups */}
-
-
- {/* Bottom: Settings + Collapse toggle */}
-
- {canEdit && (
- onMobileClose() : undefined}
- />
- )}
- {!isMobile && (
-
- )}
-
-
- )
+ const isActive = (item: NavItem) => {
+ const href = item.href(siteId)
+ return item.matchPrefix ? pathname.startsWith(href) : pathname === href
}
return (
<>
- {/* Mobile hamburger trigger — rendered in the header via leftActions */}
+
+ {/* Site Picker */}
+
- {/* Desktop sidebar */}
-
-
- {/* Mobile overlay drawer */}
- {mobileOpen && (
- <>
-
onMobileClose()}
- />
-