@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.
- package/package.json +5 -5
- package/src/layouts/AppLayout/AppLayout.tsx +126 -28
- package/src/layouts/AppLayout/components/ErrorBoundary.tsx +99 -0
- package/src/layouts/AppLayout/components/PageProgress.tsx +28 -11
- package/src/layouts/AppLayout/components/index.ts +1 -0
- package/src/layouts/AppLayout/layouts/AuthLayout/AuthContext.tsx +1 -1
- package/src/layouts/AppLayout/layouts/AuthLayout/AuthHelp.tsx +5 -5
- package/src/layouts/AppLayout/layouts/AuthLayout/AuthLayout.tsx +2 -2
- package/src/layouts/AppLayout/layouts/AuthLayout/IdentifierForm.tsx +2 -2
- package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardHeader.tsx +1 -1
- package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +1 -1
- package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileMenu.tsx +53 -36
- package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +64 -52
- package/src/layouts/AppLayout/types/config.ts +22 -0
- package/src/layouts/ErrorLayout/ErrorLayout.tsx +169 -0
- package/src/layouts/ErrorLayout/errorConfig.tsx +152 -0
- package/src/layouts/ErrorLayout/index.ts +8 -0
- package/src/layouts/UILayout/README.md +267 -0
- package/src/layouts/UILayout/REFACTORING.md +331 -0
- package/src/layouts/UILayout/UIGuideApp.tsx +18 -0
- package/src/layouts/UILayout/UIGuideLanding.tsx +198 -0
- package/src/layouts/UILayout/UIGuideView.tsx +61 -0
- package/src/layouts/UILayout/UILayout.tsx +122 -0
- package/src/layouts/UILayout/components/AutoComponentDemo.tsx +77 -0
- package/src/layouts/UILayout/components/CategoryRenderer.tsx +45 -0
- package/src/layouts/UILayout/components/Header.tsx +114 -0
- package/src/layouts/UILayout/components/MobileOverlay.tsx +33 -0
- package/src/layouts/UILayout/components/Sidebar.tsx +195 -0
- package/src/layouts/UILayout/components/TailwindGuideRenderer.tsx +138 -0
- package/src/layouts/UILayout/config/ai-export.config.ts +80 -0
- package/src/layouts/UILayout/config/categories.config.tsx +114 -0
- package/src/layouts/UILayout/config/components/blocks.config.tsx +233 -0
- package/src/layouts/UILayout/config/components/data.config.tsx +308 -0
- package/src/layouts/UILayout/config/components/feedback.config.tsx +246 -0
- package/src/layouts/UILayout/config/components/forms.config.tsx +171 -0
- package/src/layouts/UILayout/config/components/hooks.config.tsx +131 -0
- package/src/layouts/UILayout/config/components/index.ts +69 -0
- package/src/layouts/UILayout/config/components/layout.config.tsx +133 -0
- package/src/layouts/UILayout/config/components/navigation.config.tsx +244 -0
- package/src/layouts/UILayout/config/components/overlay.config.tsx +561 -0
- package/src/layouts/UILayout/config/components/specialized.config.tsx +125 -0
- package/src/layouts/UILayout/config/components/types.ts +14 -0
- package/src/layouts/UILayout/config/index.ts +42 -0
- package/src/layouts/UILayout/config/tailwind.config.ts +77 -0
- package/src/layouts/UILayout/constants.ts +23 -0
- package/src/layouts/UILayout/context/ShowcaseContext.tsx +53 -0
- package/src/layouts/UILayout/context/index.ts +1 -0
- package/src/layouts/UILayout/index.ts +64 -0
- package/src/layouts/UILayout/types.ts +13 -0
- 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
|
+
}
|