@djangocfg/layouts 1.0.6 → 1.1.0

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.
Files changed (50) hide show
  1. package/package.json +5 -5
  2. package/src/layouts/AppLayout/AppLayout.tsx +126 -28
  3. package/src/layouts/AppLayout/components/ErrorBoundary.tsx +99 -0
  4. package/src/layouts/AppLayout/components/PageProgress.tsx +28 -11
  5. package/src/layouts/AppLayout/components/index.ts +1 -0
  6. package/src/layouts/AppLayout/layouts/AuthLayout/AuthContext.tsx +1 -1
  7. package/src/layouts/AppLayout/layouts/AuthLayout/AuthHelp.tsx +5 -5
  8. package/src/layouts/AppLayout/layouts/AuthLayout/AuthLayout.tsx +2 -2
  9. package/src/layouts/AppLayout/layouts/AuthLayout/IdentifierForm.tsx +2 -2
  10. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardHeader.tsx +1 -1
  11. package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +1 -1
  12. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenu.tsx +53 -36
  13. package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +64 -52
  14. package/src/layouts/AppLayout/types/config.ts +22 -0
  15. package/src/layouts/ErrorLayout/ErrorLayout.tsx +169 -0
  16. package/src/layouts/ErrorLayout/errorConfig.tsx +152 -0
  17. package/src/layouts/ErrorLayout/index.ts +8 -0
  18. package/src/layouts/UILayout/README.md +267 -0
  19. package/src/layouts/UILayout/REFACTORING.md +331 -0
  20. package/src/layouts/UILayout/UIGuideApp.tsx +18 -0
  21. package/src/layouts/UILayout/UIGuideLanding.tsx +198 -0
  22. package/src/layouts/UILayout/UIGuideView.tsx +61 -0
  23. package/src/layouts/UILayout/UILayout.tsx +122 -0
  24. package/src/layouts/UILayout/components/AutoComponentDemo.tsx +77 -0
  25. package/src/layouts/UILayout/components/CategoryRenderer.tsx +45 -0
  26. package/src/layouts/UILayout/components/Header.tsx +114 -0
  27. package/src/layouts/UILayout/components/MobileOverlay.tsx +33 -0
  28. package/src/layouts/UILayout/components/Sidebar.tsx +195 -0
  29. package/src/layouts/UILayout/components/TailwindGuideRenderer.tsx +138 -0
  30. package/src/layouts/UILayout/config/ai-export.config.ts +80 -0
  31. package/src/layouts/UILayout/config/categories.config.tsx +114 -0
  32. package/src/layouts/UILayout/config/components/blocks.config.tsx +233 -0
  33. package/src/layouts/UILayout/config/components/data.config.tsx +308 -0
  34. package/src/layouts/UILayout/config/components/feedback.config.tsx +246 -0
  35. package/src/layouts/UILayout/config/components/forms.config.tsx +171 -0
  36. package/src/layouts/UILayout/config/components/hooks.config.tsx +131 -0
  37. package/src/layouts/UILayout/config/components/index.ts +69 -0
  38. package/src/layouts/UILayout/config/components/layout.config.tsx +133 -0
  39. package/src/layouts/UILayout/config/components/navigation.config.tsx +244 -0
  40. package/src/layouts/UILayout/config/components/overlay.config.tsx +561 -0
  41. package/src/layouts/UILayout/config/components/specialized.config.tsx +125 -0
  42. package/src/layouts/UILayout/config/components/types.ts +14 -0
  43. package/src/layouts/UILayout/config/index.ts +42 -0
  44. package/src/layouts/UILayout/config/tailwind.config.ts +77 -0
  45. package/src/layouts/UILayout/constants.ts +23 -0
  46. package/src/layouts/UILayout/context/ShowcaseContext.tsx +53 -0
  47. package/src/layouts/UILayout/context/index.ts +1 -0
  48. package/src/layouts/UILayout/index.ts +64 -0
  49. package/src/layouts/UILayout/types.ts +13 -0
  50. package/src/layouts/index.ts +5 -1
