@djangocfg/layouts 2.1.20 → 2.1.21

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 (28) hide show
  1. package/package.json +5 -5
  2. package/src/layouts/AppLayout/AppLayout.tsx +29 -27
  3. package/src/layouts/AppLayout/BaseApp.tsx +36 -38
  4. package/src/layouts/PublicLayout/PublicLayout.tsx +9 -43
  5. package/src/layouts/PublicLayout/components/PublicFooter/DjangoCFGLogo.tsx +45 -0
  6. package/src/layouts/PublicLayout/components/PublicFooter/FooterBottom.tsx +114 -0
  7. package/src/layouts/PublicLayout/components/PublicFooter/FooterMenuSections.tsx +53 -0
  8. package/src/layouts/PublicLayout/components/PublicFooter/FooterProjectInfo.tsx +77 -0
  9. package/src/layouts/PublicLayout/components/PublicFooter/FooterSocialLinks.tsx +82 -0
  10. package/src/layouts/PublicLayout/components/PublicFooter/PublicFooter.tsx +129 -0
  11. package/src/layouts/PublicLayout/components/PublicFooter/index.ts +17 -0
  12. package/src/layouts/PublicLayout/components/PublicFooter/types.ts +57 -0
  13. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +3 -6
  14. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +3 -6
  15. package/src/layouts/PublicLayout/index.ts +12 -1
  16. package/src/layouts/_components/UserMenu.tsx +159 -38
  17. package/src/layouts/index.ts +4 -1
  18. package/src/layouts/shared/README.md +86 -0
  19. package/src/layouts/shared/index.ts +21 -0
  20. package/src/layouts/shared/types.ts +215 -0
  21. package/src/snippets/McpChat/components/AIChatWidget.tsx +150 -53
  22. package/src/snippets/McpChat/components/AskAIButton.tsx +2 -5
  23. package/src/snippets/McpChat/components/ChatMessages.tsx +30 -9
  24. package/src/snippets/McpChat/components/ChatPanel.tsx +1 -1
  25. package/src/snippets/McpChat/components/ChatSidebar.tsx +1 -1
  26. package/src/snippets/McpChat/components/MessageBubble.tsx +46 -34
  27. package/src/snippets/McpChat/context/AIChatContext.tsx +23 -6
  28. package/src/layouts/PublicLayout/components/PublicFooter.tsx +0 -190
