@djangocfg/layouts 1.4.30 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +277 -18
- package/package.json +15 -24
- package/src/auth/context/AuthContext.tsx +5 -5
- package/src/auth/hooks/useAuthGuard.ts +1 -1
- package/src/auth/hooks/useAutoAuth.ts +8 -7
- package/src/components/ErrorBoundary.tsx +78 -0
- package/src/components/JsonLd.tsx +31 -0
- package/src/components/LucideIcon.tsx +91 -0
- package/src/components/PageProgress.tsx +127 -0
- package/src/components/Suspense.tsx +29 -0
- package/src/{layouts/AppLayout/components → components}/UpdateNotifier/UpdateNotifier.tsx +56 -49
- package/src/components/index.ts +10 -0
- package/src/index.ts +25 -7
- package/src/layouts/AdminLayout/AdminLayout.tsx +46 -0
- package/src/layouts/AdminLayout/index.ts +7 -0
- package/src/layouts/AppLayout/AppLayout.tsx +278 -326
- package/src/layouts/AppLayout/index.ts +2 -39
- package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/AuthContext.tsx +3 -2
- package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/AuthHelp.tsx +1 -0
- package/src/layouts/AuthLayout/AuthLayout.tsx +61 -0
- package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/IdentifierForm.tsx +47 -34
- package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/OTPForm.tsx +2 -3
- package/src/layouts/AuthLayout/index.ts +24 -0
- package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/types.ts +1 -0
- package/src/layouts/PrivateLayout/PrivateLayout.tsx +144 -0
- package/src/layouts/PrivateLayout/components/PrivateContent.tsx +32 -0
- package/src/layouts/PrivateLayout/components/PrivateHeader.tsx +57 -0
- package/src/layouts/PrivateLayout/components/PrivateSidebar.tsx +141 -0
- package/src/layouts/PrivateLayout/components/index.ts +8 -0
- package/src/layouts/PrivateLayout/index.ts +7 -0
- package/src/layouts/ProfileLayout/ProfileLayout.tsx +15 -7
- package/src/layouts/PublicLayout/PublicLayout.tsx +121 -0
- package/src/layouts/PublicLayout/components/PublicFooter.tsx +190 -0
- package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +117 -0
- package/src/layouts/PublicLayout/components/PublicNavigation.tsx +101 -0
- package/src/layouts/PublicLayout/components/index.ts +8 -0
- package/src/layouts/PublicLayout/index.ts +7 -0
- package/src/layouts/_components/UserMenu.tsx +160 -0
- package/src/layouts/_components/index.ts +7 -0
- package/src/layouts/index.ts +15 -8
- package/src/snippets/Analytics/AnalyticsProvider.tsx +8 -4
- package/src/snippets/Analytics/useAnalytics.ts +11 -21
- package/src/snippets/Chat/ChatWidget.tsx +4 -4
- package/src/snippets/ContactForm/ContactFormProvider.tsx +32 -19
- package/src/snippets/ContactForm/ContactPage.tsx +2 -4
- package/src/snippets/ContactForm/types.ts +3 -2
- package/src/snippets/index.ts +0 -1
- package/src/layouts/AppLayout/README.md +0 -204
- package/src/layouts/AppLayout/SUMMARY.md +0 -240
- package/src/layouts/AppLayout/USAGE.md +0 -312
- package/src/layouts/AppLayout/components/ErrorBoundary.tsx +0 -112
- package/src/layouts/AppLayout/components/PageProgress.tsx +0 -123
- package/src/layouts/AppLayout/components/Seo.tsx +0 -171
- package/src/layouts/AppLayout/components/UserMenu.tsx +0 -385
- package/src/layouts/AppLayout/components/index.ts +0 -11
- package/src/layouts/AppLayout/context/AppContext.tsx +0 -151
- package/src/layouts/AppLayout/context/index.ts +0 -5
- package/src/layouts/AppLayout/hooks/index.ts +0 -8
- package/src/layouts/AppLayout/hooks/useLayoutMode.ts +0 -26
- package/src/layouts/AppLayout/hooks/useNavigation.ts +0 -51
- package/src/layouts/AppLayout/layouts/AdminLayout/AdminLayout.tsx +0 -224
- package/src/layouts/AppLayout/layouts/AdminLayout/README.md +0 -409
- package/src/layouts/AppLayout/layouts/AdminLayout/components/PagePreloader.example.tsx +0 -98
- package/src/layouts/AppLayout/layouts/AdminLayout/components/PagePreloader.tsx +0 -149
- package/src/layouts/AppLayout/layouts/AdminLayout/components/ParentSync.tsx +0 -146
- package/src/layouts/AppLayout/layouts/AdminLayout/components/index.ts +0 -3
- package/src/layouts/AppLayout/layouts/AdminLayout/context/CfgAppContext.tsx +0 -48
- package/src/layouts/AppLayout/layouts/AdminLayout/context/index.ts +0 -2
- package/src/layouts/AppLayout/layouts/AdminLayout/hooks/index.ts +0 -6
- package/src/layouts/AppLayout/layouts/AdminLayout/hooks/useApp.ts +0 -279
- package/src/layouts/AppLayout/layouts/AdminLayout/index.ts +0 -24
- package/src/layouts/AppLayout/layouts/AdminLayout/lottie/energizing.json +0 -1
- package/src/layouts/AppLayout/layouts/AdminLayout/types/index.ts +0 -45
- package/src/layouts/AppLayout/layouts/AuthLayout/AuthLayout.tsx +0 -41
- package/src/layouts/AppLayout/layouts/AuthLayout/index.ts +0 -15
- package/src/layouts/AppLayout/layouts/PrivateLayout/PrivateLayout.tsx +0 -82
- package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardContent.tsx +0 -62
- package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardHeader.tsx +0 -89
- package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardSidebar.tsx +0 -181
- package/src/layouts/AppLayout/layouts/PrivateLayout/components/index.ts +0 -9
- package/src/layouts/AppLayout/layouts/PrivateLayout/index.ts +0 -5
- package/src/layouts/AppLayout/layouts/PublicLayout/PublicLayout.tsx +0 -44
- package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +0 -242
- package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileDrawer.tsx +0 -150
- package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +0 -169
- package/src/layouts/AppLayout/layouts/PublicLayout/index.ts +0 -5
- package/src/layouts/AppLayout/layouts/index.ts +0 -7
- package/src/layouts/AppLayout/providers/CoreProviders.tsx +0 -80
- package/src/layouts/AppLayout/providers/index.ts +0 -5
- package/src/layouts/AppLayout/types/config.ts +0 -79
- package/src/layouts/AppLayout/types/index.ts +0 -11
- package/src/layouts/AppLayout/types/layout.ts +0 -54
- package/src/layouts/AppLayout/types/navigation.ts +0 -43
- package/src/layouts/AppLayout/types/page.ts +0 -80
- package/src/layouts/AppLayout/types/routes.ts +0 -43
- package/src/layouts/AppLayout/utils/index.ts +0 -5
- package/src/layouts/AppLayout/utils/routeDetection.ts +0 -31
- package/src/layouts/ErrorLayout/ErrorLayout.tsx +0 -173
- package/src/layouts/ErrorLayout/errorConfig.tsx +0 -152
- package/src/layouts/ErrorLayout/index.ts +0 -8
- package/src/layouts/SimpleLayout/SimpleLayout.tsx +0 -72
- package/src/layouts/SimpleLayout/index.ts +0 -3
- package/src/snippets/VideoPlayer/README.md +0 -238
- package/src/snippets/VideoPlayer/VideoControls.tsx +0 -137
- package/src/snippets/VideoPlayer/VideoPlayer.tsx +0 -248
- package/src/snippets/VideoPlayer/index.ts +0 -8
- package/src/snippets/VideoPlayer/types.ts +0 -61
- package/src/types/index.ts +0 -2
- package/src/types/pageConfig.ts +0 -100
- /package/src/{validation → components/ErrorsTracker}/README.md +0 -0
- /package/src/{validation → components/ErrorsTracker}/components/ErrorButtons.tsx +0 -0
- /package/src/{validation → components/ErrorsTracker}/components/ErrorToast.tsx +0 -0
- /package/src/{validation → components/ErrorsTracker}/hooks.ts +0 -0
- /package/src/{validation → components/ErrorsTracker}/index.ts +0 -0
- /package/src/{validation → components/ErrorsTracker}/providers/ErrorTrackingProvider.tsx +0 -0
- /package/src/{validation → components/ErrorsTracker}/types.ts +0 -0
- /package/src/{validation → components/ErrorsTracker}/utils/curl-generator.ts +0 -0
- /package/src/{validation → components/ErrorsTracker}/utils/formatters.ts +0 -0
- /package/src/{layouts/AppLayout/components → components}/UpdateNotifier/index.ts +0 -0
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
/**
|
|
3
|
-
* Private Layout
|
|
4
|
-
*
|
|
5
|
-
* Dashboard layout for authenticated pages
|
|
6
|
-
* Refactored from _old/DashboardLayout - uses context only!
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
'use client';
|
|
10
|
-
|
|
11
|
-
import React, { ReactNode, useEffect } from 'react';
|
|
12
|
-
import { SidebarInset, SidebarProvider } from '@djangocfg/ui/components';
|
|
13
|
-
import { useAuth } from '../../../../auth';
|
|
14
|
-
import { KnowledgeChat } from '../../../../snippets/Chat';
|
|
15
|
-
import { useAppContext } from '../../context';
|
|
16
|
-
import { DashboardContent, DashboardHeader, DashboardSidebar } from './components';
|
|
17
|
-
|
|
18
|
-
export interface PrivateLayoutProps {
|
|
19
|
-
children: ReactNode;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Private Layout Component
|
|
24
|
-
*
|
|
25
|
-
* Features:
|
|
26
|
-
* - SidebarProvider for collapsible sidebar
|
|
27
|
-
* - DashboardSidebar with navigation
|
|
28
|
-
* - DashboardHeader with user menu, notifications, theme toggle
|
|
29
|
-
* - DashboardContent with configurable padding
|
|
30
|
-
* - KnowledgeChat (optional)
|
|
31
|
-
* - Auth loading state
|
|
32
|
-
* - Auth redirect for unauthenticated users
|
|
33
|
-
*
|
|
34
|
-
* All data from useAppContext() - no props!
|
|
35
|
-
*/
|
|
36
|
-
export function PrivateLayout({ children }: PrivateLayoutProps) {
|
|
37
|
-
const { config } = useAppContext();
|
|
38
|
-
const { isLoading, isAuthenticated } = useAuth();
|
|
39
|
-
|
|
40
|
-
const { privateLayout, routes } = config;
|
|
41
|
-
|
|
42
|
-
// Redirect unauthenticated users (only when not loading)
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
if (!isLoading && !isAuthenticated) {
|
|
45
|
-
const redirect = routes.detectors.getUnauthenticatedRedirect(
|
|
46
|
-
window.location.pathname
|
|
47
|
-
);
|
|
48
|
-
if (redirect) {
|
|
49
|
-
window.location.href = redirect;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}, [isLoading, isAuthenticated, routes]);
|
|
53
|
-
|
|
54
|
-
// Don't render content if user is not authenticated
|
|
55
|
-
// Note: Loading state is now handled in AppLayout, so we don't show it here
|
|
56
|
-
if (!isAuthenticated) {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<>
|
|
62
|
-
<SidebarProvider defaultOpen={true}>
|
|
63
|
-
{/* Sidebar */}
|
|
64
|
-
<DashboardSidebar />
|
|
65
|
-
|
|
66
|
-
{/* Main content area */}
|
|
67
|
-
<SidebarInset className="flex flex-col">
|
|
68
|
-
{/* Header */}
|
|
69
|
-
<DashboardHeader />
|
|
70
|
-
|
|
71
|
-
{/* Page content */}
|
|
72
|
-
<div className="flex-1 overflow-y-auto">
|
|
73
|
-
<DashboardContent>{children}</DashboardContent>
|
|
74
|
-
</div>
|
|
75
|
-
</SidebarInset>
|
|
76
|
-
</SidebarProvider>
|
|
77
|
-
|
|
78
|
-
{/* Chat positioned outside main layout for proper fixed positioning */}
|
|
79
|
-
{privateLayout.showChat && <KnowledgeChat />}
|
|
80
|
-
</>
|
|
81
|
-
);
|
|
82
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dashboard Content
|
|
3
|
-
*
|
|
4
|
-
* Main content wrapper for dashboard pages
|
|
5
|
-
* Refactored from _old/DashboardLayout - uses context only!
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
'use client';
|
|
9
|
-
|
|
10
|
-
import React from 'react';
|
|
11
|
-
import { cn } from '@djangocfg/ui/lib';
|
|
12
|
-
import { useAppContext } from '../../../context';
|
|
13
|
-
|
|
14
|
-
interface DashboardContentProps {
|
|
15
|
-
children: React.ReactNode;
|
|
16
|
-
className?: string;
|
|
17
|
-
isAdmin?: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const paddingVariants = {
|
|
21
|
-
none: '',
|
|
22
|
-
default: 'p-6',
|
|
23
|
-
sm: 'p-4',
|
|
24
|
-
md: 'p-6',
|
|
25
|
-
lg: 'p-8',
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Dashboard Content Component
|
|
30
|
-
*
|
|
31
|
-
* Features:
|
|
32
|
-
* - Configurable padding from context
|
|
33
|
-
* - Full-width container
|
|
34
|
-
* - Custom className support
|
|
35
|
-
*
|
|
36
|
-
* Padding controlled by config.privateLayout.contentPadding
|
|
37
|
-
*/
|
|
38
|
-
export function DashboardContent({
|
|
39
|
-
children,
|
|
40
|
-
className,
|
|
41
|
-
isAdmin = false,
|
|
42
|
-
}: DashboardContentProps) {
|
|
43
|
-
const { config } = useAppContext();
|
|
44
|
-
const { privateLayout } = config;
|
|
45
|
-
|
|
46
|
-
const padding =
|
|
47
|
-
paddingVariants[
|
|
48
|
-
privateLayout.contentPadding as keyof typeof paddingVariants
|
|
49
|
-
] || paddingVariants.default;
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<main
|
|
53
|
-
className={cn(
|
|
54
|
-
'w-full bg-background relative min-h-full',
|
|
55
|
-
padding,
|
|
56
|
-
className
|
|
57
|
-
)}
|
|
58
|
-
>
|
|
59
|
-
{children}
|
|
60
|
-
</main>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dashboard Header
|
|
3
|
-
*
|
|
4
|
-
* Header for private/dashboard layout
|
|
5
|
-
* Refactored from _old/DashboardLayout - uses context only!
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
'use client';
|
|
9
|
-
|
|
10
|
-
import { Bell } from 'lucide-react';
|
|
11
|
-
import React from 'react';
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
Button,
|
|
15
|
-
Separator,
|
|
16
|
-
SidebarTrigger,
|
|
17
|
-
} from '@djangocfg/ui';
|
|
18
|
-
import { ThemeToggle } from '@djangocfg/ui/theme';
|
|
19
|
-
import { useAppContext } from '../../../context';
|
|
20
|
-
import { useNavigation } from '../../../hooks';
|
|
21
|
-
import { UserMenu } from '../../../components';
|
|
22
|
-
|
|
23
|
-
export interface DashboardHeaderProps {
|
|
24
|
-
isAdmin?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Dashboard Header Component
|
|
29
|
-
*
|
|
30
|
-
* Features:
|
|
31
|
-
* - Sidebar trigger (mobile)
|
|
32
|
-
* - Page title
|
|
33
|
-
* - Custom header actions
|
|
34
|
-
* - Notifications button with badge
|
|
35
|
-
* - Theme toggle
|
|
36
|
-
* - User dropdown with avatar, profile, logout
|
|
37
|
-
* - Login button for guests
|
|
38
|
-
*
|
|
39
|
-
* All data from context!
|
|
40
|
-
*/
|
|
41
|
-
export function DashboardHeader({ isAdmin = false }: DashboardHeaderProps) {
|
|
42
|
-
const { config } = useAppContext();
|
|
43
|
-
const { getPageTitle } = useNavigation();
|
|
44
|
-
|
|
45
|
-
const { privateLayout } = config;
|
|
46
|
-
const pageTitle = getPageTitle();
|
|
47
|
-
|
|
48
|
-
// Notification handler - TODO: implement notification system
|
|
49
|
-
const handleNotificationClick = () => {
|
|
50
|
-
// console.log('Notifications clicked');
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<header className="sticky top-0 py-2 z-10 h-16 flex items-center justify-between px-4 shrink-0 bg-background border-b border-border">
|
|
55
|
-
{/* Left side */}
|
|
56
|
-
<div className="flex items-center gap-4">
|
|
57
|
-
<SidebarTrigger className="-ml-1" />
|
|
58
|
-
<Separator orientation="vertical" className="mr-2 h-4" />
|
|
59
|
-
|
|
60
|
-
{pageTitle && (
|
|
61
|
-
<h1 className="text-lg font-semibold text-foreground">{pageTitle}</h1>
|
|
62
|
-
)}
|
|
63
|
-
</div>
|
|
64
|
-
|
|
65
|
-
{/* Right side */}
|
|
66
|
-
<div className="flex items-center gap-3">
|
|
67
|
-
{/* Custom header actions */}
|
|
68
|
-
{privateLayout.headerActions}
|
|
69
|
-
|
|
70
|
-
{/* Notifications */}
|
|
71
|
-
<Button
|
|
72
|
-
variant="ghost"
|
|
73
|
-
size="icon"
|
|
74
|
-
className="relative"
|
|
75
|
-
onClick={handleNotificationClick}
|
|
76
|
-
>
|
|
77
|
-
<Bell className="h-5 w-5" />
|
|
78
|
-
{/* TODO: implement notification count from context */}
|
|
79
|
-
</Button>
|
|
80
|
-
|
|
81
|
-
{/* Theme Toggle */}
|
|
82
|
-
<ThemeToggle />
|
|
83
|
-
|
|
84
|
-
{/* User menu - unified component */}
|
|
85
|
-
<UserMenu variant="desktop" />
|
|
86
|
-
</div>
|
|
87
|
-
</header>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dashboard Sidebar
|
|
3
|
-
*
|
|
4
|
-
* Sidebar navigation for private/dashboard layout
|
|
5
|
-
* Refactored from _old/DashboardLayout - uses context only!
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
'use client';
|
|
9
|
-
|
|
10
|
-
import Link from 'next/link';
|
|
11
|
-
import React from 'react';
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
Sidebar,
|
|
15
|
-
SidebarContent,
|
|
16
|
-
SidebarFooter,
|
|
17
|
-
SidebarGroup,
|
|
18
|
-
SidebarGroupContent,
|
|
19
|
-
SidebarGroupLabel,
|
|
20
|
-
SidebarHeader,
|
|
21
|
-
SidebarMenu,
|
|
22
|
-
SidebarMenuBadge,
|
|
23
|
-
SidebarMenuButton,
|
|
24
|
-
SidebarMenuItem,
|
|
25
|
-
SidebarMenuSub,
|
|
26
|
-
SidebarMenuSubButton,
|
|
27
|
-
SidebarMenuSubItem,
|
|
28
|
-
useSidebar,
|
|
29
|
-
} from '@djangocfg/ui/components';
|
|
30
|
-
import { useAppContext } from '../../../context';
|
|
31
|
-
import { useNavigation } from '../../../hooks';
|
|
32
|
-
|
|
33
|
-
export interface DashboardSidebarProps {
|
|
34
|
-
isAdmin?: boolean;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Dashboard Sidebar Component
|
|
39
|
-
*
|
|
40
|
-
* Features:
|
|
41
|
-
* - Project logo and name (clickable to home)
|
|
42
|
-
* - Menu groups with labels
|
|
43
|
-
* - Menu items with icons, labels, badges
|
|
44
|
-
* - Sub-menu items (nested navigation)
|
|
45
|
-
* - Active state detection
|
|
46
|
-
* - Optional footer content
|
|
47
|
-
*
|
|
48
|
-
* All data from context!
|
|
49
|
-
*/
|
|
50
|
-
export function DashboardSidebar({ isAdmin = false }: DashboardSidebarProps) {
|
|
51
|
-
const { config } = useAppContext();
|
|
52
|
-
const { currentPath } = useNavigation();
|
|
53
|
-
const { state, isMobile } = useSidebar();
|
|
54
|
-
|
|
55
|
-
const { app, privateLayout, adminLayout } = config;
|
|
56
|
-
|
|
57
|
-
// Admin layout: use adminLayout.menuSections converted to menuGroups, fallback to privateLayout
|
|
58
|
-
const menuGroups = isAdmin && adminLayout
|
|
59
|
-
? adminLayout.menuSections.map((section, idx) => ({
|
|
60
|
-
label: section.title,
|
|
61
|
-
order: idx + 1,
|
|
62
|
-
items: section.items.map(item => ({
|
|
63
|
-
path: item.path,
|
|
64
|
-
label: item.label,
|
|
65
|
-
icon: item.icon || (() => null),
|
|
66
|
-
badge: item.badge,
|
|
67
|
-
})),
|
|
68
|
-
}))
|
|
69
|
-
: privateLayout.menuGroups;
|
|
70
|
-
|
|
71
|
-
const homeHref = privateLayout.homeHref;
|
|
72
|
-
|
|
73
|
-
const isActiveRoute = (path: string) => {
|
|
74
|
-
// Only exact match - no prefix matching
|
|
75
|
-
// This ensures /private/jobs ONLY matches /private/jobs
|
|
76
|
-
// and NOT /private, /private/jobs/123, etc.
|
|
77
|
-
return currentPath === path;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<Sidebar collapsible="icon">
|
|
82
|
-
<SidebarHeader>
|
|
83
|
-
<div
|
|
84
|
-
className="flex items-center gap-3"
|
|
85
|
-
style={state === "collapsed" ? {
|
|
86
|
-
paddingLeft: '7px',
|
|
87
|
-
paddingTop: '0.5rem',
|
|
88
|
-
paddingBottom: '0.5rem',
|
|
89
|
-
transition: 'padding 200ms ease-in-out'
|
|
90
|
-
} : {
|
|
91
|
-
padding: '0.5rem',
|
|
92
|
-
transition: 'padding 200ms ease-in-out'
|
|
93
|
-
}}
|
|
94
|
-
>
|
|
95
|
-
<Link href={homeHref}>
|
|
96
|
-
<div className="flex items-center gap-3">
|
|
97
|
-
{app.logoPath ? (
|
|
98
|
-
<img
|
|
99
|
-
src={app.logoPath}
|
|
100
|
-
alt={app.name}
|
|
101
|
-
className={isMobile ? "h-10 w-10 flex-shrink-0" : "h-8 w-8 flex-shrink-0"}
|
|
102
|
-
/>
|
|
103
|
-
) : (
|
|
104
|
-
<div className={isMobile ? "h-10 w-10 bg-primary rounded-sm flex items-center justify-center flex-shrink-0" : "h-8 w-8 bg-primary rounded-sm flex items-center justify-center flex-shrink-0"}>
|
|
105
|
-
<span className="text-primary-foreground font-bold text-sm">
|
|
106
|
-
{app.name.charAt(0).toUpperCase()}
|
|
107
|
-
</span>
|
|
108
|
-
</div>
|
|
109
|
-
)}
|
|
110
|
-
{state !== "collapsed" && (
|
|
111
|
-
<span className={isMobile ? "font-semibold text-foreground truncate text-base" : "font-semibold text-foreground truncate"} style={{ whiteSpace: 'nowrap' }}>
|
|
112
|
-
{app.name}
|
|
113
|
-
</span>
|
|
114
|
-
)}
|
|
115
|
-
</div>
|
|
116
|
-
</Link>
|
|
117
|
-
</div>
|
|
118
|
-
</SidebarHeader>
|
|
119
|
-
|
|
120
|
-
<SidebarContent>
|
|
121
|
-
{menuGroups.map((group) => (
|
|
122
|
-
<SidebarGroup key={group.label}>
|
|
123
|
-
<SidebarGroupLabel>{group.label}</SidebarGroupLabel>
|
|
124
|
-
<SidebarGroupContent>
|
|
125
|
-
<SidebarMenu>
|
|
126
|
-
{group.items.map((item) => {
|
|
127
|
-
const isActive = isActiveRoute(item.path);
|
|
128
|
-
const Icon = item.icon;
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<SidebarMenuItem key={item.path}>
|
|
132
|
-
<SidebarMenuButton
|
|
133
|
-
asChild
|
|
134
|
-
isActive={isActive}
|
|
135
|
-
tooltip={item.label}
|
|
136
|
-
size={isMobile ? "lg" : "default"}
|
|
137
|
-
>
|
|
138
|
-
<Link href={item.path}>
|
|
139
|
-
<Icon className={isMobile ? "h-5 w-5" : "h-4 w-4"} />
|
|
140
|
-
<span className={isMobile ? "text-base" : ""}>{item.label}</span>
|
|
141
|
-
{item.badge && (
|
|
142
|
-
<SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
|
|
143
|
-
)}
|
|
144
|
-
</Link>
|
|
145
|
-
</SidebarMenuButton>
|
|
146
|
-
|
|
147
|
-
{/* Submenu */}
|
|
148
|
-
{item.subItems && item.subItems.length > 0 && (
|
|
149
|
-
<SidebarMenuSub>
|
|
150
|
-
{item.subItems.map((subItem) => {
|
|
151
|
-
const isSubActive = isActiveRoute(subItem.path);
|
|
152
|
-
const SubIcon = subItem.icon;
|
|
153
|
-
|
|
154
|
-
return (
|
|
155
|
-
<SidebarMenuSubItem key={subItem.path}>
|
|
156
|
-
<SidebarMenuSubButton
|
|
157
|
-
asChild
|
|
158
|
-
isActive={isSubActive}
|
|
159
|
-
size={isMobile ? "md" : "md"}
|
|
160
|
-
>
|
|
161
|
-
<Link href={subItem.path}>
|
|
162
|
-
<SubIcon className={isMobile ? "h-5 w-5" : "h-4 w-4"} />
|
|
163
|
-
<span className={isMobile ? "text-base" : ""}>{subItem.label}</span>
|
|
164
|
-
</Link>
|
|
165
|
-
</SidebarMenuSubButton>
|
|
166
|
-
</SidebarMenuSubItem>
|
|
167
|
-
);
|
|
168
|
-
})}
|
|
169
|
-
</SidebarMenuSub>
|
|
170
|
-
)}
|
|
171
|
-
</SidebarMenuItem>
|
|
172
|
-
);
|
|
173
|
-
})}
|
|
174
|
-
</SidebarMenu>
|
|
175
|
-
</SidebarGroupContent>
|
|
176
|
-
</SidebarGroup>
|
|
177
|
-
))}
|
|
178
|
-
</SidebarContent>
|
|
179
|
-
</Sidebar>
|
|
180
|
-
);
|
|
181
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Private Layout Components
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { DashboardHeader } from './DashboardHeader';
|
|
6
|
-
export type { DashboardHeaderProps } from './DashboardHeader';
|
|
7
|
-
export { DashboardSidebar } from './DashboardSidebar';
|
|
8
|
-
export type { DashboardSidebarProps } from './DashboardSidebar';
|
|
9
|
-
export { DashboardContent } from './DashboardContent';
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public Layout
|
|
3
|
-
*
|
|
4
|
-
* Layout for public pages (landing, docs, etc.)
|
|
5
|
-
* All data accessed through context - no prop drilling
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
'use client';
|
|
9
|
-
|
|
10
|
-
import React, { ReactNode } from 'react';
|
|
11
|
-
import { Navigation } from './components/Navigation';
|
|
12
|
-
import { Footer } from './components/Footer';
|
|
13
|
-
|
|
14
|
-
export interface PublicLayoutProps {
|
|
15
|
-
children: ReactNode;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Public Layout Component
|
|
20
|
-
*
|
|
21
|
-
* Features:
|
|
22
|
-
* - Top navigation bar
|
|
23
|
-
* - User menu integration
|
|
24
|
-
* - Footer with links
|
|
25
|
-
* - Mobile responsive
|
|
26
|
-
*
|
|
27
|
-
* All data from useAppContext() and useAuth() - no props needed!
|
|
28
|
-
*/
|
|
29
|
-
export function PublicLayout({ children }: PublicLayoutProps) {
|
|
30
|
-
return (
|
|
31
|
-
<div className="min-h-screen flex flex-col">
|
|
32
|
-
{/* Navigation - gets data from context */}
|
|
33
|
-
<Navigation />
|
|
34
|
-
|
|
35
|
-
{/* Main Content */}
|
|
36
|
-
<main className="flex-1">
|
|
37
|
-
{children}
|
|
38
|
-
</main>
|
|
39
|
-
|
|
40
|
-
{/* Footer - gets data from context */}
|
|
41
|
-
<Footer />
|
|
42
|
-
</div>
|
|
43
|
-
);
|
|
44
|
-
}
|