@@ -0,0 +1,198 @@
1
+ /**
2
+ * UI Guide Landing Page
3
+ *
4
+ * Beautiful landing page for Django CFG UI Library
5
+ * Uses ready blocks from @djangocfg/ui/blocks
6
+ */
7
+
8
+ 'use client';
9
+
10
+ import React from 'react';
11
+ import {
12
+ Package,
13
+ Sparkles,
14
+ Zap,
15
+ Shield,
16
+ Palette,
17
+ Code2,
18
+ Blocks,
19
+ Github,
20
+ BookOpen,
21
+ } from 'lucide-react';
22
+ import {
23
+ SuperHero,
24
+ FeatureSection,
25
+ StatsSection,
26
+ CTASection,
27
+ } from '@djangocfg/ui/blocks';
28
+ import { useShowcase } from './context';
29
+
30
+ interface UIGuideLandingProps {
31
+ githubUrl?: string;
32
+ }
33
+
34
+ export function UIGuideLanding({
35
+ githubUrl = 'https://github.com'
36
+ }: UIGuideLandingProps) {
37
+ const { setCurrentCategory } = useShowcase();
38
+
39
+ const handleBrowseComponents = () => {
40
+ setCurrentCategory('forms');
41
+ };
42
+
43
+ const handleViewBlocks = () => {
44
+ setCurrentCategory('blocks');
45
+ };
46
+ return (
47
+ <div className="min-h-screen">
48
+ {/* Hero Section using SuperHero block */}
49
+ <SuperHero
50
+ badge={{
51
+ icon: <Sparkles className="w-4 h-4" />,
52
+ text: "56+ Components · 7 Blocks · 11 Hooks"
53
+ }}
54
+ title="Django CFG"
55
+ titleGradient="UI Library"
56
+ subtitle="Modern React component library built with Next.js 15, Radix UI, and Tailwind CSS 4"
57
+ features={[
58
+ { icon: <span>⚛️</span>, text: "React 19" },
59
+ { icon: <span>📘</span>, text: "TypeScript" },
60
+ { icon: <span>🎨</span>, text: "Tailwind CSS 4" },
61
+ { icon: <span>🌙</span>, text: "Dark Mode" },
62
+ ]}
63
+ primaryAction={{
64
+ label: "Explore Components",
65
+ onClick: handleBrowseComponents
66
+ }}
67
+ secondaryAction={{
68
+ label: "View Blocks",
69
+ onClick: handleViewBlocks,
70
+ icon: <BookOpen className="w-5 h-5" />
71
+ }}
72
+ stats={[
73
+ { number: "56+", label: "Components" },
74
+ { number: "7", label: "Blocks" },
75
+ { number: "11", label: "Hooks" },
76
+ { number: "100%", label: "Type Safe" },
77
+ ]}
78
+ />
79
+
80
+ {/* Features Section using FeatureSection block */}
81
+ <FeatureSection
82
+ title="Everything You Need"
83
+ subtitle="A comprehensive component library with all the building blocks for modern web applications"
84
+ columns={3}
85
+ background="card"
86
+ features={[
87
+ {
88
+ icon: <Package className="w-6 h-6" />,
89
+ title: "56+ Components",
90
+ description: "From basic buttons to complex data tables, we've got you covered with production-ready components",
91
+ },
92
+ {
93
+ icon: <Blocks className="w-6 h-6" />,
94
+ title: "Landing Page Blocks",
95
+ description: "Pre-built sections like Hero, Features, CTA, Testimonials to ship landing pages faster",
96
+ },
97
+ {
98
+ icon: <Zap className="w-6 h-6" />,
99
+ title: "Lightning Fast",
100
+ description: "Optimized for performance with React 19 and Next.js 15 for blazing fast user experiences",
101
+ },
102
+ {
103
+ icon: <Shield className="w-6 h-6" />,
104
+ title: "Fully Accessible",
105
+ description: "Built on Radix UI primitives ensuring WCAG compliance and keyboard navigation support",
106
+ },
107
+ {
108
+ icon: <Palette className="w-6 h-6" />,
109
+ title: "Themeable",
110
+ description: "Dark mode built-in with CSS variables. Customize colors, spacing, and typography easily",
111
+ },
112
+ {
113
+ icon: <Code2 className="w-6 h-6" />,
114
+ title: "TypeScript First",
115
+ description: "Fully typed with TypeScript for better DX, autocomplete, and fewer runtime errors",
116
+ },
117
+ ]}
118
+ />
119
+
120
+ {/* Stats Section using StatsSection block */}
121
+ <StatsSection
122
+ title="Built for Scale"
123
+ subtitle="Everything you need to build modern web applications"
124
+ columns={4}
125
+ stats={[
126
+ {
127
+ number: "56+",
128
+ label: "UI Components",
129
+ description: "Production-ready",
130
+ },
131
+ {
132
+ number: "7",
133
+ label: "Landing Blocks",
134
+ description: "Pre-built sections",
135
+ },
136
+ {
137
+ number: "11",
138
+ label: "React Hooks",
139
+ description: "Custom utilities",
140
+ },
141
+ {
142
+ number: "100%",
143
+ label: "Type Safe",
144
+ description: "Full TypeScript",
145
+ },
146
+ ]}
147
+ />
148
+
149
+ {/* CTA Section using CTASection block */}
150
+ <CTASection
151
+ title="Ready to Build Something Amazing?"
152
+ subtitle="Start exploring our component library and ship your next project faster with pre-built, accessible components"
153
+ primaryCTA={{
154
+ label: "Browse Components",
155
+ onClick: handleBrowseComponents
156
+ }}
157
+ secondaryCTA={{
158
+ label: "View Blocks",
159
+ onClick: handleViewBlocks
160
+ }}
161
+ background="gradient"
162
+ />
163
+
164
+ {/* Simple Footer */}
165
+ <footer className="border-t py-8 sm:py-10 md:py-12 bg-background">
166
+ <div className="container max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
167
+ <div className="flex flex-col md:flex-row items-center justify-between gap-4">
168
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
169
+ <Package className="w-4 h-4" />
170
+ <span>Built with Radix UI + Tailwind CSS</span>
171
+ </div>
172
+ <div className="flex items-center gap-6">
173
+ <button
174
+ onClick={handleBrowseComponents}
175
+ className="text-sm text-muted-foreground hover:text-foreground transition-colors"
176
+ >
177
+ Components
178
+ </button>
179
+ <button
180
+ onClick={handleViewBlocks}
181
+ className="text-sm text-muted-foreground hover:text-foreground transition-colors"
182
+ >
183
+ Blocks
184
+ </button>
185
+ <button
186
+ onClick={() => window.open(githubUrl, '_blank')}
187
+ className="text-sm text-muted-foreground hover:text-foreground transition-colors flex items-center gap-1"
188
+ >
189
+ <Github className="w-4 h-4" />
190
+ GitHub
191
+ </button>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ </footer>
196
+ </div>
197
+ );
198
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * UI Guide View
3
+ * Main view for showcasing all UI components from @djangocfg/ui package
4
+ * Uses config-driven approach - all data comes from centralized config
5
+ */
6
+
7
+ 'use client';
8
+
9
+ import React from 'react';
10
+ import { UILayout } from './UILayout';
11
+ import { CATEGORIES } from './config';
12
+ import { ShowcaseProvider, useShowcase } from './context';
13
+ import { UIGuideLanding } from './UIGuideLanding';
14
+ import { CategoryRenderer } from './components/CategoryRenderer';
15
+ import { TailwindGuideRenderer } from './components/TailwindGuideRenderer';
16
+
17
+ function UIGuideContent() {
18
+ const { currentCategory, setCurrentCategory } = useShowcase();
19
+
20
+ // For overview, show only landing page without layout
21
+ if (currentCategory === 'overview') {
22
+ return <UIGuideLanding />;
23
+ }
24
+
25
+ // Logo component
26
+ const logo = (
27
+ <div className="h-8 w-8 rounded-md bg-primary flex items-center justify-center text-primary-foreground font-bold text-sm">
28
+ DC
29
+ </div>
30
+ );
31
+
32
+ return (
33
+ <UILayout
34
+ title="UI Component Library"
35
+ description="Explore our comprehensive collection of 56+ React components built with Radix UI and Tailwind CSS"
36
+ categories={CATEGORIES}
37
+ currentCategory={currentCategory}
38
+ onCategoryChange={setCurrentCategory}
39
+ logo={logo}
40
+ projectName="Django CFG UI"
41
+ >
42
+ <div className="space-y-8">
43
+ {/* Tailwind 4 Guide */}
44
+ {currentCategory === 'tailwind4' && <TailwindGuideRenderer />}
45
+
46
+ {/* All other categories use CategoryRenderer */}
47
+ {currentCategory !== 'tailwind4' && currentCategory !== 'overview' && (
48
+ <CategoryRenderer categoryId={currentCategory} />
49
+ )}
50
+ </div>
51
+ </UILayout>
52
+ );
53
+ }
54
+
55
+ export default function UIGuideView() {
56
+ return (
57
+ <ShowcaseProvider defaultCategory="overview">
58
+ <UIGuideContent />
59
+ </ShowcaseProvider>
60
+ );
61
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * UILayout
3
+ * Modern, config-driven layout for UI component documentation
4
+ */
5
+
6
+ 'use client';
7
+
8
+ import React, { ReactNode } from 'react';
9
+ import { useCopy, Sticky } from '@djangocfg/ui';
10
+ import { Sidebar } from './components/Sidebar';
11
+ import { Header } from './components/Header';
12
+ import { MobileOverlay } from './components/MobileOverlay';
13
+ import { generateAIContext } from './config';
14
+ import { useShowcase } from './context';
15
+ import type { ComponentCategory } from './config';
16
+
17
+ export interface UILayoutProps {
18
+ children: ReactNode;
19
+ title?: string;
20
+ description?: string;
21
+ categories: ComponentCategory[];
22
+ currentCategory?: string;
23
+ onCategoryChange?: (categoryId: string) => void;
24
+ logo?: ReactNode;
25
+ projectName?: string;
26
+ }
27
+
28
+ /**
29
+ * UILayout - Main layout component for UI documentation
30
+ *
31
+ * Features:
32
+ * - Config-driven: All component data comes from centralized config
33
+ * - "Copy for AI": One-click export of all documentation
34
+ * - Responsive: Mobile-first design with sidebar
35
+ * - Type-safe: Full TypeScript support
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * <UILayout
40
+ * title="UI Components"
41
+ * categories={CATEGORIES}
42
+ * currentCategory={category}
43
+ * onCategoryChange={setCategory}
44
+ * >
45
+ * <CategoryRenderer categoryId={category} />
46
+ * </UILayout>
47
+ * ```
48
+ */
49
+ export function UILayout({
50
+ children,
51
+ title = "UI Component Library",
52
+ description,
53
+ categories,
54
+ currentCategory,
55
+ onCategoryChange,
56
+ logo,
57
+ projectName = "Django CFG UI",
58
+ }: UILayoutProps) {
59
+ const { isSidebarOpen, toggleSidebar, closeSidebar } = useShowcase();
60
+ const { copyToClipboard } = useCopy();
61
+
62
+ const handleCategoryChange = (categoryId: string) => {
63
+ onCategoryChange?.(categoryId);
64
+ closeSidebar();
65
+ };
66
+
67
+ const handleCopyForAI = () => {
68
+ const aiContext = generateAIContext();
69
+ copyToClipboard(aiContext);
70
+ };
71
+
72
+ return (
73
+ <div className="flex bg-background">
74
+ {/* Mobile Overlay - outside flex container for proper z-index stacking */}
75
+ <MobileOverlay
76
+ isOpen={isSidebarOpen}
77
+ onClose={closeSidebar}
78
+ />
79
+
80
+ {/* Sidebar with Sticky - parent must be scrollable for react-sticky-box */}
81
+ <div className="h-full sticky top-0">
82
+ <Sidebar
83
+ categories={categories}
84
+ currentCategory={currentCategory}
85
+ onCategoryChange={handleCategoryChange}
86
+ isOpen={isSidebarOpen}
87
+ projectName={projectName}
88
+ logo={logo}
89
+ />
90
+ </div>
91
+
92
+ {/* Main Content */}
93
+ <main className="flex-1 flex flex-col min-w-0">
94
+ {/* Header with Copy for AI button */}
95
+ <Header
96
+ title={title}
97
+ projectName={projectName}
98
+ logo={logo}
99
+ isSidebarOpen={isSidebarOpen}
100
+ onToggleSidebar={toggleSidebar}
101
+ onCopyForAI={handleCopyForAI}
102
+ />
103
+
104
+ {/* Content Area */}
105
+ <div className="flex-1">
106
+ <div className="container max-w-7xl mx-auto p-6">
107
+ {description && (
108
+ <p className="text-sm text-muted-foreground mb-6">
109
+ {description}
110
+ </p>
111
+ )}
112
+ {children}
113
+ </div>
114
+ </div>
115
+ </main>
116
+ </div>
117
+ );
118
+ }
119
+
120
+ // Legacy export for backward compatibility
121
+ export { UILayout as ComponentShowcaseLayout };
122
+ export type { UILayoutProps as ComponentShowcaseLayoutProps };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * AutoComponentDemo
3
+ * Automatically renders component demos from configuration
4
+ */
5
+
6
+ 'use client';
7
+
8
+ import React from 'react';
9
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle, Tabs, TabsContent, TabsList, TabsTrigger } from '@djangocfg/ui';
10
+ import { PrettyCode } from '@djangocfg/ui/tools';
11
+ import type { ComponentConfig } from '../config';
12
+
13
+ interface AutoComponentDemoProps {
14
+ component: ComponentConfig;
15
+ }
16
+
17
+ /**
18
+ * AutoComponentDemo - Renders a component demo from config
19
+ * This is the single component used to display all UI components
20
+ */
21
+ export function AutoComponentDemo({ component }: AutoComponentDemoProps) {
22
+ return (
23
+ <Card className="mb-6">
24
+ <CardHeader>
25
+ <CardTitle className="text-lg">{component.name}</CardTitle>
26
+ <CardDescription>{component.description}</CardDescription>
27
+ </CardHeader>
28
+ <CardContent>
29
+ <Tabs defaultValue="preview" className="w-full">
30
+ <TabsList className="mb-4">
31
+ <TabsTrigger value="preview">Preview</TabsTrigger>
32
+ <TabsTrigger value="code">Code</TabsTrigger>
33
+ </TabsList>
34
+
35
+ <TabsContent value="preview" className="space-y-4">
36
+ <div className="p-6 border rounded-md bg-card">
37
+ {component.preview}
38
+ </div>
39
+ </TabsContent>
40
+
41
+ <TabsContent value="code">
42
+ <PrettyCode
43
+ data={`${component.importPath}\n\n${component.example}`}
44
+ language="tsx"
45
+ className="text-sm"
46
+ />
47
+ </TabsContent>
48
+ </Tabs>
49
+ </CardContent>
50
+ </Card>
51
+ );
52
+ }
53
+
54
+ /**
55
+ * CategorySection - Groups related component demos
56
+ */
57
+ interface CategorySectionProps {
58
+ title: string;
59
+ description?: string;
60
+ children: React.ReactNode;
61
+ }
62
+
63
+ export function CategorySection({ title, description, children }: CategorySectionProps) {
64
+ return (
65
+ <div className="mb-12">
66
+ <div className="mb-6">
67
+ <h2 className="text-2xl font-bold tracking-tight">{title}</h2>
68
+ {description && (
69
+ <p className="text-muted-foreground mt-2">{description}</p>
70
+ )}
71
+ </div>
72
+ <div className="space-y-6">
73
+ {children}
74
+ </div>
75
+ </div>
76
+ );
77
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * CategoryRenderer
3
+ * Universal renderer for any category using config data
4
+ */
5
+
6
+ 'use client';
7
+
8
+ import React from 'react';
9
+ import { getComponentsByCategory, getCategoryById } from '../config';
10
+ import { AutoComponentDemo, CategorySection } from './AutoComponentDemo';
11
+
12
+ interface CategoryRendererProps {
13
+ categoryId: string;
14
+ }
15
+
16
+ /**
17
+ * CategoryRenderer - Dynamically renders all components in a category
18
+ * No need for separate demo files - everything comes from config
19
+ */
20
+ export function CategoryRenderer({ categoryId }: CategoryRendererProps) {
21
+ const category = getCategoryById(categoryId);
22
+ const components = getComponentsByCategory(categoryId);
23
+
24
+ if (!category || components.length === 0) {
25
+ return (
26
+ <div className="p-8 text-center text-muted-foreground">
27
+ <p>No components found for this category</p>
28
+ </div>
29
+ );
30
+ }
31
+
32
+ return (
33
+ <CategorySection
34
+ title={category.label}
35
+ description={category.description}
36
+ >
37
+ {components.map((component) => (
38
+ <AutoComponentDemo
39
+ key={component.name}
40
+ component={component}
41
+ />
42
+ ))}
43
+ </CategorySection>
44
+ );
45
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Header Component
3
+ * Top header for mobile and page title with Copy for AI button
4
+ */
5
+
6
+ 'use client';
7
+
8
+ import React, { useState } from 'react';
9
+ import { Button, useIsMobile, useCopy } from '@djangocfg/ui';
10
+ import { Menu, X, Sparkles, Check } from 'lucide-react';
11
+
12
+ interface HeaderProps {
13
+ title?: string;
14
+ projectName?: string;
15
+ logo?: React.ReactNode;
16
+ isSidebarOpen?: boolean;
17
+ onToggleSidebar?: () => void;
18
+ onCopyForAI?: () => void;
19
+ }
20
+
21
+ export function Header({
22
+ title = 'UI Component Library',
23
+ projectName = 'Django CFG',
24
+ logo,
25
+ isSidebarOpen = false,
26
+ onToggleSidebar,
27
+ onCopyForAI,
28
+ }: HeaderProps) {
29
+ const isMobile = useIsMobile();
30
+ const { copyToClipboard } = useCopy();
31
+ const [copied, setCopied] = useState(false);
32
+
33
+ const handleCopyForAI = async () => {
34
+ if (onCopyForAI) {
35
+ onCopyForAI();
36
+ }
37
+ setCopied(true);
38
+ setTimeout(() => setCopied(false), 2000);
39
+ };
40
+
41
+ return (
42
+ <>
43
+ {/* Mobile Header - only on mobile */}
44
+ {isMobile && (
45
+ <header className="w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
46
+ <div className="flex h-14 items-center px-4 gap-4">
47
+ <Button
48
+ variant="ghost"
49
+ size="icon"
50
+ className="h-9 w-9"
51
+ onClick={onToggleSidebar}
52
+ >
53
+ {isSidebarOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
54
+ </Button>
55
+
56
+ <div className="flex items-center gap-2 flex-1">
57
+ {logo}
58
+ <span className="font-semibold text-sm">{projectName}</span>
59
+ </div>
60
+
61
+ <Button
62
+ variant="outline"
63
+ size="sm"
64
+ onClick={handleCopyForAI}
65
+ className="gap-2"
66
+ >
67
+ {copied ? (
68
+ <>
69
+ <Check className="h-4 w-4" />
70
+ <span className="hidden xs:inline">Copied!</span>
71
+ </>
72
+ ) : (
73
+ <>
74
+ <Sparkles className="h-4 w-4" />
75
+ <span className="hidden xs:inline">Copy for AI</span>
76
+ </>
77
+ )}
78
+ </Button>
79
+ </div>
80
+ </header>
81
+ )}
82
+
83
+ {/* Desktop Page Header - only on desktop */}
84
+ {!isMobile && (
85
+ <div className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
86
+ <div className="flex h-14 items-center gap-4 px-6">
87
+ <div className="flex-1">
88
+ <h1 className="text-lg font-semibold">{title}</h1>
89
+ </div>
90
+
91
+ <Button
92
+ variant="outline"
93
+ size="sm"
94
+ onClick={handleCopyForAI}
95
+ className="gap-2"
96
+ >
97
+ {copied ? (
98
+ <>
99
+ <Check className="h-4 w-4" />
100
+ Copied!
101
+ </>
102
+ ) : (
103
+ <>
104
+ <Sparkles className="h-4 w-4" />
105
+ Copy for AI
106
+ </>
107
+ )}
108
+ </Button>
109
+ </div>
110
+ </div>
111
+ )}
112
+ </>
113
+ );
114
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Mobile Overlay Component
3
+ * Backdrop overlay for mobile sidebar
4
+ */
5
+
6
+ 'use client';
7
+
8
+ import React from 'react';
9
+ import { cn } from '@djangocfg/ui/lib';
10
+ import { useIsMobile } from '@djangocfg/ui';
11
+
12
+ interface MobileOverlayProps {
13
+ isOpen: boolean;
14
+ onClose: () => void;
15
+ }
16
+
17
+ export function MobileOverlay({ isOpen, onClose }: MobileOverlayProps) {
18
+ const isMobile = useIsMobile();
19
+
20
+ // Only show on mobile when sidebar is open
21
+ if (!isMobile || !isOpen) return null;
22
+
23
+ return (
24
+ <div
25
+ className={cn(
26
+ "fixed inset-0 z-[150] bg-background/80 backdrop-blur-sm",
27
+ "animate-in fade-in duration-300"
28
+ )}
29
+ onClick={onClose}
30
+ aria-hidden="true"
31
+ />
32
+ );
33
+ }