@@ -0,0 +1,86 @@
1
+ # Shared Layout Types
2
+
3
+ Universal type system for all layouts to avoid duplication and ensure consistency.
4
+
5
+ ## Overview
6
+
7
+ This module provides shared TypeScript types used across all layout components in the `@djangocfg/layouts` package.
8
+
9
+ ## Available Types
10
+
11
+ ### Core Configuration Types
12
+
13
+ - **`ThemeConfig`** - Theme settings (light/dark/system)
14
+ - **`AuthConfig`** - Authentication configuration
15
+ - **`ErrorTrackingConfig`** - Error tracking settings
16
+ - **`ErrorBoundaryConfig`** - Error boundary options
17
+ - **`SWRConfigOptions`** - SWR data fetching configuration
18
+ - **`McpChatConfig`** - MCP AI chat widget settings
19
+
20
+ ### Layout Component Types
21
+
22
+ - **`BaseLayoutProps`** - Base props for all layouts (includes all configs above)
23
+ - **`NavigationItem`** - Single navigation item
24
+ - **`NavigationSection`** - Group of navigation items
25
+ - **`FooterLink`** - Footer link
26
+ - **`FooterMenuSection`** - Footer menu section
27
+ - **`FooterSocialLinks`** - Social media links
28
+ - **`FooterConfig`** - Complete footer configuration
29
+
30
+ ## Usage
31
+
32
+ ### Import Types
33
+
34
+ ```typescript
35
+ import type {
36
+ BaseLayoutProps,
37
+ McpChatConfig,
38
+ ThemeConfig,
39
+ FooterConfig,
40
+ } from '@djangocfg/layouts';
41
+ ```
42
+
43
+ ### Extend Layout Props
44
+
45
+ ```typescript
46
+ import type { BaseLayoutProps } from '@djangocfg/layouts';
47
+
48
+ interface MyCustomLayoutProps extends BaseLayoutProps {
49
+ customProp?: string;
50
+ }
51
+ ```
52
+
53
+ ### MCP Chat Configuration
54
+
55
+ ```typescript
56
+ import { AppLayout } from '@djangocfg/layouts';
57
+
58
+ <AppLayout
59
+ mcpChat={{
60
+ enabled: true,
61
+ autoDetectEnvironment: true,
62
+ title: 'My AI Assistant',
63
+ position: 'bottom-right',
64
+ enableStreaming: true,
65
+ }}
66
+ >
67
+ {children}
68
+ </AppLayout>
69
+ ```
70
+
71
+ ## Benefits
72
+
73
+ 1. **No Duplication** - Define types once, use everywhere
74
+ 2. **Type Safety** - Full TypeScript support across all layouts
75
+ 3. **Consistency** - All layouts use the same prop names and shapes
76
+ 4. **Easy Maintenance** - Update types in one place
77
+ 5. **Better DX** - IntelliSense shows all available options
78
+
79
+ ## File Structure
80
+
81
+ ```
82
+ shared/
83
+ ├── types.ts # All type definitions
84
+ ├── index.ts # Type exports
85
+ └── README.md # This file
86
+ ```
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared Layouts Exports
3
+ */
4
+
5
+ export type {
6
+ ThemeConfig,
7
+ LayoutErrorTrackingConfig,
8
+ ErrorBoundaryConfig,
9
+ SWRConfigOptions,
10
+ McpChatConfig,
11
+ BaseLayoutProps,
12
+ NavigationItem,
13
+ NavigationSection,
14
+ FooterLink,
15
+ FooterMenuSection,
16
+ FooterSocialLinks,
17
+ FooterConfig,
18
+ UserMenuItem,
19
+ UserMenuGroup,
20
+ UserMenuConfig,
21
+ } from './types';
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Shared Types for All Layouts
3
+ *
4
+ * Universal type system to avoid duplication across layouts
5
+ */
6
+
7
+ import type { ReactNode } from 'react';
8
+ import type { LucideIcon } from 'lucide-react';
9
+ import type { AuthConfig } from '@djangocfg/api/auth';
10
+
11
+ // ============================================================================
12
+ // Theme Configuration
13
+ // ============================================================================
14
+
15
+ export interface ThemeConfig {
16
+ defaultTheme?: 'light' | 'dark' | 'system';
17
+ storageKey?: string;
18
+ }
19
+
20
+ // ============================================================================
21
+ // Error Tracking Configuration
22
+ // ============================================================================
23
+
24
+ /**
25
+ * Error tracking configuration for layouts
26
+ * Note: Import detailed types from @djangocfg/layouts/components if needed
27
+ */
28
+ export interface LayoutErrorTrackingConfig {
29
+ validation?: {
30
+ enabled?: boolean;
31
+ showToast?: boolean;
32
+ };
33
+ cors?: {
34
+ enabled?: boolean;
35
+ showToast?: boolean;
36
+ };
37
+ network?: {
38
+ enabled?: boolean;
39
+ showToast?: boolean;
40
+ };
41
+ onError?: (error: any) => boolean | void;
42
+ }
43
+
44
+ // ============================================================================
45
+ // Error Boundary Configuration
46
+ // ============================================================================
47
+
48
+ export interface ErrorBoundaryConfig {
49
+ enabled?: boolean;
50
+ supportEmail?: string;
51
+ onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
52
+ }
53
+
54
+ // ============================================================================
55
+ // SWR Configuration
56
+ // ============================================================================
57
+
58
+ export interface SWRConfigOptions {
59
+ revalidateOnFocus?: boolean;
60
+ revalidateOnReconnect?: boolean;
61
+ dedupingInterval?: number;
62
+ }
63
+
64
+ // ============================================================================
65
+ // MCP Chat Configuration
66
+ // ============================================================================
67
+
68
+ export interface McpChatConfig {
69
+ /** Enable MCP chat widget */
70
+ enabled?: boolean;
71
+ /** API endpoint for chat */
72
+ apiEndpoint?: string;
73
+ /** Chat widget title */
74
+ title?: string;
75
+ /** Input placeholder */
76
+ placeholder?: string;
77
+ /** Greeting message */
78
+ greeting?: string;
79
+ /** Widget position */
80
+ position?: 'bottom-right' | 'bottom-left';
81
+ /** Widget variant */
82
+ variant?: 'default' | 'minimal';
83
+ /** Enable streaming responses */
84
+ enableStreaming?: boolean;
85
+ /** Auto-detect environment (dev/prod) */
86
+ autoDetectEnvironment?: boolean;
87
+ /** Custom class name */
88
+ className?: string;
89
+ }
90
+
91
+ // ============================================================================
92
+ // Base Layout Props
93
+ // ============================================================================
94
+
95
+ export interface BaseLayoutProps {
96
+ children: ReactNode;
97
+
98
+ /** Theme configuration */
99
+ theme?: ThemeConfig;
100
+
101
+ /** Auth configuration */
102
+ auth?: AuthConfig;
103
+
104
+ /** Error tracking configuration */
105
+ errorTracking?: LayoutErrorTrackingConfig;
106
+
107
+ /** SWR configuration */
108
+ swr?: SWRConfigOptions;
109
+
110
+ /** Error boundary configuration (enabled by default) */
111
+ errorBoundary?: ErrorBoundaryConfig;
112
+
113
+ /** MCP chat configuration */
114
+ mcpChat?: McpChatConfig;
115
+ }
116
+
117
+ // ============================================================================
118
+ // Navigation Types
119
+ // ============================================================================
120
+
121
+ export interface NavigationItem {
122
+ label: string;
123
+ href: string;
124
+ icon?: LucideIcon | string;
125
+ badge?: string | number;
126
+ external?: boolean;
127
+ }
128
+
129
+ export interface NavigationSection {
130
+ title?: string;
131
+ items: NavigationItem[];
132
+ }
133
+
134
+ // ============================================================================
135
+ // Footer Types
136
+ // ============================================================================
137
+
138
+ export interface FooterLink {
139
+ label: string;
140
+ path: string;
141
+ external?: boolean;
142
+ }
143
+
144
+ export interface FooterMenuSection {
145
+ title: string;
146
+ items: FooterLink[];
147
+ }
148
+
149
+ export interface FooterSocialLinks {
150
+ github?: string;
151
+ linkedin?: string;
152
+ twitter?: string;
153
+ telegram?: string;
154
+ youtube?: string;
155
+ facebook?: string;
156
+ instagram?: string;
157
+ whatsapp?: string;
158
+ email?: string;
159
+ }
160
+
161
+ export interface FooterConfig {
162
+ siteName?: string;
163
+ description?: string;
164
+ logo?: string;
165
+ badge?: {
166
+ icon: LucideIcon;
167
+ text: string;
168
+ };
169
+ socialLinks?: FooterSocialLinks;
170
+ links?: FooterLink[];
171
+ menuSections?: FooterMenuSection[];
172
+ copyright?: string;
173
+ credits?: {
174
+ text: string;
175
+ url?: string;
176
+ };
177
+ variant?: 'full' | 'simple';
178
+ }
179
+
180
+ // ============================================================================
181
+ // User Menu Types
182
+ // ============================================================================
183
+
184
+ export interface UserMenuItem {
185
+ /** Menu item label */
186
+ label: string;
187
+ /** Link href (optional if onClick is provided) */
188
+ href?: string;
189
+ /** Icon component */
190
+ icon?: LucideIcon;
191
+ /** Visual variant */
192
+ variant?: 'default' | 'destructive';
193
+ /** Click handler (optional if href is provided) */
194
+ onClick?: () => void;
195
+ /** Open link in new tab */
196
+ external?: boolean;
197
+ }
198
+
199
+ export interface UserMenuGroup {
200
+ /** Optional group title (renders DropdownMenuLabel) */
201
+ title?: string;
202
+ /** Menu items in this group */
203
+ items: UserMenuItem[];
204
+ }
205
+
206
+ export interface UserMenuConfig {
207
+ /** Menu groups for authenticated users */
208
+ groups?: UserMenuGroup[];
209
+ /** Profile page path (used when no groups provided - backward compatibility) */
210
+ profilePath?: string;
211
+ /** Dashboard page path (used when no groups provided - backward compatibility) */
212
+ dashboardPath?: string;
213
+ /** Auth page path (for sign in button) */
214
+ authPath?: string;
215
+ }
@@ -9,48 +9,109 @@ import { useAIChatContext, useAIChatContextOptional, AIChatProvider } from '../c
9
9
  import { useChatLayout } from '../hooks/useChatLayout';
