@djangocfg/layouts 1.4.26 → 1.4.28

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 (79) hide show
  1. package/package.json +5 -5
  2. package/src/auth/middlewares/index.ts +1 -1
  3. package/src/auth/middlewares/proxy.ts +10 -2
  4. package/src/layouts/index.ts +0 -3
  5. package/src/snippets/ContactForm/ContactForm.tsx +59 -12
  6. package/src/snippets/ContactForm/ContactPage.tsx +21 -20
  7. package/src/snippets/ContactForm/dynamic.tsx +55 -0
  8. package/src/snippets/ContactForm/index.ts +6 -3
  9. package/src/layouts/UILayout/README.md +0 -267
  10. package/src/layouts/UILayout/SUMMARY.md +0 -298
  11. package/src/layouts/UILayout/TOOLS_INTEGRATION.md +0 -216
  12. package/src/layouts/UILayout/components/AutoComponentDemo.tsx +0 -77
  13. package/src/layouts/UILayout/components/CategoryRenderer.tsx +0 -45
  14. package/src/layouts/UILayout/components/TailwindGuideRenderer.tsx +0 -138
  15. package/src/layouts/UILayout/components/index.ts +0 -15
  16. package/src/layouts/UILayout/components/layout/Header/CopyAIButton.tsx +0 -58
  17. package/src/layouts/UILayout/components/layout/Header/Header.tsx +0 -60
  18. package/src/layouts/UILayout/components/layout/Header/HeaderDesktop.tsx +0 -51
  19. package/src/layouts/UILayout/components/layout/Header/HeaderMobile.tsx +0 -71
  20. package/src/layouts/UILayout/components/layout/Header/TestValidationButton.tsx +0 -268
  21. package/src/layouts/UILayout/components/layout/Header/index.ts +0 -11
  22. package/src/layouts/UILayout/components/layout/MobileOverlay/MobileOverlay.tsx +0 -47
  23. package/src/layouts/UILayout/components/layout/MobileOverlay/index.ts +0 -6
  24. package/src/layouts/UILayout/components/layout/Sidebar/Sidebar.tsx +0 -95
  25. package/src/layouts/UILayout/components/layout/Sidebar/SidebarCategory.tsx +0 -54
  26. package/src/layouts/UILayout/components/layout/Sidebar/SidebarContent.tsx +0 -93
  27. package/src/layouts/UILayout/components/layout/Sidebar/SidebarFooter.tsx +0 -49
  28. package/src/layouts/UILayout/components/layout/Sidebar/index.ts +0 -9
  29. package/src/layouts/UILayout/components/layout/index.ts +0 -8
  30. package/src/layouts/UILayout/components/shared/Badge/CountBadge.tsx +0 -38
  31. package/src/layouts/UILayout/components/shared/Badge/index.ts +0 -5
  32. package/src/layouts/UILayout/components/shared/CodeBlock/CodeBlock.tsx +0 -48
  33. package/src/layouts/UILayout/components/shared/CodeBlock/CopyButton.tsx +0 -49
  34. package/src/layouts/UILayout/components/shared/CodeBlock/index.ts +0 -6
  35. package/src/layouts/UILayout/components/shared/Section/Section.tsx +0 -63
  36. package/src/layouts/UILayout/components/shared/Section/index.ts +0 -5
  37. package/src/layouts/UILayout/components/shared/index.ts +0 -8
  38. package/src/layouts/UILayout/config/ai-export.config.ts +0 -89
  39. package/src/layouts/UILayout/config/categories.config.tsx +0 -122
  40. package/src/layouts/UILayout/config/components/blocks.config.tsx +0 -239
  41. package/src/layouts/UILayout/config/components/data.config.tsx +0 -433
  42. package/src/layouts/UILayout/config/components/feedback.config.tsx +0 -290
  43. package/src/layouts/UILayout/config/components/forms.config.tsx +0 -996
  44. package/src/layouts/UILayout/config/components/hooks.config.tsx +0 -168
  45. package/src/layouts/UILayout/config/components/index.ts +0 -72
  46. package/src/layouts/UILayout/config/components/layout.config.tsx +0 -246
  47. package/src/layouts/UILayout/config/components/navigation.config.tsx +0 -352
  48. package/src/layouts/UILayout/config/components/overlay.config.tsx +0 -569
  49. package/src/layouts/UILayout/config/components/specialized.config.tsx +0 -400
  50. package/src/layouts/UILayout/config/components/tools.config.tsx +0 -234
  51. package/src/layouts/UILayout/config/components/types.ts +0 -14
  52. package/src/layouts/UILayout/config/index.ts +0 -42
  53. package/src/layouts/UILayout/config/tailwind.config.ts +0 -131
  54. package/src/layouts/UILayout/constants.ts +0 -23
  55. package/src/layouts/UILayout/context/ShowcaseContext.tsx +0 -81
  56. package/src/layouts/UILayout/context/index.ts +0 -1
  57. package/src/layouts/UILayout/core/UIGuideApp.client.tsx +0 -18
  58. package/src/layouts/UILayout/core/UIGuideApp.tsx +0 -33
  59. package/src/layouts/UILayout/core/UIGuideLanding.tsx +0 -172
  60. package/src/layouts/UILayout/core/UIGuideView.tsx +0 -61
  61. package/src/layouts/UILayout/core/UILayout.tsx +0 -125
  62. package/src/layouts/UILayout/core/UILayoutSidebar.tsx +0 -11
  63. package/src/layouts/UILayout/core/index.ts +0 -10
  64. package/src/layouts/UILayout/hooks/index.ts +0 -9
  65. package/src/layouts/UILayout/hooks/useAIExport.ts +0 -78
  66. package/src/layouts/UILayout/hooks/useCategoryNavigation.ts +0 -92
  67. package/src/layouts/UILayout/hooks/useComponentSearch.ts +0 -81
  68. package/src/layouts/UILayout/hooks/useSidebarState.ts +0 -36
  69. package/src/layouts/UILayout/index.ts +0 -160
  70. package/src/layouts/UILayout/types/component.ts +0 -45
  71. package/src/layouts/UILayout/types/index.ts +0 -23
  72. package/src/layouts/UILayout/types/layout.ts +0 -57
  73. package/src/layouts/UILayout/types/navigation.ts +0 -33
  74. package/src/layouts/UILayout/utils/ai-export/formatters.ts +0 -71
  75. package/src/layouts/UILayout/utils/ai-export/index.ts +0 -5
  76. package/src/layouts/UILayout/utils/component-helpers/filter.ts +0 -109
  77. package/src/layouts/UILayout/utils/component-helpers/index.ts +0 -6
  78. package/src/layouts/UILayout/utils/component-helpers/search.ts +0 -95
  79. package/src/layouts/UILayout/utils/index.ts +0 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/layouts",
