@djangocfg/layouts 1.2.20 → 1.2.22

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/layouts",
3
- "version": "1.2.20",
3
+ "version": "1.2.22",
4
4
  "description": "Layout system and components for Unrealon applications",
5
5
  "author": {
6
6
  "name": "DjangoCFG",
@@ -53,9 +53,9 @@
53
53
  "check": "tsc --noEmit"
54
54
  },
55
55
  "peerDependencies": {
56
- "@djangocfg/api": "^1.2.20",
57
- "@djangocfg/og-image": "^1.2.20",
58
- "@djangocfg/ui": "^1.2.20",
56
+ "@djangocfg/api": "^1.2.22",
57
+ "@djangocfg/og-image": "^1.2.22",
58
+ "@djangocfg/ui": "^1.2.22",
59
59
  "@hookform/resolvers": "^5.2.0",
60
60
  "consola": "^3.4.2",
61
61
  "lucide-react": "^0.468.0",
@@ -76,7 +76,7 @@
76
76
  "vidstack": "0.6.15"
77
77
  },
78
78
  "devDependencies": {
79
- "@djangocfg/typescript-config": "^1.2.20",
79
+ "@djangocfg/typescript-config": "^1.2.22",
80
80
  "@types/node": "^24.7.2",
81
81
  "@types/react": "19.2.2",
82
82
  "@types/react-dom": "19.2.1",
@@ -93,25 +93,36 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
93
93
 
94
94
  // Simple profile loading without retry - now uses AccountsContext
95
95
  const loadCurrentProfile = useCallback(async (): Promise<void> => {
96
+ // console.log('[AuthContext] loadCurrentProfile called');
96
97
  try {
97
98
  // Ensure API clients are properly initialized with current token
98
- if (!api.isAuthenticated()) {
99
+ const isAuth = api.isAuthenticated();
100
+ const token = api.getToken();
101
+ // console.log('[AuthContext] isAuthenticated:', isAuth, 'token:', token ? token.substring(0, 20) + '...' : 'null');
102
+
103
+ if (!isAuth) {
104
+ console.warn('[AuthContext] No valid authentication token, throwing error');
99
105
  throw new Error('No valid authentication token');
100
106
  }
101
107
 
108
+ // console.log('[AuthContext] Refreshing profile from AccountsContext...');
102
109
  // Refresh profile from AccountsContext
103
110
  const refreshedProfile = await accounts.refreshProfile();
104
111
 
105
112
  if (refreshedProfile) {
113
+ // console.log('[AuthContext] Profile loaded successfully:', refreshedProfile.id, 'is_staff:', refreshedProfile.is_staff, 'is_superuser:', refreshedProfile.is_superuser);
106
114
  authLogger.info('Profile loaded successfully:', refreshedProfile.id);
107
115
  } else {
116
+ console.warn('[AuthContext] Profile refresh returned undefined - but keeping tokens');
108
117
  authLogger.warn('Profile refresh returned undefined - but keeping tokens');
109
118
  }
110
119
 
111
120
  // Always mark as initialized if we have valid tokens
112
121
  // Don't clear tokens just because profile fetch failed
113
122
  setInitialized(true);
123
+ // console.log('[AuthContext] loadCurrentProfile completed, initialized=true');
114
124
  } catch (error) {
125
+ console.error('[AuthContext] Failed to load profile:', error);
115
126
  authLogger.error('Failed to load profile:', error);
116
127
  // Use global error handler first, fallback to clearing state
117
128
  if (!handleGlobalAuthError(error, 'loadCurrentProfile')) {
@@ -110,6 +110,19 @@ function LayoutRouter({
110
110
  // Admin routes: Always show loading during SSR and initial client render
111
111
  // This prevents hydration mismatch when isAuthenticated differs between server/client
112
112
  if (isAdminRoute && !forceLayout) {
113
+ // In embedded mode (iframe), render AdminLayout immediately to receive postMessage
114
+ const isEmbedded = typeof window !== 'undefined' && window !== window.parent;
115
+
116
+ if (isEmbedded) {
117
+ // Skip loading checks - AdminLayout will handle auth via postMessage
118
+ return (
119
+ <AdminLayout enableParentSync={true}>
120
+ {children}
121
+ </AdminLayout>
122
+ );
123
+ }
124
+
125
+ // Standalone mode: show loading during initialization
113
126
  if (!isMounted || isLoading) {
114
127
  return (
115
128
  <div className="min-h-screen flex items-center justify-center">
@@ -16,36 +16,36 @@ export interface PackageInfo {
16
16
  /**
17
17
  * Package versions registry
18
18
  * Auto-synced from package.json files
19
- * Last updated: 2025-11-02T09:59:18.371Z
19
+ * Last updated: 2025-11-03T06:46:24.174Z
20
20
  */
21
21
  const PACKAGE_VERSIONS: PackageInfo[] = [
22
22
  {
23
23
  "name": "@djangocfg/ui",
24
- "version": "1.2.20"
24
+ "version": "1.2.22"
25
25
  },
26
26
  {
27
27
  "name": "@djangocfg/api",
28
- "version": "1.2.20"
28
+ "version": "1.2.22"
29
29
  },
30
30
  {
31
31
  "name": "@djangocfg/layouts",
32
- "version": "1.2.20"
32
+ "version": "1.2.22"
33
33
  },
34
34
  {
35
35
  "name": "@djangocfg/markdown",
36
- "version": "1.2.20"
36
+ "version": "1.2.22"
37
37
  },
38
38
  {
39
39
  "name": "@djangocfg/og-image",
40
- "version": "1.2.20"
40
+ "version": "1.2.22"
41
41
  },
42
42
  {
43
43
  "name": "@djangocfg/eslint-config",
44
- "version": "1.2.20"
44
+ "version": "1.2.22"
45
45
  },
46
46
  {
47
47
  "name": "@djangocfg/typescript-config",
48
- "version": "1.2.20"
48
+ "version": "1.2.22"
49
49
  }
50
50
  ];
51
51
 
@@ -82,27 +82,68 @@ export function AdminLayout({
82
82
  config,
83
83
  enableParentSync = true
84
84
  }: AdminLayoutProps) {
85
- const { user } = useAuth();
85
+ const [isMounted, setIsMounted] = React.useState(false);
86
+ const { user, isLoading, loadCurrentProfile } = useAuth();
87
+ // console.log('[AdminLayout] Rendering with user:', user, 'isLoading:', isLoading);
88
+
89
+ // Track mount state to prevent hydration mismatch
90
+ React.useEffect(() => {
91
+ setIsMounted(true);
92
+ }, []);
86
93
 
87
94
  // useCfgApp hook is called here to initialize iframe communication
88
95
  // Automatically sets tokens in API client when received from parent
89
96
  const { isEmbedded } = useCfgApp({
90
- onAuthTokenReceived: (authToken, refreshToken) => {
97
+ onAuthTokenReceived: async (authToken, refreshToken) => {
98
+ // console.log('[AdminLayout] onAuthTokenReceived called');
99
+ // console.log('[AdminLayout] authToken:', authToken.substring(0, 20) + '...', 'refreshToken:', refreshToken ? refreshToken.substring(0, 20) + '...' : 'null');
100
+
91
101
  // Always set tokens in API client
92
102
  api.setToken(authToken, refreshToken);
103
+ // console.log('[AdminLayout] Tokens set in API client');
104
+
105
+ // Load user profile after setting tokens
106
+ // console.log('[AdminLayout] Loading user profile...');
107
+ await loadCurrentProfile();
108
+ // console.log('[AdminLayout] User profile loaded');
93
109
 
94
110
  // Call custom handler if provided
95
111
  if (config?.onAuthTokenReceived) {
112
+ // console.log('[AdminLayout] Calling custom onAuthTokenReceived handler');
96
113
  config.onAuthTokenReceived(authToken, refreshToken);
97
114
  }
98
115
  }
99
116
  });
100
117
 
118
+ // console.log('[AdminLayout] isEmbedded:', isEmbedded);
119
+
120
+ // During SSR and initial render, show loading to prevent hydration mismatch
121
+ if (!isMounted) {
122
+ return (
123
+ <div className="min-h-screen flex items-center justify-center bg-background">
124
+ <div className="text-muted-foreground">Loading admin panel...</div>
125
+ </div>
126
+ );
127
+ }
128
+
129
+ // Show loading while auth is initializing (waiting for tokens from parent or profile loading)
130
+ if (isLoading) {
131
+ // console.log('[AdminLayout] Showing loading state - isLoading:', isLoading);
132
+ return (
133
+ <div className="min-h-screen flex items-center justify-center bg-background">
134
+ <div className="text-muted-foreground">Loading admin panel...</div>
135
+ </div>
136
+ );
137
+ }
138
+
101
139
  // Check if user has staff or superuser privileges
102
140
  const hasAdminAccess = user?.is_staff || user?.is_superuser;
141
+ // console.log('[AdminLayout] user:', user, 'hasAdminAccess:', hasAdminAccess, 'is_staff:', user?.is_staff, 'is_superuser:', user?.is_superuser);
103
142
 
104
143
  // Only render AdminLayout features for staff/superuser
105
144
  if (!hasAdminAccess) {
145
+ console.warn('[AdminLayout] Access denied - user does not have admin access');
146
+ // console.log('[AdminLayout] User details:', JSON.stringify(user, null, 2));
106
147
  return (
107
148
  <div className="min-h-screen flex items-center justify-center bg-background">
108
149
  <div className="text-center space-y-4 p-8">
@@ -9,6 +9,7 @@
9
9
  'use client';
10
10
 
11
11
  import { useEffect, useState } from 'react';
12
+ import { useRouter } from 'next/router';
12
13
  import { useAuth } from '../../../../../auth';
13
14
  import { useThemeContext } from '@djangocfg/ui';
14
15
  import { useCfgApp } from '../hooks/useApp';
@@ -47,15 +48,20 @@ export function ParentSync() {
47
48
  * Separated to avoid SSR issues during static export
48
49
  */
49
50
  function ParentSyncClient() {
51
+ const router = useRouter();
50
52
  const auth = useAuth();
51
53
  const { setTheme } = useThemeContext();
52
54
  const { isEmbedded, isMounted, parentTheme } = useCfgApp();
53
55
 
54
56
  // 1. Sync theme from parent → iframe
55
57
  useEffect(() => {
58
+ // console.log('[ParentSync] Theme sync effect triggered - isEmbedded:', isEmbedded, 'parentTheme:', parentTheme);
56
59
  if (isEmbedded && parentTheme) {
57
- // console.log('[ParentSync] 🎨 Syncing theme from parent:', parentTheme);
60
+ // console.log('[ParentSync] Syncing theme from parent:', parentTheme);
58
61
  setTheme(parentTheme);
62
+ // console.log('[ParentSync] setTheme called with:', parentTheme);
63
+ } else {
64
+ // console.log('[ParentSync] Skipping theme sync - isEmbedded:', isEmbedded, 'parentTheme:', parentTheme);
59
65
  }
60
66
  }, [isEmbedded, parentTheme, setTheme]);
61
67
 
@@ -89,94 +95,37 @@ function ParentSyncClient() {
89
95
  }
90
96
  }, [auth.isAuthenticated, auth.isLoading, auth.user, isEmbedded, isMounted]);
91
97
 
92
- // 3. Send iframe height changes to parent for auto-resize
98
+ // 3. iframe-resize removed - was causing log spam
99
+
100
+ // 4. Send navigation events to parent (for "Open in New Window" button)
93
101
  useEffect(() => {
94
102
  // Only send if embedded and mounted
95
103
  if (!isEmbedded || !isMounted) {
96
104
  return;
97
105
  }
98
106
 
99
- // Function to send height to parent
100
- const sendHeight = () => {
101
- const height = document.documentElement.scrollHeight;
102
- // console.log('[ParentSync] 📏 Sending height to parent:', height);
103
-
107
+ const handleRouteChange = (url: string) => {
104
108
  try {
105
109
  window.parent.postMessage({
106
- type: 'iframe-resize',
107
- data: { height }
110
+ type: 'iframe-navigation',
111
+ data: { path: url }
108
112
  }, '*');
109
113
  } catch (e) {
110
- console.error('[ParentSync] Failed to send height:', e);
114
+ console.error('[ParentSync] Failed to send navigation event:', e);
111
115
  }
112
116
  };
113
117
 
114
- // Send initial height
115
- sendHeight();
118
+ // Listen to Next.js router events
119
+ router.events.on('routeChangeComplete', handleRouteChange);
116
120
 
117
- // Watch for content height changes with ResizeObserver
118
- const resizeObserver = new ResizeObserver(() => {
119
- sendHeight();
120
- });
121
-
122
- // Observe body element for size changes
123
- resizeObserver.observe(document.body);
121
+ // Send initial route
122
+ handleRouteChange(router.asPath);
124
123
 
125
124
  // Cleanup
126
125
  return () => {
127
- resizeObserver.disconnect();
126
+ router.events.off('routeChangeComplete', handleRouteChange);
128
127
  };
129
- }, [isEmbedded, isMounted]);
130
-
131
- // 4. Send navigation events to parent (for "Open in New Window" button)
132
- useEffect(() => {
133
- // Only send if embedded and mounted
134
- if (!isEmbedded || !isMounted) {
135
- return;
136
- }
137
-
138
- // Import Next.js router dynamically
139
- import('next/router').then(({ default: Router }) => {
140
- const handleRouteChange = (url: string) => {
141
- // console.log('[ParentSync] 🔗 Route changed:', url);
142
-
143
- try {
144
- window.parent.postMessage({
145
- type: 'iframe-navigation',
146
- data: { path: url }
147
- }, '*');
148
- } catch (e) {
149
- console.error('[ParentSync] ❌ Failed to send navigation event:', e);
150
- }
151
-
152
- // Also send height update after route change
153
- setTimeout(() => {
154
- const height = document.documentElement.scrollHeight;
155
- try {
156
- window.parent.postMessage({
157
- type: 'iframe-resize',
158
- data: { height }
159
- }, '*');
160
- } catch (e) {
161
- console.error('[ParentSync] ❌ Failed to send height:', e);
162
- }
163
- }, 100);
164
- };
165
-
166
- // Listen to Next.js router events
167
- Router.events.on('routeChangeComplete', handleRouteChange);
168
-
169
- // Send initial route
170
- handleRouteChange(Router.asPath);
171
-
172
- // Cleanup
173
- return () => {
174
- Router.events.off('routeChangeComplete', handleRouteChange);
175
- };
176
- }).catch(err => {
177
- console.warn('[ParentSync] Failed to load next/router:', err);
178
- });
179
- }, [isEmbedded, isMounted]);
128
+ }, [isEmbedded, isMounted, router]);
180
129
 
181
130
  // This component doesn't render anything
182
131
  return null;
@@ -111,21 +111,36 @@ export function useCfgApp(options?: UseCfgAppOptions): UseCfgAppReturn {
111
111
 
112
112
  // Listen for messages from parent window
113
113
  const handleMessage = (event: MessageEvent) => {
114
+ // console.log('[useCfgApp] RAW message event:', {
115
+ // origin: event.origin,
116
+ // source: event.source === window.parent ? 'parent' : 'other',
117
+ // dataType: typeof event.data,
118
+ // data: event.data
119
+ // });
120
+
114
121
  const { type, data } = event.data || {};
122
+ // console.log('[useCfgApp] Received message:', type, data);
115
123
 
116
124
  switch (type) {
117
125
  case 'parent-auth':
126
+ // console.log('[useCfgApp] parent-auth message received');
118
127
  // Receive authentication tokens from parent
119
128
  if (data?.authToken && options?.onAuthTokenReceived) {
129
+ // console.log('[useCfgApp] Auth tokens found, calling onAuthTokenReceived callback');
130
+ // console.log('[useCfgApp] authToken:', data.authToken.substring(0, 20) + '...', 'refreshToken:', data.refreshToken ? data.refreshToken.substring(0, 20) + '...' : 'null');
120
131
  try {
121
132
  options.onAuthTokenReceived(data.authToken, data.refreshToken);
133
+ // console.log('[useCfgApp] onAuthTokenReceived callback completed successfully');
122
134
  } catch (e) {
123
135
  console.error('[useCfgApp] Failed to process auth tokens:', e);
124
136
  }
137
+ } else {
138
+ console.warn('[useCfgApp] parent-auth message received but authToken or callback missing:', { hasToken: !!data?.authToken, hasCallback: !!options?.onAuthTokenReceived });
125
139
  }
126
140
  break;
127
141
 
128
142
  case 'parent-theme':
143
+ // console.log('[useCfgApp] parent-theme message received:', data?.theme);
129
144
  // Receive theme from parent
130
145
  if (data?.theme) {
131
146
  try {
@@ -133,26 +148,25 @@ export function useCfgApp(options?: UseCfgAppOptions): UseCfgAppReturn {
133
148
  if (data.themeMode) {
134
149
  setParentThemeMode(data.themeMode);
135
150
  }
151
+ // console.log('[useCfgApp] Theme set successfully:', data.theme);
136
152
  } catch (e) {
137
153
  console.error('[useCfgApp] Failed to process theme:', e);
138
154
  }
139
155
  }
140
156
  break;
141
157
 
142
- case 'parent-resize':
143
- // Handle parent window resize (optional)
144
- break;
145
-
146
158
  default:
147
159
  break;
148
160
  }
149
161
  };
150
162
 
151
163
  window.addEventListener('message', handleMessage);
164
+ // console.log('[useCfgApp] Message listener registered, isEmbedded:', inIframe);
152
165
 
153
166
  // Send iframe-ready since listener is registered
154
167
  if (inIframe) {
155
168
  try {
169
+ // console.log('[useCfgApp] Sending iframe-ready message to parent');
156
170
  window.parent.postMessage({
157
171
  type: 'iframe-ready',
158
172
  data: {
@@ -160,9 +174,12 @@ export function useCfgApp(options?: UseCfgAppOptions): UseCfgAppReturn {
160
174
  referrer: document.referrer
161
175
  }
162
176
  }, '*');
177
+ // console.log('[useCfgApp] iframe-ready message sent');
163
178
  } catch (e) {
164
179
  console.error('[useCfgApp] Failed to notify parent about ready state:', e);
165
180
  }
181
+ } else {
182
+ // console.log('[useCfgApp] Not in iframe, skipping iframe-ready message');
166
183
  }
167
184
 
168
185
  return () => {
@@ -47,7 +47,7 @@ export function DashboardHeader({ isAdmin = false }: DashboardHeaderProps) {
47
47
 
48
48
  // Notification handler - TODO: implement notification system
49
49
  const handleNotificationClick = () => {
50
- console.log('Notifications clicked');
50
+ // console.log('Notifications clicked');
51
51
  };
52
52
 
53
53
  return (
@@ -0,0 +1,216 @@
1
+ # Developer Tools Integration
2
+
3
+ ## Overview
4
+
5
+ Successfully integrated three developer tool components into the UILayout showcase:
6
+
7
+ 1. **JsonTree** - Interactive JSON viewer with expand/collapse functionality
8
+ 2. **PrettyCode** - Syntax-highlighted code display
9
+ 3. **Mermaid** - Diagram renderer with fullscreen support
10
+
11
+ ## Changes Made
12
+
13
+ ### 1. Created Tools Configuration
14
+
15
+ **File**: `config/components/tools.config.tsx`
16
+
17
+ - Defined 3 component configurations with examples and previews
18
+ - Added sample data for demonstrations
19
+ - Included comprehensive usage examples
20
+
21
+ ### 2. Updated Components Index
22
+
23
+ **File**: `config/components/index.ts`
24
+
25
+ - Added `TOOLS_COMPONENTS` export
26
+ - Integrated tools into `COMPONENTS_CONFIG` array
27
+ - Tools now available in component registry
28
+
29
+ ### 3. Added Developer Tools Category
30
+
31
+ **File**: `config/categories.config.tsx`
32
+
33
+ - Created new "Developer Tools" category
34
+ - Added Wrench icon from lucide-react
35
+ - Positioned between "Specialized" and "Blocks" categories
36
+ - Description: "Developer utilities: JSON viewer, code syntax highlighting, Mermaid diagrams"
37
+
38
+ ### 4. Updated Tools Exports
39
+
40
+ **File**: `packages/ui/src/tools/index.ts`
41
+
42
+ - Ensured all tools are properly exported as named exports
43
+ - Exported TypeScript types (Language, JsonTreeConfig)
44
+
45
+ ## Component Features
46
+
47
+ ### JsonTree
48
+
49
+ **Features:**
50
+ - Expand/collapse all functionality
51
+ - Smart auto-expansion based on depth and collection size
52
+ - Collection info display (array length, object keys count)
53
+ - Copy to clipboard
54
+ - Download as JSON file
55
+ - Theme-aware colors using CSS variables
56
+ - String truncation for long values
57
+ - Configurable expansion limits
58
+
59
+ **Configuration Options:**
60
+ - `maxAutoExpandDepth` - Maximum depth to auto-expand (default: 2)
61
+ - `maxAutoExpandArrayItems` - Max array items to auto-expand (default: 10)
62
+ - `maxAutoExpandObjectKeys` - Max object keys to auto-expand (default: 5)
63
+ - `maxStringLength` - String truncation threshold (default: 200)
64
+ - `collectionLimit` - Collection size limit for performance (default: 50)
65
+ - `showCollectionInfo` - Display collection metadata
66
+ - `showExpandControls` - Show expand/collapse buttons
67
+ - `showActionButtons` - Show copy/download buttons
68
+
69
+ ### PrettyCode
70
+
71
+ **Features:**
72
+ - Syntax highlighting with Prism
73
+ - Automatic language detection
74
+ - Theme support (dark/light)
75
+ - Inline and block modes
76
+ - Language badge display
77
+ - Support for 15+ languages
78
+ - Custom background colors
79
+ - JSON auto-formatting
80
+
81
+ **Supported Languages:**
82
+ - JavaScript/TypeScript
83
+ - Python
84
+ - Bash/Shell
85
+ - JSON, YAML, XML
86
+ - HTML, CSS
87
+ - SQL
88
+ - Markdown
89
+ - And more...
90
+
91
+ ### Mermaid
92
+
93
+ **Features:**
94
+ - Fullscreen modal view
95
+ - Click to expand
96
+ - ESC key to close
97
+ - Theme-aware rendering
98
+ - Semantic color variables
99
+ - Support for all Mermaid diagram types
100
+ - Responsive SVG sizing
101
+ - Error handling with user feedback
102
+
103
+ **Supported Diagrams:**
104
+ - Flowchart / Graph
105
+ - Sequence diagram
106
+ - Class diagram
107
+ - State diagram
108
+ - Entity Relationship diagram
109
+ - User Journey
110
+ - Gantt chart
111
+ - Pie chart
112
+ - Git graph
113
+
114
+ ## Usage in UILayout
115
+
116
+ The tools are now accessible through the UILayout navigation:
117
+
118
+ 1. Navigate to **Developer Tools** category in sidebar
119
+ 2. Click on any tool (JsonTree, PrettyCode, Mermaid)
120
+ 3. View live preview and usage examples
121
+ 4. Copy code examples for use in your project
122
+
123
+ ## Import Examples
124
+
125
+ ```tsx
126
+ // Individual imports
127
+ import { JsonTree } from '@djangocfg/ui';
128
+ import { PrettyCode } from '@djangocfg/ui';
129
+ import { Mermaid } from '@djangocfg/ui';
130
+
131
+ // All at once
132
+ import { JsonTree, PrettyCode, Mermaid } from '@djangocfg/ui';
133
+ ```
134
+
135
+ ## Preview Examples
136
+
137
+ ### JsonTree Preview
138
+ ```tsx
139
+ <JsonTree
140
+ title="User Data"
141
+ data={{
142
+ user: {
143
+ id: 1,
144
+ name: "John Doe",
145
+ profile: { bio: "Software engineer" }
146
+ }
147
+ }}
148
+ config={{
149
+ maxAutoExpandDepth: 2,
150
+ showCollectionInfo: true,
151
+ showExpandControls: true,
152
+ }}
153
+ />
154
+ ```
155
+
156
+ ### PrettyCode Preview
157
+ ```tsx
158
+ <PrettyCode
159
+ data={pythonCode}
160
+ language="python"
161
+ />
162
+ ```
163
+
164
+ ### Mermaid Preview
165
+ ```tsx
166
+ <Mermaid
167
+ chart={`
168
+ graph TD
169
+ A[Start] --> B{Decision}
170
+ B -->|Yes| C[OK]
171
+ B -->|No| D[End]
172
+ `}
173
+ />
174
+ ```
175
+
176
+ ## File Structure
177
+
178
+ ```
179
+ UILayout/
180
+ ├── config/
181
+ │ ├── components/
182
+ │ │ ├── tools.config.tsx # NEW - Tools configurations
183
+ │ │ └── index.ts # UPDATED - Added tools export
184
+ │ └── categories.config.tsx # UPDATED - Added tools category
185
+ └── TOOLS_INTEGRATION.md # THIS FILE
186
+ ```
187
+
188
+ ## Testing
189
+
190
+ To verify the integration:
191
+
192
+ 1. Start the development server
193
+ 2. Navigate to UILayout showcase
194
+ 3. Check sidebar for "Developer Tools" category
195
+ 4. Verify all 3 components render correctly
196
+ 5. Test interactive features:
197
+ - JsonTree: expand/collapse, copy, download
198
+ - PrettyCode: syntax highlighting in different themes
199
+ - Mermaid: fullscreen view, ESC key close
200
+
201
+ ## Next Steps
202
+
203
+ Potential enhancements:
204
+ - Add search functionality to JsonTree
205
+ - Add more code language examples to PrettyCode
206
+ - Add more diagram type examples to Mermaid
207
+ - Create composite examples combining multiple tools
208
+ - Add performance benchmarks section
209
+
210
+ ## Notes
211
+
212
+ - All components are theme-aware using CSS variables
213
+ - All components support both light and dark modes
214
+ - All components are fully responsive
215
+ - No breaking changes to existing components
216
+ - Backward compatible with existing UILayout structure
@@ -16,6 +16,7 @@ import {
16
16
  Boxes,
17
17
  Code2,
18
18
  Palette,
19
+ Wrench,
19
20
  } from 'lucide-react';
20
21
  import { getComponentCount } from './components';
21
22
 
@@ -83,6 +84,13 @@ export const CATEGORIES: ComponentCategory[] = [
83
84
  count: getComponentCount('specialized'),
84
85
  description: 'Advanced components like sidebar navigation and image handling',
85
86
  },
87
+ {
88
+ id: 'tools',
89
+ label: 'Developer Tools',
90
+ icon: <Wrench className="h-4 w-4" />,
91
+ count: getComponentCount('tools'),
92
+ description: 'Developer utilities: JSON viewer, code syntax highlighting, Mermaid diagrams',
93
+ },
86
94
  {
87
95
  id: 'blocks',
88
96
  label: 'Blocks',
@@ -11,6 +11,7 @@ export { OVERLAY_COMPONENTS } from './overlay.config';
11
11
  export { FEEDBACK_COMPONENTS } from './feedback.config';
12
12
  export { DATA_COMPONENTS } from './data.config';
13
13
  export { SPECIALIZED_COMPONENTS } from './specialized.config';
14
+ export { TOOLS_COMPONENTS } from './tools.config';
14
15
  export { BLOCKS } from './blocks.config';
15
16
  export { HOOKS } from './hooks.config';
16
17
 
@@ -21,6 +22,7 @@ import { OVERLAY_COMPONENTS } from './overlay.config';
21
22
  import { FEEDBACK_COMPONENTS } from './feedback.config';
22
23
  import { DATA_COMPONENTS } from './data.config';
23
24
  import { SPECIALIZED_COMPONENTS } from './specialized.config';
25
+ import { TOOLS_COMPONENTS } from './tools.config';
24
26
  import { BLOCKS } from './blocks.config';
25
27
  import { HOOKS } from './hooks.config';
26
28
  import type { ComponentConfig } from './types';
@@ -36,6 +38,7 @@ export const COMPONENTS_CONFIG: ComponentConfig[] = [
36
38
  ...FEEDBACK_COMPONENTS,
37
39
  ...DATA_COMPONENTS,
38
40
  ...SPECIALIZED_COMPONENTS,
41
+ ...TOOLS_COMPONENTS,
39
42
  ...BLOCKS,
40
43
  ...HOOKS,
41
44
  ];
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Developer Tools Components Configuration
3
+ */
4
+
5
+ import React from 'react';
6
+ import { JsonTree, PrettyCode, Mermaid } from '@djangocfg/ui';
7
+ import type { ComponentConfig } from './types';
8
+
9
+ // Sample data for demos
10
+ const sampleJsonData = {
11
+ user: {
12
+ id: 1,
13
+ name: "John Doe",
14
+ email: "john@example.com",
15
+ profile: {
16
+ bio: "Software engineer",
17
+ location: "San Francisco",
18
+ interests: ["coding", "music", "travel"]
19
+ },
20
+ posts: [
21
+ { id: 1, title: "First Post", views: 120 },
22
+ { id: 2, title: "Second Post", views: 89 }
23
+ ]
24
+ },
25
+ settings: {
26
+ theme: "dark",
27
+ notifications: true,
28
+ language: "en"
29
+ }
30
+ };
31
+
32
+ const samplePythonCode = `def fibonacci(n):
33
+ """Calculate the nth Fibonacci number."""
34
+ if n <= 1:
35
+ return n
36
+ return fibonacci(n - 1) + fibonacci(n - 2)
37
+
38
+ # Example usage
39
+ result = fibonacci(10)
40
+ print(f"The 10th Fibonacci number is: {result}")`;
41
+
42
+ const sampleMermaidChart = `graph TD
43
+ A[Start] --> B{Is it?}
44
+ B -->|Yes| C[OK]
45
+ C --> D[Rethink]
46
+ D --> B
47
+ B ---->|No| E[End]`;
48
+
49
+ export const TOOLS_COMPONENTS: ComponentConfig[] = [
50
+ {
51
+ name: 'JsonTree',
52
+ category: 'tools',
53
+ description: 'Interactive JSON tree viewer with expand/collapse, search, and export functionality',
54
+ importPath: `import { JsonTree } from '@djangocfg/ui';`,
55
+ example: `<JsonTree
56
+ title="User Data"
57
+ data={{
58
+ user: {
59
+ id: 1,
60
+ name: "John Doe",
61
+ email: "john@example.com",
62
+ profile: {
63
+ bio: "Software engineer",
64
+ interests: ["coding", "music"]
65
+ }
66
+ }
67
+ }}
68
+ config={{
69
+ maxAutoExpandDepth: 2,
70
+ showCollectionInfo: true,
71
+ showExpandControls: true,
72
+ showActionButtons: true,
73
+ }}
74
+ />`,
75
+ preview: (
76
+ <div className="h-[500px]">
77
+ <JsonTree
78
+ title="User Data"
79
+ data={sampleJsonData}
80
+ config={{
81
+ maxAutoExpandDepth: 2,
82
+ showCollectionInfo: true,
83
+ showExpandControls: true,
84
+ showActionButtons: true,
85
+ }}
86
+ />
87
+ </div>
88
+ ),
89
+ },
90
+ {
91
+ name: 'PrettyCode',
92
+ category: 'tools',
93
+ description: 'Syntax-highlighted code display with automatic language detection and theme support',
94
+ importPath: `import { PrettyCode } from '@djangocfg/ui';`,
95
+ example: `// Code as string
96
+ <PrettyCode
97
+ data={pythonCode}
98
+ language="python"
99
+ />
100
+
101
+ // JSON object (auto-formatted)
102
+ <PrettyCode
103
+ data={{ user: "John", age: 30 }}
104
+ language="json"
105
+ />
106
+
107
+ // Inline code
108
+ <PrettyCode
109
+ data="const x = 42;"
110
+ language="javascript"
111
+ inline
112
+ />`,
113
+ preview: (
114
+ <div className="space-y-4">
115
+ {/* Block code example */}
116
+ <div className="h-[300px]">
117
+ <PrettyCode
118
+ data={samplePythonCode}
119
+ language="python"
120
+ />
121
+ </div>
122
+
123
+ {/* Inline code example */}
124
+ <div className="p-4 border rounded-md bg-muted/50">
125
+ <p className="text-sm text-muted-foreground mb-2">
126
+ Inline code example:
127
+ </p>
128
+ <div className="flex items-center gap-2">
129
+ <span className="text-sm">Run</span>
130
+ <PrettyCode
131
+ data="npm install @djangocfg/ui"
132
+ language="bash"
133
+ inline
134
+ />
135
+ <span className="text-sm">to install</span>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ ),
140
+ },
141
+ {
142
+ name: 'Mermaid',
143
+ category: 'tools',
144
+ description: 'Interactive Mermaid diagram renderer with fullscreen view and theme support',
145
+ importPath: `import { Mermaid } from '@djangocfg/ui';`,
146
+ example: `<Mermaid
147
+ chart={\`
148
+ graph TD
149
+ A[Start] --> B{Is it?}
150
+ B -->|Yes| C[OK]
151
+ C --> D[Rethink]
152
+ D --> B
153
+ B -->|No| E[End]
154
+ \`}
155
+ />
156
+
157
+ // Sequence diagram
158
+ <Mermaid
159
+ chart={\`
160
+ sequenceDiagram
161
+ participant A as Alice
162
+ participant B as Bob
163
+ A->>B: Hello Bob!
164
+ B->>A: Hello Alice!
165
+ \`}
166
+ />
167
+
168
+ // Flowchart
169
+ <Mermaid
170
+ chart={\`
171
+ flowchart LR
172
+ A[Hard edge] -->|Link text| B(Round edge)
173
+ B --> C{Decision}
174
+ C -->|One| D[Result one]
175
+ C -->|Two| E[Result two]
176
+ \`}
177
+ />`,
178
+ preview: (
179
+ <div className="space-y-4">
180
+ <Mermaid chart={sampleMermaidChart} />
181
+
182
+ <div className="p-4 border rounded-md bg-muted/50">
183
+ <p className="text-sm text-muted-foreground mb-2">
184
+ Supported diagram types:
185
+ </p>
186
+ <ul className="space-y-1 text-sm text-muted-foreground">
187
+ <li>• Flowchart / Graph</li>
188
+ <li>• Sequence diagram</li>
189
+ <li>• Class diagram</li>
190
+ <li>• State diagram</li>
191
+ <li>• Entity Relationship diagram</li>
192
+ <li>• User Journey</li>
193
+ <li>• Gantt chart</li>
194
+ <li>• Pie chart</li>
195
+ <li>• Git graph</li>
196
+ </ul>
197
+ <p className="text-xs text-muted-foreground mt-3">
198
+ Click on diagram to view in fullscreen mode
199
+ </p>
200
+ </div>
201
+ </div>
202
+ ),
203
+ },
204
+ ];