10
10
  import { getMcpEndpoints, type ChatWidgetConfig } from '../types';
11
11
 
12
- // CSS for mysterious rotating border animation with multi-color ethereal effects
12
+ // CSS for game-quality multi-layer animated border with smooth color flow
13
13
  const fabAnimationStyles = `
14
14
  @keyframes rotate-gradient {
15
15
  0% { transform: rotate(0deg); }
16
16
  100% { transform: rotate(360deg); }
17
17
  }
18
+
19
+ @keyframes rotate-gradient-reverse {
20
+ 0% { transform: rotate(360deg); }
21
+ 100% { transform: rotate(0deg); }
22
+ }
23
+
18
24
  @keyframes color-shift-glow {
19
25
  0%, 100% {
20
26
  box-shadow:
21
- 0 0 15px rgba(251, 191, 36, 0.4),
22
- 0 0 30px rgba(168, 85, 247, 0.2),
23
- 0 0 45px rgba(20, 184, 166, 0.1);
27
+ 0 0 20px rgba(251, 191, 36, 0.5),
28
+ 0 0 40px rgba(168, 85, 247, 0.3),
29
+ 0 0 60px rgba(20, 184, 166, 0.2);
24
30
  }
25
- 25% {
31
+ 33% {
26
32
  box-shadow:
27
- 0 0 18px rgba(168, 85, 247, 0.4),
28
- 0 0 35px rgba(20, 184, 166, 0.25),
29
- 0 0 50px rgba(251, 191, 36, 0.1);
33
+ 0 0 20px rgba(168, 85, 247, 0.5),
34
+ 0 0 40px rgba(20, 184, 166, 0.3),
35
+ 0 0 60px rgba(251, 191, 36, 0.2);
30
36
  }
31
- 50% {
37
+ 66% {
32
38
  box-shadow:
33
- 0 0 20px rgba(20, 184, 166, 0.4),
34
- 0 0 40px rgba(251, 191, 36, 0.2),
35
- 0 0 55px rgba(168, 85, 247, 0.15);
36
- }
37
- 75% {
38
- box-shadow:
39
- 0 0 17px rgba(236, 72, 153, 0.35),
40
- 0 0 32px rgba(168, 85, 247, 0.25),
41
- 0 0 48px rgba(20, 184, 166, 0.1);
39
+ 0 0 20px rgba(20, 184, 166, 0.5),
40
+ 0 0 40px rgba(236, 72, 153, 0.3),
41
+ 0 0 60px rgba(168, 85, 247, 0.2);
42
42
  }
43
43
  }
44
+
44
45
  @keyframes icon-pulse {
45
46
  0%, 100% {
46
47
  opacity: 1;
47
48
  transform: scale(1);
48
- filter: drop-shadow(0 0 2px rgba(251, 191, 36, 0.5));
49
+ filter: drop-shadow(0 0 4px rgba(251, 191, 36, 0.7));
49
50
  }
50
51
  50% {
51
52
  opacity: 0.85;
52
- transform: scale(0.95);
53
- filter: drop-shadow(0 0 6px rgba(251, 191, 36, 0.8));
53
+ transform: scale(1.15);
54
+ filter: drop-shadow(0 0 12px rgba(251, 191, 36, 1));
55
+ }
56
+ }
57
+
58
+ @keyframes border-pulse {
59
+ 0%, 100% {
60
+ opacity: 1;
61
+ filter: blur(0px);
62
+ }
63
+ 50% {
64
+ opacity: 0.85;
65
+ filter: blur(0.5px);
66
+ }
67
+ }
68
+
69
+ @keyframes inner-glow-pulse {
70
+ 0%, 100% {
71
+ box-shadow:
72
+ inset 0 0 15px rgba(251, 191, 36, 0.3),
73
+ inset 0 0 25px rgba(168, 85, 247, 0.2);
74
+ }
75
+ 50% {
76
+ box-shadow:
77
+ inset 0 0 20px rgba(168, 85, 247, 0.35),
78
+ inset 0 0 30px rgba(20, 184, 166, 0.25);
79
+ }
80
+ }
81
+
82
+ @keyframes fab-entrance {
83
+ 0% {
84
+ transform: scale(0);
85
+ }
86
+ 50% {
87
+ transform: scale(1.08);
88
+ }
89
+ 70% {
90
+ transform: scale(0.98);
91
+ }
92
+ 85% {
93
+ transform: scale(1.02);
94
+ }
95
+ 100% {
96
+ transform: scale(1);
97
+ }
98
+ }
99
+
100
+ @keyframes fab-glow-entrance {
101
+ 0% {
102
+ box-shadow: 0 0 0 rgba(251, 191, 36, 0);
103
+ }
104
+ 40% {
105
+ box-shadow:
106
+ 0 0 25px rgba(251, 191, 36, 0.6),
107
+ 0 0 50px rgba(168, 85, 247, 0.4),
108
+ 0 0 75px rgba(20, 184, 166, 0.25);
109
+ }
110
+ 100% {
111
+ box-shadow:
112
+ 0 0 20px rgba(251, 191, 36, 0.5),
113
+ 0 0 40px rgba(168, 85, 247, 0.3),
114
+ 0 0 60px rgba(20, 184, 166, 0.2);
54
115
  }
55
116
  }
56
117
  `;
