diff --git a/apps/apollo-vertex/app/_components/preview-full-screen.tsx b/apps/apollo-vertex/app/_components/preview-full-screen.tsx
index a20ea3545..95377284f 100644
--- a/apps/apollo-vertex/app/_components/preview-full-screen.tsx
+++ b/apps/apollo-vertex/app/_components/preview-full-screen.tsx
@@ -31,7 +31,9 @@ export function PreviewFullScreen({
style={{ height }}
>
{!isOpen && (
-
{children}
+
+ {children}
+
)}
- {children}
+
+ {children}
+
);
diff --git a/apps/apollo-vertex/app/components/sidebar/page.mdx b/apps/apollo-vertex/app/components/sidebar/page.mdx
index 542542fa6..97415b083 100644
--- a/apps/apollo-vertex/app/components/sidebar/page.mdx
+++ b/apps/apollo-vertex/app/components/sidebar/page.mdx
@@ -1,12 +1,13 @@
+import { SidebarExampleTemplate } from '@/templates/SidebarTemplateDynamic';
+import { PreviewFullScreen } from '@/app/_components/preview-full-screen';
+
# Sidebar
A composable, themeable and customizable sidebar component.
-
-
- The Sidebar component is a complex layout component. See the usage example below for implementation details.
-
-
+
+
+
## Installation
@@ -42,19 +43,28 @@ import {
## Features
-- **Collapsible** - Can collapse to icons only
-- **Composable** - Build your own sidebar structure
-- **Themeable** - Supports dark mode and custom themes
-- **Responsive** - Works well on mobile and desktop
-- **Keyboard accessible** - Full keyboard navigation support
+- **Collapsible** - Can collapse to icons only with `collapsible="icon"`
+- **Composable** - Build your own sidebar structure with provided primitives
+- **Themeable** - Supports dark mode and custom themes via CSS variables
+- **Responsive** - Renders as a sheet on mobile, fixed sidebar on desktop
+- **Keyboard accessible** - Toggle with `⌘B`, full keyboard navigation support
## Components
- `SidebarProvider` - Provides context for sidebar state
- `Sidebar` - The main sidebar container
- `SidebarHeader` - Header section of the sidebar
-- `SidebarContent` - Main content area
+- `SidebarContent` - Main scrollable content area
- `SidebarFooter` - Footer section
- `SidebarGroup` - Groups related items
+- `SidebarGroupLabel` - Label for a group
+- `SidebarGroupContent` - Content wrapper for a group
- `SidebarMenu` - Navigation menu
+- `SidebarMenuButton` - Clickable menu button with tooltip support
- `SidebarMenuItem` - Individual menu items
+- `SidebarMenuSub` - Sub-menu container for nested navigation
+- `SidebarMenuSubButton` - Sub-menu item button
+- `SidebarMenuSubItem` - Sub-menu item wrapper
+- `SidebarInset` - Main content area adjacent to the sidebar
+- `SidebarTrigger` - Button to toggle sidebar open/closed
+- `SidebarRail` - Narrow rail for hover-to-expand interaction
diff --git a/apps/apollo-vertex/app/patterns/shell/page.mdx b/apps/apollo-vertex/app/patterns/shell/page.mdx
index 6bdd2e181..73eb2a884 100644
--- a/apps/apollo-vertex/app/patterns/shell/page.mdx
+++ b/apps/apollo-vertex/app/patterns/shell/page.mdx
@@ -19,6 +19,10 @@ Use the `variant="minimal"` prop to render a horizontal header layout instead of
## Features
+- **Collapsible Sidebar**: Icon-only collapsed mode with smooth spring animations, built on the shadcn sidebar primitives
+- **Sub-Navigation**: Collapsible menu items with nested sub-items that auto-expand when active
+- **Collapsed Menu Handling**: Clicking a collapsible item while collapsed expands the sidebar and opens the submenu
+- **Custom Logo**: Support for company logos with separate light/dark mode variants
- **Optional OAuth2 Authentication**: Plug-and-play authorization code flow with PKCE
- **Theme Toggle**: Built-in light/dark mode support
- **Language Toggle**: Built-in language switcher for internationalization
@@ -40,7 +44,15 @@ import { ApolloShell } from '@/components/ui/shell';
const navItems = [
{ path: '/dashboard', label: 'dashboard', icon: Home },
- { path: '/settings', label: 'settings', icon: Settings },
+ {
+ path: '/settings',
+ label: 'settings',
+ icon: Settings,
+ subItems: [
+ { path: '/settings', label: 'settings' },
+ { path: '/settings/appearance', label: 'appearance' },
+ ],
+ },
];
function App() {
diff --git a/apps/apollo-vertex/registry/shell/shell.tsx b/apps/apollo-vertex/registry/shell/shell.tsx
index b7b9a6bb1..b01d6392d 100644
--- a/apps/apollo-vertex/registry/shell/shell.tsx
+++ b/apps/apollo-vertex/registry/shell/shell.tsx
@@ -12,12 +12,19 @@ export interface CompanyLogo {
url: string;
darkUrl?: string;
alt: string;
+ isCustom?: boolean;
+}
+
+export interface ShellSubNavItem {
+ path: string;
+ label: TranslationKey;
}
export interface ShellNavItem {
path: string;
label: TranslationKey;
icon: LucideIcon;
+ subItems?: ShellSubNavItem[];
}
export interface ApolloShellProps extends PropsWithChildren {
diff --git a/apps/apollo-vertex/templates/SidebarTemplate.tsx b/apps/apollo-vertex/templates/SidebarTemplate.tsx
new file mode 100644
index 000000000..fcea77341
--- /dev/null
+++ b/apps/apollo-vertex/templates/SidebarTemplate.tsx
@@ -0,0 +1,200 @@
+"use client";
+
+import {
+ ChevronDown,
+ Home,
+ Inbox,
+ LayoutDashboard,
+ PanelLeft,
+ Search,
+ Settings,
+ User2,
+} from "lucide-react";
+import { useState } from "react";
+import {
+ Collapsible,
+ CollapsibleContent,
+ CollapsibleTrigger,
+} from "@/components/ui/collapsible";
+import {
+ Sidebar,
+ SidebarContent,
+ SidebarFooter,
+ SidebarGroup,
+ SidebarGroupContent,
+ SidebarGroupLabel,
+ SidebarHeader,
+ SidebarInset,
+ SidebarMenu,
+ SidebarMenuButton,
+ SidebarMenuItem,
+ SidebarMenuSub,
+ SidebarMenuSubButton,
+ SidebarMenuSubItem,
+ SidebarProvider,
+ useSidebar,
+} from "@/components/ui/sidebar";
+import { cn } from "@/lib/utils";
+
+const mainNavItems = [
+ { label: "Home", icon: Home },
+ { label: "Inbox", icon: Inbox },
+ { label: "Search", icon: Search },
+];
+
+const settingsSubItems = [
+ { label: "General" },
+ { label: "Appearance" },
+ { label: "Notifications" },
+];
+
+function SidebarHeaderContent() {
+ const { toggleSidebar, state } = useSidebar();
+ const isCollapsed = state === "collapsed";
+
+ return (
+
+ {!isCollapsed && (
+ <>
+
+
+ >
+ )}
+ {isCollapsed && (
+
+ )}
+
+ );
+}
+
+export function SidebarExample() {
+ const [active, setActive] = useState("Home");
+ const [settingsOpen, setSettingsOpen] = useState(false);
+
+ return (
+
+
+
+
+
+
+
+
+ Navigation
+
+
+ {mainNavItems.map((item) => (
+
+ {
+ setActive(item.label);
+ setSettingsOpen(false);
+ }}
+ >
+
+ {item.label}
+
+
+ ))}
+
+
+
+
+
+
+ Settings
+
+
+
+
+
+ {settingsSubItems.map((sub) => {
+ const subKey = `Settings: ${sub.label}`;
+ return (
+
+ setActive(subKey)}
+ >
+ {sub.label}
+
+
+ );
+ })}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ John Doe
+
+
+
+
+
+
+
+
+
{active}
+
+ Click a nav item or collapse the sidebar
+
+
+
+
+ );
+}
diff --git a/apps/apollo-vertex/templates/SidebarTemplateDynamic.tsx b/apps/apollo-vertex/templates/SidebarTemplateDynamic.tsx
new file mode 100644
index 000000000..4b2b37254
--- /dev/null
+++ b/apps/apollo-vertex/templates/SidebarTemplateDynamic.tsx
@@ -0,0 +1,11 @@
+"use client";
+
+import dynamic from "next/dynamic";
+
+export const SidebarExampleTemplate = dynamic(
+ () =>
+ import("./SidebarTemplate").then((mod) => ({
+ default: mod.SidebarExample,
+ })),
+ { ssr: false },
+);
diff --git a/apps/apollo-vertex/templates/shell/ShellRoot.tsx b/apps/apollo-vertex/templates/shell/ShellRoot.tsx
index a63fd2893..5a9d3d55d 100644
--- a/apps/apollo-vertex/templates/shell/ShellRoot.tsx
+++ b/apps/apollo-vertex/templates/shell/ShellRoot.tsx
@@ -8,7 +8,15 @@ const navItems: ShellNavItem[] = [
{ path: "/preview/shell/projects", label: "projects", icon: FolderOpen },
{ path: "/preview/shell/analytics", label: "analytics", icon: BarChart3 },
{ path: "/preview/shell/team", label: "team", icon: Users },
- { path: "/preview/shell/settings", label: "settings", icon: Settings },
+ {
+ path: "/preview/shell/settings",
+ label: "settings",
+ icon: Settings,
+ subItems: [
+ { path: "/preview/shell/settings", label: "settings" },
+ { path: "/preview/shell/team", label: "team" },
+ ],
+ },
];
const minimalNavItems: ShellNavItem[] = [