3
- "version": "1.4.26",
3
+ "version": "1.4.28",
4
4
  "description": "Pre-built dashboard layouts, authentication pages, and admin templates for Next.js applications with Tailwind CSS",
5
5
  "keywords": [
6
6
  "layouts",
@@ -85,9 +85,9 @@
85
85
  "check": "tsc --noEmit"
86
86
  },
87
87
  "peerDependencies": {
88
- "@djangocfg/api": "^1.4.26",
89
- "@djangocfg/og-image": "^1.4.26",
90
- "@djangocfg/ui": "^1.4.26",
88
+ "@djangocfg/api": "^1.4.28",
89
+ "@djangocfg/og-image": "^1.4.28",
90
+ "@djangocfg/ui": "^1.4.28",
91
91
  "@hookform/resolvers": "^5.2.0",
92
92
  "consola": "^3.4.2",
93
93
  "lucide-react": "^0.468.0",
@@ -109,7 +109,7 @@
109
109
  "vidstack": "0.6.15"
110
110
  },
111
111
  "devDependencies": {
112
- "@djangocfg/typescript-config": "^1.4.26",
112
+ "@djangocfg/typescript-config": "^1.4.28",
113
113
  "@types/node": "^24.7.2",
114
114
  "@types/react": "19.2.2",
115
115
  "@types/react-dom": "19.2.1",
@@ -1 +1 @@
1
- export { middleware, config } from './proxy';
1
+ export { proxyMiddleware, proxyMiddlewareConfig } from './proxy';
@@ -1,6 +1,10 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
 
3
- export function middleware(request: NextRequest) {
3
+ /**
4
+ * Proxy middleware for media and API endpoints
5
+ * Use this in your middleware.ts file
6
+ */
7
+ export function proxyMiddleware(request: NextRequest) {
4
8
  const { pathname, search } = request.nextUrl;
5
9
  const apiUrl = process.env.NEXT_PUBLIC_API_URL;
6
10
 
@@ -19,6 +23,10 @@ export function middleware(request: NextRequest) {
19
23
  return NextResponse.next();
20
24
  }
21
25
 
22
- export const config = {
26
+ /**
27
+ * Recommended matcher config for proxy middleware
28
+ * Add this to your middleware.ts config
29
+ */
30
+ export const proxyMiddlewareConfig = {
23
31
  matcher: ['/media/:path*', '/api/:path*'],
24
32
  };
@@ -9,8 +9,5 @@ export * from './PaymentsLayout';
9
9
  export * from './AppLayout';
10
10
  export * from './ErrorLayout';
11
11
 
12
- // UILayout - Config-driven UI documentation layout
13
- export * from './UILayout';
14
-
15
12
  // Note: CfgLayout is now part of AppLayout exports
16
13
  // Import it via: import { CfgLayout, useCfgApp } from '@djangocfg/layouts';
@@ -58,17 +58,17 @@ export interface ContactFormProps {
58
58
  // ============================================================================
59
59
 
60
60
  /**
61
- * ContactForm - Contact form using Django-CFG Lead API
61
+ * ContactFormBase - Contact form using Django-CFG Lead API
62
+ *
63
+ * NOTE: Use ContactForm from index.ts which is dynamically imported (ssr: false)
62
64
  *
63
65
  * @example
64
66
  * ```tsx
65
- * <ContactForm
66
- * apiUrl="https://api.example.com"
67
- * onSuccess={(result) => console.log('Lead ID:', result.lead_id)}
68
- * />
67
+ * import { ContactForm } from '@djangocfg/layouts';
68
+ * <ContactForm apiUrl="https://api.example.com" />
69
69
  * ```
70
70
  */
71
- export function ContactForm({ apiUrl, ...props }: ContactFormProps) {
71
+ export function ContactFormBase({ apiUrl, ...props }: ContactFormProps) {
72
72
  return (
73
73
  <ContactFormProvider apiUrl={apiUrl}>
74
74
  <ContactFormInner {...props} />
@@ -112,20 +112,42 @@ function ContactFormInner({
112
112
  const t = { ...DEFAULT_FORM_TEXTS, ...texts };
113
113
  const [draft, setDraft, clearDraft] = useLocalStorage<FormDraft>(STORAGE_KEY, emptyDraft);
114
114
  const [isSuccess, setIsSuccess] = useState(false);
115
+ const [isHydrated, setIsHydrated] = useState(false);
115
116
 
116
117
  const form = useForm<FormData>({
117
118
  resolver: zodResolver(Schemas.LeadSubmissionRequestSchema),
119
+ // Start with empty values to match SSR
118
120
  defaultValues: {
119
121
  ...emptyDraft,
120
- ...draft,
121
- site_url: typeof window !== 'undefined' ? window.location.href : '',
122
+ site_url: '',
122
123
  },
123
124
  });
124
125
 
126
+ // Hydrate form with localStorage draft and site_url after mount
127
+ useEffect(() => {
128
+ if (isHydrated) return;
129
+ setIsHydrated(true);
130
+
131
+ // Apply draft from localStorage and set site_url
132
+ const currentValues = form.getValues();
133
+ const hasDraftData = draft.name || draft.email || draft.company || draft.subject || draft.message;
134
+
135
+ if (hasDraftData || !currentValues.site_url) {
136
+ form.reset({
137
+ ...emptyDraft,
138
+ ...draft,
139
+ site_url: window.location.href,
140
+ });
141
+ }
142
+ }, [draft, form, isHydrated]);
143
+
125
144
  // Watch form values and save to localStorage
126
145
  const watchedValues = useWatch({ control: form.control });
127
146
 
128
147
  useEffect(() => {
148
+ // Only save to localStorage after hydration to avoid unnecessary writes
149
+ if (!isHydrated) return;
150
+
129
151
  const { name, email, company, subject, message } = watchedValues;
130
152
  if (name || email || company || subject || message) {
131
153
  setDraft({
@@ -136,14 +158,30 @@ function ContactFormInner({
136
158
  message: message || '',
137
159
  });
138
160
  }
139
- }, [watchedValues, setDraft]);
161
+ }, [watchedValues, setDraft, isHydrated]);
140
162
 
141
163
  const handleSubmit = async (data: FormData) => {
142
164
  try {
143
165
  const result = await submit(data);
144
166
  if (resetOnSuccess) {
145
- form.reset();
146
- clearDraft();
167
+ // Keep contact info (name, email, company), clear only message content
168
+ const currentValues = form.getValues();
169
+ form.reset({
170
+ name: currentValues.name,
171
+ email: currentValues.email,
172
+ company: currentValues.company,
173
+ subject: '',
174
+ message: '',
175
+ site_url: currentValues.site_url,
176
+ });
177
+ // Update draft to keep contact info
178
+ setDraft({
179
+ name: currentValues.name || '',
180
+ email: currentValues.email || '',
181
+ company: currentValues.company || '',
182
+ subject: '',
183
+ message: '',
184
+ });
147
185
  }
148
186
  setIsSuccess(true);
149
187
  onSuccess?.(result);
@@ -156,7 +194,16 @@ function ContactFormInner({
156
194
 
157
195
  const handleReset = () => {
158
196
  setIsSuccess(false);
159
- form.reset();
197
+ // Keep contact info when returning to form
198
+ const currentDraft = draft;
199
+ form.reset({
200
+ name: currentDraft.name,
201
+ email: currentDraft.email,
202
+ company: currentDraft.company,
203
+ subject: '',
204
+ message: '',
205
+ site_url: typeof window !== 'undefined' ? window.location.href : '',
206
+ });
160
207
  };
161
208
 
162
209
  // Success state
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import React from 'react';
4
- import { Mail, MapPin, Calendar } from 'lucide-react';
5
- import { ContactForm } from './ContactForm';
4
+ import { Mail, MapPin, Calendar, MessageCircle } from 'lucide-react';
5
+ import { ContactFormBase as ContactForm } from './ContactForm';
6
6
  import { ContactInfo } from './ContactInfo';
7
7
  import type { ContactDetail, LeadSubmissionResult } from './types';
8
8
 
@@ -15,6 +15,7 @@ const isDev = process.env.NODE_ENV === 'development';
15
15
  const DEFAULT_CONFIG = {
16
16
  apiUrl: isDev ? 'http://localhost:8000' : 'https://api.reforms.ai',
17
17
  email: 'markolofsen@gmail.com',
18
+ telegram: '+62 813 39646301',
18
19
  calendly: 'https://calendly.com/markolofsen/meeting',
19
20
  };
20
21
 
@@ -27,6 +28,8 @@ export interface ContactPageProps {
27
28
  apiUrl?: string;
28
29
  /** Override email */
29
30
  email?: string;
31
+ /** Override telegram */
32
+ telegram?: string;
30
33
  /** Override calendly link */
31
34
  calendlyUrl?: string;
32
35
  /** Page title */
@@ -48,31 +51,20 @@ export interface ContactPageProps {
48
51
  // ============================================================================
49
52
 
50
53
  /**
51
- * ContactPage - Pre-configured contact page component
54
+ * ContactPageBase - Pre-configured contact page component
52
55
  *
53
- * Ready to use in any project with sensible defaults.
56
+ * NOTE: Use ContactPage from index.ts which is dynamically imported (ssr: false)
54
57
  *
55
58
  * @example
56
59
  * ```tsx
57
- * // Minimal usage - just drop it in
60
+ * import { ContactPage } from '@djangocfg/layouts';
58
61
  * <ContactPage />
59
- *
60
- * // With custom title
61
- * <ContactPage
62
- * title={<>Contact <span className="text-primary">Us</span></>}
63
- * subtitle="We'd love to hear from you"
64
- * />
65
- *
66
- * // Override defaults
67
- * <ContactPage
68
- * apiUrl="https://api.myproject.com"
69
- * email="hello@myproject.com"
70
- * />
71
62
  * ```
72
63
  */
73
- export function ContactPage({
64
+ export function ContactPageBase({
74
65
  apiUrl = DEFAULT_CONFIG.apiUrl,
75
66
  email = DEFAULT_CONFIG.email,
67
+ telegram = DEFAULT_CONFIG.telegram,
76
68
  calendlyUrl = DEFAULT_CONFIG.calendly,
77
69
  title = 'Get in Touch',
78
70
  subtitle = "Have a question or want to work together? We'd love to hear from you.",
@@ -81,6 +73,9 @@ export function ContactPage({
81
73
  className,
82
74
  onSuccess,
83
75
  }: ContactPageProps) {
76
+ // Format phone for tel: link (remove spaces)
77
+ const telegramPhone = telegram.replace(/\s/g, '');
78
+
84
79
  const contactDetails: ContactDetail[] = [
85
80
  {
86
81
  icon: <Mail className="h-5 w-5" />,
@@ -88,6 +83,12 @@ export function ContactPage({
88
83
  value: email,
89
84
  href: `mailto:${email}`,
90
85
  },
86
+ {
87
+ icon: <MessageCircle className="h-5 w-5" />,
88
+ label: 'Telegram',
89
+ value: telegram,
90
+ href: `https://t.me/${telegramPhone}`,
91
+ },
91
92
  {
92
93
  icon: <MapPin className="h-5 w-5" />,
93
94
  label: 'Location',
@@ -108,8 +109,8 @@ export function ContactPage({
108
109
  </div>
109
110
 
110
111
  {/* Content Grid */}
111
- <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
112
- <div className="lg:col-span-2">
112
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-8 w-full">
113
+ <div>
113
114
  <ContactForm apiUrl={apiUrl} onSuccess={onSuccess} />
114
115
  </div>
115
116
  <div>
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Dynamic ContactForm components (ssr: false)
3
+ *
4
+ * Avoids hydration mismatch when using localStorage for form drafts.
5
+ * Components are loaded client-side only.
6
+ */
7
+
8
+ 'use client';
9
+
10
+ import dynamic from 'next/dynamic';
11
+ import { Skeleton } from '@djangocfg/ui';
12
+ import type { ContactFormProps } from './ContactForm';
13
+ import type { ContactPageProps } from './ContactPage';
14
+
15
+ function ContactFormSkeleton() {
16
+ return (
17
+ <div className="space-y-4">
18
+ <Skeleton className="w-full h-10" />
19
+ <Skeleton className="w-full h-10" />
20
+ <Skeleton className="w-full h-10" />
21
+ <Skeleton className="w-full h-24" />
22
+ <Skeleton className="w-full h-10" />
23
+ </div>
24
+ );
25
+ }
26
+
27
+ function ContactPageSkeleton() {
28
+ return (
29
+ <div>
30
+ <div className="text-center mb-8 md:mb-12">
31
+ <Skeleton className="w-64 h-12 mx-auto mb-4" />
32
+ <Skeleton className="w-96 h-6 mx-auto" />
33
+ </div>
34
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
35
+ <div className="lg:col-span-2">
36
+ <ContactFormSkeleton />
37
+ </div>
38
+ <div className="space-y-4">
39
+ <Skeleton className="w-full h-32" />
40
+ <Skeleton className="w-full h-24" />
41
+ </div>
42
+ </div>
43
+ </div>
44
+ );
45
+ }
46
+
47
+ export const ContactForm = dynamic<ContactFormProps>(
48
+ () => import('./ContactForm').then((mod) => mod.ContactFormBase),
49
+ { ssr: false, loading: () => <ContactFormSkeleton /> }
50
+ );
51
+
52
+ export const ContactPage = dynamic<ContactPageProps>(
53
+ () => import('./ContactPage').then((mod) => mod.ContactPageBase),
54
+ { ssr: false, loading: () => <ContactPageSkeleton /> }
55
+ );
@@ -2,10 +2,13 @@
2
2
  // ContactForm - Contact form using Django-CFG Lead API
3
3
  // ============================================================================
4
4
 
5
- // Components
6
- export { ContactForm, type ContactFormProps } from './ContactForm';
5
+ // Components (dynamic import, ssr: false - no hydration issues)
6
+ export { ContactForm, ContactPage } from './dynamic';
7
7
  export { ContactInfo } from './ContactInfo';
8
- export { ContactPage, type ContactPageProps } from './ContactPage';
8
+
9
+ // Types
10
+ export type { ContactFormProps } from './ContactForm';
11
+ export type { ContactPageProps } from './ContactPage';
9
12
 
10
13
  // Provider & Hooks
11
14
  export {
@@ -1,267 +0,0 @@
1
- # UILayout - Config-Driven UI Documentation System
2
-
3
- Modern, type-safe layout system for showcasing UI component libraries with built-in "Copy for AI" functionality.
4
-
5
- ## 🎯 Key Features
6
-
7
- - **Config-Driven**: Single source of truth for all component documentation
8
- - **Type-Safe**: Full TypeScript support with strict typing
9
- - **Auto-Rendering**: Components automatically rendered from config
10
- - **AI-Ready**: One-click export of entire documentation for AI consumption
11
- - **Responsive**: Mobile-first design with adaptive sidebar
12
- - **Dark Mode**: Built-in theme support
13
- - **Organized**: Modular config structure by category
14
-
15
- ## 📁 Structure
16
-
17
- ```
18
- UILayout/
19
- ├── config/ # All configuration (Single Source of Truth)
20
- │ ├── components/ # Component configs by category
21
- │ │ ├── forms.config.tsx # 8 form components
22
- │ │ ├── layout.config.tsx # 5 layout components
23
- │ │ ├── navigation.config.tsx # 4 navigation components
24
- │ │ ├── overlay.config.tsx # 11 overlay components
25
- │ │ ├── feedback.config.tsx # 5 feedback components
26
- │ │ ├── data.config.tsx # 5 data display components
27
- │ │ ├── specialized.config.tsx # 2 specialized components
28
- │ │ ├── blocks.config.tsx # 7 landing page blocks
29
- │ │ ├── hooks.config.tsx # 6 custom hooks
30
- │ │ └── index.ts # Aggregates all configs
31
- │ ├── categories.config.tsx # Category definitions
32
- │ ├── tailwind.config.ts # Tailwind 4 guidelines
33
- │ ├── ai-export.config.ts # AI context generator
34
- │ └── index.ts # Main config exports
35
- ├── components/ # React components
36
- │ ├── AutoComponentDemo.tsx # Auto-renders from config
37
- │ ├── CategoryRenderer.tsx # Renders entire category
38
- │ ├── TailwindGuideRenderer.tsx # Renders Tailwind guide
39
- │ ├── Header.tsx # Header with "Copy for AI"
40
- │ ├── Sidebar.tsx
41
- │ └── MobileOverlay.tsx
42
- ├── context/ # React Context
43
- │ └── ShowcaseContext.tsx # Navigation state management
44
- ├── UILayout.tsx # Main layout component
45
- ├── UIGuideView.tsx # Complete UI guide view
46
- ├── UIGuideLanding.tsx # Landing page
47
- └── UIGuideApp.tsx # Full app wrapper
48
- ```
49
-
50
- ## 🚀 Quick Start
51
-
52
- ### Basic Usage
53
-
54
- ```tsx
55
- import { UILayout, CATEGORIES } from '@djangocfg/layouts';
56
-
57
- function MyComponentGuide() {
58
- const [category, setCategory] = useState('forms');
59
-
60
- return (
61
- <UILayout
62
- title="My Component Library"
63
- categories={CATEGORIES}
64
- currentCategory={category}
65
- onCategoryChange={setCategory}
66
- >
67
- {/* Your content */}
68
- </UILayout>
69
- );
70
- }
71
- ```
72
-
73
- ### Using Category Renderer (Auto-render from config)
74
-
75
- ```tsx
76
- import { UILayout, CATEGORIES, CategoryRenderer } from '@djangocfg/layouts';
77
-
78
- function MyComponentGuide() {
79
- const [category, setCategory] = useState('forms');
80
-
81
- return (
82
- <UILayout
83
- title="My Component Library"
84
- categories={CATEGORIES}
85
- currentCategory={category}
86
- onCategoryChange={setCategory}
87
- >
88
- {/* Automatically renders all components in category */}
89
- <CategoryRenderer categoryId={category} />
90
- </UILayout>
91
- );
92
- }
93
- ```
94
-
95
- ### Using Complete UI Guide
96
-
97
- ```tsx
98
- import { UIGuideApp } from '@djangocfg/layouts';
99
-
100
- // Complete pre-configured UI guide with all components
101
- export default function Page() {
102
- return <UIGuideApp />;
103
- }
104
- ```
105
-
106
- ## 📝 Adding New Components
107
-
108
- ### 1. Add to Config
109
-
110
- Edit the appropriate config file in `config/components/`:
111
-
112
- ```tsx
113
- // config/components/forms.config.tsx
114
- export const FORM_COMPONENTS: ComponentConfig[] = [
115
- {
116
- name: 'MyComponent',
117
- category: 'forms',
118
- description: 'A custom form component',
119
- importPath: "import { MyComponent } from '@mylib/ui';",
120
- example: `<MyComponent value="test" onChange={handler} />`,
121
- preview: <MyComponent value="test" onChange={() => {}} />
122
- },
123
- // ... other components
124
- ];
125
- ```
126
-
127
- ### 2. That's It!
128
-
129
- No need to:
130
- - ❌ Create separate demo files
131
- - ❌ Write duplicate rendering code
132
- - ❌ Update multiple places
133
-
134
- The component automatically:
135
- - ✅ Appears in the UI guide
136
- - ✅ Gets included in "Copy for AI"
137
- - ✅ Shows in the category with proper formatting
138
-
139
- ## 🤖 Copy for AI Feature
140
-
141
- Click the "Copy for AI" button in the header to export entire documentation including:
142
-
143
- - ✅ Tailwind CSS v4 guidelines and best practices
144
- - ✅ All 53 components with full examples
145
- - ✅ Import statements
146
- - ✅ Usage examples
147
- - ✅ Properly formatted for AI consumption
148
-
149
- Perfect for giving AI assistants complete context about your UI library!
150
-
151
- ## 📊 Component Statistics
152
-
153
- | Category | Components |
154
- |----------|------------|
155
- | Forms | 8 |
156
- | Layout | 5 |
157
- | Navigation | 4 |
158
- | Overlay | 11 |
159
- | Feedback | 5 |
160
- | Data Display | 5 |
161
- | Specialized | 2 |
162
- | Blocks | 7 |
163
- | Hooks | 6 |
164
- | **Total** | **53** |
165
-
166
- ## 🎨 Customization
167
-
168
- ### Custom Categories
169
-
170
- ```tsx
171
- import type { ComponentCategory } from '@djangocfg/layouts';
172
-
173
- const customCategories: ComponentCategory[] = [
174
- {
175
- id: 'custom',
176
- label: 'My Category',
177
- icon: <MyIcon />,
178
- count: 5,
179
- description: 'Custom component category'
180
- }
181
- ];
182
- ```
183
-
184
- ### Custom Config
185
-
186
- ```tsx
187
- import type { ComponentConfig } from '@djangocfg/layouts';
188
-
189
- const customComponents: ComponentConfig[] = [
190
- {
191
- name: 'Component',
192
- category: 'custom',
193
- description: '...',
194
- importPath: '...',
195
- example: '...',
196
- preview: <Component />
197
- }
198
- ];
199
- ```
200
-
201
- ## 🔧 API Reference
202
-
203
- ### UILayout Props
204
-
205
- ```typescript
206
- interface UILayoutProps {
207
- children: ReactNode;
208
- title?: string;
209
- description?: string;
210
- categories: ComponentCategory[];
211
- currentCategory?: string;
212
- onCategoryChange?: (categoryId: string) => void;
213
- logo?: ReactNode;
214
- projectName?: string;
215
- }
216
- ```
217
-
218
- ### ComponentConfig Type
219
-
220
- ```typescript
221
- interface ComponentConfig {
222
- name: string; // Component name
223
- category: string; // Category ID
224
- description: string; // Short description
225
- importPath: string; // Import statement
226
- example: string; // Code example
227
- preview: ReactNode; // Live preview component
228
- }
229
- ```
230
-
231
- ### Available Exports
232
-
233
- ```typescript
234
- // Components
235
- export { UILayout, CategoryRenderer, AutoComponentDemo };
236
-
237
- // Views
238
- export { UIGuideView, UIGuideApp, UIGuideLanding };
239
-
240
- // Config
241
- export {
242
- CATEGORIES,
243
- COMPONENTS_CONFIG,
244
- generateAIContext
245
- };
246
-
247
- // Types
248
- export type {
249
- ComponentConfig,
250
- ComponentCategory,
251
- UILayoutProps
252
- };
253
- ```
254
-
255
- ## 🎯 Benefits
256
-
257
- 1. **Single Source of Truth**: All component data in one place
258
- 2. **Zero Duplication**: Write component config once, use everywhere
259
- 3. **Type-Safe**: Full TypeScript support prevents errors
260
- 4. **Auto-Update**: Add to config, automatically appears everywhere
261
- 5. **AI-Friendly**: Built-in export for AI assistants
262
- 6. **Maintainable**: Easy to update and extend
263
- 7. **Scalable**: Add categories and components effortlessly
264
-
265
- ## 📖 More Info
266
-
267
- See the main package README for complete documentation and examples.