@@ -75,67 +136,103 @@ const AIChatWidgetInternal = React.memo<{ className?: string }>(({ className })
75
136
  const fabStyles = getFabStyles(position);
76
137
  const floatingStyles = getFloatingStyles(position);
77
138
 
78
- // Mode: closed - just show FAB with multi-color rotating border animation
139
+ // Mode: closed - just show FAB with game-quality multi-layer animated border
79
140
  if (displayMode === 'closed') {
80
141
  return (
81
142
  <Portal>
82
143
  <style>{fabAnimationStyles}</style>
83
144
  <div style={fabStyles} className={className || ''}>
84
- {/* Outer glow container with color-shifting animation */}
145
+ {/* Outer glow container with entrance and color-shifting animations */}
85
146
  <div
86
147
  className="relative rounded-full"
87
148
  style={{
88
- width: '64px',
89
- height: '64px',
90
- animation: 'color-shift-glow 6s ease-in-out infinite',
149
+ width: '68px',
150
+ height: '68px',
151
+ overflow: 'hidden',
152
+ animation: 'fab-entrance 0.6s cubic-bezier(0.34, 1.45, 0.64, 1) 0s 1 normal forwards, fab-glow-entrance 0.8s ease-out 0s 1 normal forwards, color-shift-glow 8s ease-in-out 0.6s infinite',
91
153
  }}
92
154
  >
93
- {/* Border container - clips the rotating gradient */}
155
+ {/* Border container - multiple layers for depth */}
94
156
  <div
95
- className="absolute rounded-full group"
157
+ className="absolute rounded-full"
96
158
  style={{
97
159
  inset: '0',
98
160
  overflow: 'hidden',
99
161
  }}
100
162
  >
101
- {/* Rotating conic gradient - multi-color organic glow */}
163
+ {/* Layer 1: Base smooth gradient with more color stops */}
102
164
  <div
103
- className="absolute"
165
+ className="absolute rounded-full"
104
166
  style={{
105
- width: '200%',
106
- height: '200%',
107
- top: '-50%',
108
- left: '-50%',
167
+ inset: '0',
109
168
  background: `conic-gradient(
110
169
  from 0deg,
111
- #fbbf24 0%,
112
- transparent 8%,
113
- #a855f7 18%,
114
- transparent 28%,
115
- #14b8a6 38%,
116
- transparent 52%,
117
- #ec4899 62%,
118
- transparent 75%,
119
- #fbbf24 88%,
120
- transparent 95%,
121
- #a855f7 100%
170
+ rgba(251, 191, 36, 1) 0%,
171
+ rgba(251, 191, 36, 0.7) 8%,
172
+ rgba(251, 191, 36, 0) 15%,
173
+ rgba(168, 85, 247, 0) 20%,
174
+ rgba(168, 85, 247, 0.7) 28%,
175
+ rgba(168, 85, 247, 1) 35%,
176
+ rgba(168, 85, 247, 0.7) 42%,
177
+ rgba(168, 85, 247, 0) 50%,
178
+ rgba(20, 184, 166, 0) 55%,
179
+ rgba(20, 184, 166, 0.7) 63%,
180
+ rgba(20, 184, 166, 1) 70%,
181
+ rgba(20, 184, 166, 0.7) 77%,
182
+ rgba(20, 184, 166, 0) 85%,
183
+ rgba(236, 72, 153, 0) 88%,
184
+ rgba(236, 72, 153, 0.7) 93%,
185
+ rgba(236, 72, 153, 1) 97%,
186
+ rgba(251, 191, 36, 1) 100%
187
+ )`,
188
+ animation: 'rotate-gradient 7s linear infinite, border-pulse 4s ease-in-out infinite',
189
+ filter: 'blur(1px)',
190
+ opacity: 0.95,
191
+ }}
192
+ />
193
+
194
+ {/* Layer 2: Secondary gradient (counter-clockwise) - stronger */}
195
+ <div
196
+ className="absolute rounded-full"
197
+ style={{
198
+ inset: '1px',
199
+ background: `conic-gradient(
200
+ from 180deg,
201
+ rgba(168, 85, 247, 0.85) 0%,
202
+ rgba(168, 85, 247, 0.5) 10%,
203
+ rgba(168, 85, 247, 0) 20%,
204
+ rgba(20, 184, 166, 0) 30%,
205
+ rgba(20, 184, 166, 0.5) 40%,
206
+ rgba(20, 184, 166, 0.85) 50%,
207
+ rgba(20, 184, 166, 0.5) 60%,
208
+ rgba(20, 184, 166, 0) 70%,
209
+ rgba(251, 191, 36, 0) 75%,
210
+ rgba(251, 191, 36, 0.5) 85%,
211
+ rgba(251, 191, 36, 0.85) 95%,
212
+ rgba(168, 85, 247, 0.85) 100%
122
213
  )`,
123
- animation: 'rotate-gradient 5s linear infinite',
124
- opacity: 0.9,
214
+ animation: 'rotate-gradient-reverse 9s linear infinite',
215
+ filter: 'blur(0.75px)',
216
+ opacity: 0.75,
125
217
  }}
126
218
  />
127
- {/* Inner mask - creates the thin organic border */}
219
+
220
+ {/* Inner mask with glowing edge */}
128
221
  <div
129
222
  className="absolute rounded-full bg-background"
130
- style={{ inset: '1.5px' }}
223
+ style={{
224
+ inset: '4px',
225
+ animation: 'inner-glow-pulse 5s ease-in-out infinite',
226
+ }}
131
227
  />
228
+
132
229
  {/* Main FAB button */}
133
230
  <Button
134
231
  onClick={openChat}
135
232
  variant="ghost"
136
- className="absolute rounded-full hover:scale-105 transition-all duration-300 bg-background hover:bg-background/95 border-0"
233
+ className="absolute rounded-full hover:scale-105 transition-all duration-300 bg-background/80 hover:bg-background/95 border-0 backdrop-blur-sm"
137
234
  style={{
138
- inset: '1.5px',
235
+ inset: '2.5px',
139
236
  width: 'auto',
140
237
  height: 'auto',
141
238
  }}
@@ -143,7 +240,7 @@ const AIChatWidgetInternal = React.memo<{ className?: string }>(({ className })
143
240
  <Zap
144
241
  className="h-6 w-6"
145
242
  style={{
146
- animation: 'icon-pulse 2s ease-in-out infinite',
243
+ animation: 'icon-pulse 2.5s ease-in-out infinite',
147
244
  color: '#fbbf24',
148
245
  fill: '#fbbf24',
149
246
  }}
@@ -225,7 +322,7 @@ AIChatWidgetInternal.displayName = 'AIChatWidgetInternal';
225
322
  */
226
323
  export const AIChatWidget: React.FC<AIChatWidgetProps> = ({
227
324
  apiEndpoint,
228
- title = 'DjangoCFG AI Assistant',
325
+ title = 'DjangoCFG AI',
229
326
  placeholder = 'Ask about DjangoCFG...',
230
327
  greeting = "Hi! I'm your DjangoCFG AI assistant powered by GPT. Ask me anything about configuration, features, or how to use the library.",
231
328
  position = 'bottom-right',
@@ -54,12 +54,13 @@ export function AskAIButton({
54
54
  className,
55
55
  ...buttonProps
56
56
  }: AskAIButtonProps) {
57
- const { sendToChat, isChatAvailable } = useMcpChat();
57
+ const { sendToChat } = useMcpChat();
58
58
 
59
59
  const handleClick = () => {
60
60
  const detail: McpChatEventDetail = {
61
61
  message,
62
62
  autoSend,
63
+ // No displayMode - chat will use remembered mode automatically
63
64
  };
64
65
 
65
66
  if (contextData || source) {
@@ -73,16 +74,12 @@ export function AskAIButton({
73
74
  onSent?.();
74
75
  };
75
76
 
76
- const isAvailable = isChatAvailable();
77
-
78
77
  return (
79
78
  <Button
80
79
  onClick={handleClick}
81
80
  variant={variant}
82
81
  size={size}
83
82
  className={className}
84
- disabled={!isAvailable}
85
- title={!isAvailable ? 'AI Chat not available' : undefined}
86
83
  {...buttonProps}
87
84
  >
88
85
  {showIcon && <Bot className="h-4 w-4 mr-2" />}