@moontra/moonui-pro 2.20.2 → 2.20.4
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 +8 -3
- package/plugin/index.d.ts +86 -0
- package/plugin/index.js +308 -0
- package/scripts/postinstall.js +191 -23
- package/src/components/advanced-chart/index.tsx +0 -1246
- package/src/components/advanced-forms/index.tsx +0 -585
- package/src/components/animated-button/index.tsx +0 -385
- package/src/components/calendar/event-dialog.tsx +0 -377
- package/src/components/calendar/index.tsx +0 -1220
- package/src/components/calendar-pro/index.tsx +0 -1697
- package/src/components/color-picker/index.tsx +0 -432
- package/src/components/credit-card-input/index.tsx +0 -406
- package/src/components/dashboard/dashboard-grid.tsx +0 -480
- package/src/components/dashboard/demo.tsx +0 -425
- package/src/components/dashboard/index.tsx +0 -1046
- package/src/components/dashboard/time-range-picker.tsx +0 -336
- package/src/components/dashboard/types.ts +0 -225
- package/src/components/dashboard/widgets/activity-feed.tsx +0 -349
- package/src/components/dashboard/widgets/chart-widget.tsx +0 -418
- package/src/components/dashboard/widgets/comparison-widget.tsx +0 -177
- package/src/components/dashboard/widgets/index.ts +0 -5
- package/src/components/dashboard/widgets/metric-card.tsx +0 -363
- package/src/components/dashboard/widgets/progress-widget.tsx +0 -113
- package/src/components/data-table/data-table-bulk-actions.tsx +0 -204
- package/src/components/data-table/data-table-column-toggle.tsx +0 -169
- package/src/components/data-table/data-table-export.ts +0 -156
- package/src/components/data-table/data-table-filter-drawer.tsx +0 -448
- package/src/components/data-table/index.tsx +0 -845
- package/src/components/draggable-list/index.tsx +0 -100
- package/src/components/error-boundary/index.tsx +0 -232
- package/src/components/file-upload/index.tsx +0 -1660
- package/src/components/floating-action-button/index.tsx +0 -206
- package/src/components/form-wizard/form-wizard-context.tsx +0 -335
- package/src/components/form-wizard/form-wizard-navigation.tsx +0 -118
- package/src/components/form-wizard/form-wizard-progress.tsx +0 -329
- package/src/components/form-wizard/form-wizard-step.tsx +0 -111
- package/src/components/form-wizard/index.tsx +0 -102
- package/src/components/form-wizard/types.ts +0 -77
- package/src/components/gesture-drawer/index.tsx +0 -551
- package/src/components/github-stars/github-api.ts +0 -426
- package/src/components/github-stars/hooks.ts +0 -517
- package/src/components/github-stars/index.tsx +0 -375
- package/src/components/github-stars/types.ts +0 -148
- package/src/components/github-stars/variants.tsx +0 -515
- package/src/components/health-check/index.tsx +0 -439
- package/src/components/hover-card-3d/index.tsx +0 -529
- package/src/components/index.ts +0 -130
- package/src/components/internal/index.ts +0 -78
- package/src/components/kanban/add-card-modal.tsx +0 -502
- package/src/components/kanban/card-detail-modal.tsx +0 -761
- package/src/components/kanban/index.ts +0 -13
- package/src/components/kanban/kanban.tsx +0 -1689
- package/src/components/kanban/types.ts +0 -168
- package/src/components/lazy-component/index.tsx +0 -823
- package/src/components/license-error/index.tsx +0 -31
- package/src/components/magnetic-button/index.tsx +0 -216
- package/src/components/memory-efficient-data/index.tsx +0 -1018
- package/src/components/moonui-quiz-form/index.tsx +0 -817
- package/src/components/navbar/index.tsx +0 -781
- package/src/components/optimized-image/index.tsx +0 -425
- package/src/components/performance-debugger/index.tsx +0 -613
- package/src/components/performance-monitor/index.tsx +0 -808
- package/src/components/phone-number-input/index.tsx +0 -343
- package/src/components/phone-number-input/phone-number-input-simple.tsx +0 -167
- package/src/components/pinch-zoom/index.tsx +0 -566
- package/src/components/quiz-form/index.tsx +0 -479
- package/src/components/rich-text-editor/index.tsx +0 -2322
- package/src/components/rich-text-editor/slash-commands-extension.ts +0 -230
- package/src/components/rich-text-editor/slash-commands.css +0 -35
- package/src/components/rich-text-editor/table-styles.css +0 -65
- package/src/components/sidebar/index.tsx +0 -884
- package/src/components/spotlight-card/index.tsx +0 -191
- package/src/components/swipeable-card/index.tsx +0 -100
- package/src/components/timeline/index.tsx +0 -1183
- package/src/components/ui/accordion.tsx +0 -581
- package/src/components/ui/alert-dialog.tsx +0 -141
- package/src/components/ui/alert.tsx +0 -141
- package/src/components/ui/aspect-ratio.tsx +0 -245
- package/src/components/ui/avatar.tsx +0 -155
- package/src/components/ui/badge.tsx +0 -230
- package/src/components/ui/breadcrumb.tsx +0 -216
- package/src/components/ui/button.tsx +0 -228
- package/src/components/ui/calendar.tsx +0 -387
- package/src/components/ui/card.tsx +0 -216
- package/src/components/ui/checkbox.tsx +0 -259
- package/src/components/ui/collapsible.tsx +0 -631
- package/src/components/ui/color-picker.tsx +0 -97
- package/src/components/ui/command.tsx +0 -948
- package/src/components/ui/dialog.tsx +0 -752
- package/src/components/ui/dropdown-menu.tsx +0 -706
- package/src/components/ui/gesture-drawer.tsx +0 -11
- package/src/components/ui/hover-card.tsx +0 -29
- package/src/components/ui/index.ts +0 -222
- package/src/components/ui/input.tsx +0 -224
- package/src/components/ui/label.tsx +0 -29
- package/src/components/ui/lightbox.tsx +0 -606
- package/src/components/ui/magnetic-button.tsx +0 -129
- package/src/components/ui/media-gallery.tsx +0 -611
- package/src/components/ui/navigation-menu.tsx +0 -130
- package/src/components/ui/pagination.tsx +0 -125
- package/src/components/ui/popover.tsx +0 -185
- package/src/components/ui/progress.tsx +0 -30
- package/src/components/ui/radio-group.tsx +0 -257
- package/src/components/ui/scroll-area.tsx +0 -47
- package/src/components/ui/select.tsx +0 -378
- package/src/components/ui/separator.tsx +0 -145
- package/src/components/ui/sheet.tsx +0 -139
- package/src/components/ui/skeleton.tsx +0 -20
- package/src/components/ui/slider.tsx +0 -354
- package/src/components/ui/spotlight-card.tsx +0 -119
- package/src/components/ui/switch.tsx +0 -86
- package/src/components/ui/table.tsx +0 -331
- package/src/components/ui/tabs-pro.tsx +0 -542
- package/src/components/ui/tabs.tsx +0 -54
- package/src/components/ui/textarea.tsx +0 -28
- package/src/components/ui/toast.tsx +0 -317
- package/src/components/ui/toggle.tsx +0 -119
- package/src/components/ui/tooltip.tsx +0 -151
- package/src/components/virtual-list/index.tsx +0 -668
- package/src/hooks/use-chart.ts +0 -205
- package/src/hooks/use-data-table.ts +0 -182
- package/src/hooks/use-docs-pro-access.ts +0 -13
- package/src/hooks/use-license-check.ts +0 -65
- package/src/hooks/use-subscription.ts +0 -19
- package/src/hooks/use-toast.ts +0 -15
- package/src/index.ts +0 -22
- package/src/lib/ai-providers.ts +0 -377
- package/src/lib/component-metadata.ts +0 -18
- package/src/lib/micro-interactions.ts +0 -255
- package/src/lib/paddle.ts +0 -17
- package/src/lib/utils.ts +0 -6
- package/src/patterns/login-form/index.tsx +0 -276
- package/src/patterns/login-form/types.ts +0 -67
- package/src/setupTests.ts +0 -41
- package/src/styles/advanced-chart.css +0 -239
- package/src/styles/calendar.css +0 -35
- package/src/styles/design-system.css +0 -363
- package/src/styles/index.css +0 -681
- package/src/styles/tailwind.css +0 -7
- package/src/styles/tokens.css +0 -455
- package/src/types/next-auth.d.ts +0 -21
- package/src/use-intersection-observer.tsx +0 -154
- package/src/use-local-storage.tsx +0 -71
- package/src/use-paddle.ts +0 -138
- package/src/use-performance-optimizer.ts +0 -389
- package/src/use-pro-access.ts +0 -141
- package/src/use-scroll-animation.ts +0 -219
- package/src/use-subscription.ts +0 -37
- package/src/use-toast.ts +0 -32
- package/src/utils/chart-helpers.ts +0 -357
- package/src/utils/cn.ts +0 -6
- package/src/utils/data-processing.ts +0 -151
- package/src/utils/license-validator.tsx +0 -183
|
@@ -1,948 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import * as React from "react"
|
|
4
|
-
import { useState, useRef, useEffect, useCallback, useMemo } from "react"
|
|
5
|
-
import {
|
|
6
|
-
Search,
|
|
7
|
-
Mic,
|
|
8
|
-
MicOff,
|
|
9
|
-
Clock,
|
|
10
|
-
Sparkles,
|
|
11
|
-
ChevronRight,
|
|
12
|
-
Zap,
|
|
13
|
-
Brain,
|
|
14
|
-
Settings,
|
|
15
|
-
Wand2,
|
|
16
|
-
Bot,
|
|
17
|
-
RefreshCw,
|
|
18
|
-
X,
|
|
19
|
-
Check
|
|
20
|
-
} from "lucide-react"
|
|
21
|
-
import { Command as CommandPrimitive } from "cmdk"
|
|
22
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
23
|
-
import { motion, AnimatePresence } from "framer-motion"
|
|
24
|
-
import Fuse from "fuse.js"
|
|
25
|
-
|
|
26
|
-
import { cn } from "../../lib/utils"
|
|
27
|
-
import { Dialog, DialogContent, DialogTitle, DialogHeader, DialogDescription } from "./dialog"
|
|
28
|
-
import { Badge } from "./badge"
|
|
29
|
-
import { Button } from "./button"
|
|
30
|
-
import {
|
|
31
|
-
Tooltip,
|
|
32
|
-
TooltipContent,
|
|
33
|
-
TooltipProvider,
|
|
34
|
-
TooltipTrigger
|
|
35
|
-
} from "./tooltip"
|
|
36
|
-
import {
|
|
37
|
-
DropdownMenu,
|
|
38
|
-
DropdownMenuContent,
|
|
39
|
-
DropdownMenuItem,
|
|
40
|
-
DropdownMenuSeparator,
|
|
41
|
-
DropdownMenuTrigger,
|
|
42
|
-
} from "./dropdown-menu"
|
|
43
|
-
import { Input } from "./input"
|
|
44
|
-
import { Label } from "./label"
|
|
45
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./select"
|
|
46
|
-
import { createAIProvider, type AIProvider } from "../../lib/ai-providers"
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* AI-Enhanced Command Palette Component
|
|
50
|
-
*
|
|
51
|
-
* Features:
|
|
52
|
-
* - Fuzzy search with typo tolerance
|
|
53
|
-
* - AI-powered natural language processing
|
|
54
|
-
* - Voice commands with Web Speech API
|
|
55
|
-
* - Smart suggestions based on usage patterns
|
|
56
|
-
* - Intelligent history tracking
|
|
57
|
-
* - Real AI service integration
|
|
58
|
-
*/
|
|
59
|
-
|
|
60
|
-
// AI Configuration Types
|
|
61
|
-
export interface CommandAIConfig {
|
|
62
|
-
provider?: 'openai' | 'claude' | 'gemini';
|
|
63
|
-
apiKey?: string;
|
|
64
|
-
model?: string;
|
|
65
|
-
temperature?: number;
|
|
66
|
-
maxTokens?: number;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
interface AISettingsType {
|
|
70
|
-
provider: 'openai' | 'claude' | 'gemini'
|
|
71
|
-
apiKey: string
|
|
72
|
-
model: string
|
|
73
|
-
temperature: number
|
|
74
|
-
maxTokens: number
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Command history interface
|
|
78
|
-
interface CommandHistoryItem {
|
|
79
|
-
id: string
|
|
80
|
-
command: string
|
|
81
|
-
category?: string
|
|
82
|
-
timestamp: number
|
|
83
|
-
frequency: number
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Enhanced command item interface
|
|
87
|
-
export interface CommandItemData {
|
|
88
|
-
id: string
|
|
89
|
-
label: string
|
|
90
|
-
value: string
|
|
91
|
-
category?: string
|
|
92
|
-
keywords?: string[]
|
|
93
|
-
action?: () => void
|
|
94
|
-
shortcut?: string[]
|
|
95
|
-
icon?: React.ReactNode
|
|
96
|
-
priority?: number
|
|
97
|
-
context?: string[]
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Command variants with new AI-focused styles
|
|
101
|
-
export const commandVariantsPro = cva(
|
|
102
|
-
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
|
|
103
|
-
{
|
|
104
|
-
variants: {
|
|
105
|
-
variant: {
|
|
106
|
-
default: "bg-popover text-popover-foreground",
|
|
107
|
-
glass: "bg-background/80 text-foreground backdrop-blur-sm border border-white/10",
|
|
108
|
-
bordered: "bg-popover text-popover-foreground border-2 border-border",
|
|
109
|
-
gradient: "bg-gradient-to-br from-primary/10 via-background to-secondary/10 border border-primary/20",
|
|
110
|
-
neon: "bg-background border-2 border-primary shadow-[0_0_20px_rgba(var(--primary),0.3)]",
|
|
111
|
-
},
|
|
112
|
-
size: {
|
|
113
|
-
sm: "min-h-[300px] max-h-[400px]",
|
|
114
|
-
default: "min-h-[400px] max-h-[500px]",
|
|
115
|
-
lg: "min-h-[500px] max-h-[600px]",
|
|
116
|
-
xl: "min-h-[600px] max-h-[700px]",
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
defaultVariants: {
|
|
120
|
-
variant: "default",
|
|
121
|
-
size: "default",
|
|
122
|
-
},
|
|
123
|
-
}
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
// Fuzzy search hook
|
|
127
|
-
const useFuzzySearch = (items: CommandItemData[], query: string, enabled: boolean) => {
|
|
128
|
-
return useMemo(() => {
|
|
129
|
-
if (!enabled || !query) return items
|
|
130
|
-
|
|
131
|
-
const fuse = new Fuse(items, {
|
|
132
|
-
keys: ['label', 'keywords', 'category'],
|
|
133
|
-
threshold: 0.3,
|
|
134
|
-
includeScore: true,
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
return fuse.search(query).map(result => result.item)
|
|
138
|
-
}, [items, query, enabled])
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Command history hook
|
|
142
|
-
const useCommandHistory = (enabled: boolean, maxItems: number = 10) => {
|
|
143
|
-
const [history, setHistory] = useState<CommandHistoryItem[]>([])
|
|
144
|
-
|
|
145
|
-
useEffect(() => {
|
|
146
|
-
if (!enabled) return
|
|
147
|
-
|
|
148
|
-
const stored = localStorage.getItem('moonui-command-history')
|
|
149
|
-
if (stored) {
|
|
150
|
-
setHistory(JSON.parse(stored))
|
|
151
|
-
}
|
|
152
|
-
}, [enabled])
|
|
153
|
-
|
|
154
|
-
const addToHistory = useCallback((item: CommandItemData) => {
|
|
155
|
-
if (!enabled) return
|
|
156
|
-
|
|
157
|
-
setHistory(prev => {
|
|
158
|
-
const existing = prev.find(h => h.id === item.id)
|
|
159
|
-
let updated: CommandHistoryItem[]
|
|
160
|
-
|
|
161
|
-
if (existing) {
|
|
162
|
-
updated = prev.map(h =>
|
|
163
|
-
h.id === item.id
|
|
164
|
-
? { ...h, timestamp: Date.now(), frequency: h.frequency + 1 }
|
|
165
|
-
: h
|
|
166
|
-
)
|
|
167
|
-
} else {
|
|
168
|
-
updated = [...prev, {
|
|
169
|
-
id: item.id,
|
|
170
|
-
command: item.label,
|
|
171
|
-
category: item.category,
|
|
172
|
-
timestamp: Date.now(),
|
|
173
|
-
frequency: 1,
|
|
174
|
-
}]
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Keep only maxItems
|
|
178
|
-
updated = updated
|
|
179
|
-
.sort((a, b) => b.frequency - a.frequency)
|
|
180
|
-
.slice(0, maxItems)
|
|
181
|
-
|
|
182
|
-
localStorage.setItem('moonui-command-history', JSON.stringify(updated))
|
|
183
|
-
return updated
|
|
184
|
-
})
|
|
185
|
-
}, [enabled, maxItems])
|
|
186
|
-
|
|
187
|
-
return { history, addToHistory }
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Voice command hook
|
|
191
|
-
const useVoiceCommand = (enabled: boolean, onTranscript?: (text: string) => void) => {
|
|
192
|
-
const [isListening, setIsListening] = useState(false)
|
|
193
|
-
const [transcript, setTranscript] = useState('')
|
|
194
|
-
const recognitionRef = useRef<any>(null)
|
|
195
|
-
|
|
196
|
-
useEffect(() => {
|
|
197
|
-
if (!enabled || typeof window === 'undefined') return
|
|
198
|
-
|
|
199
|
-
const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition
|
|
200
|
-
if (!SpeechRecognition) return
|
|
201
|
-
|
|
202
|
-
const recognition = new SpeechRecognition()
|
|
203
|
-
recognition.continuous = false
|
|
204
|
-
recognition.interimResults = false
|
|
205
|
-
recognition.lang = 'en-US'
|
|
206
|
-
|
|
207
|
-
recognition.onresult = (event: any) => {
|
|
208
|
-
const text = event.results[0][0].transcript
|
|
209
|
-
setTranscript(text)
|
|
210
|
-
onTranscript?.(text)
|
|
211
|
-
setIsListening(false)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
recognition.onerror = () => {
|
|
215
|
-
setIsListening(false)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
recognition.onend = () => {
|
|
219
|
-
setIsListening(false)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
recognitionRef.current = recognition
|
|
223
|
-
}, [enabled, onTranscript])
|
|
224
|
-
|
|
225
|
-
const toggleListening = useCallback(() => {
|
|
226
|
-
if (!recognitionRef.current) return
|
|
227
|
-
|
|
228
|
-
if (isListening) {
|
|
229
|
-
recognitionRef.current.stop()
|
|
230
|
-
setIsListening(false)
|
|
231
|
-
} else {
|
|
232
|
-
recognitionRef.current.start()
|
|
233
|
-
setIsListening(true)
|
|
234
|
-
}
|
|
235
|
-
}, [isListening])
|
|
236
|
-
|
|
237
|
-
return { isListening, transcript, toggleListening }
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// AI Suggestions component
|
|
241
|
-
const AISuggestions: React.FC<{
|
|
242
|
-
items: CommandItemData[]
|
|
243
|
-
onSelect: (item: CommandItemData) => void
|
|
244
|
-
history: CommandHistoryItem[]
|
|
245
|
-
}> = ({ items, onSelect, history }) => {
|
|
246
|
-
const suggestions = useMemo(() => {
|
|
247
|
-
// Combine history frequency with item priority
|
|
248
|
-
const scored = items.map(item => {
|
|
249
|
-
const historyItem = history.find(h => h.id === item.id)
|
|
250
|
-
const score = (item.priority || 0) + (historyItem?.frequency || 0) * 2
|
|
251
|
-
return { ...item, score }
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
return scored
|
|
255
|
-
.sort((a, b) => b.score - a.score)
|
|
256
|
-
.slice(0, 3)
|
|
257
|
-
}, [items, history])
|
|
258
|
-
|
|
259
|
-
if (suggestions.length === 0) return null
|
|
260
|
-
|
|
261
|
-
return (
|
|
262
|
-
<div className="px-3 py-2 border-b">
|
|
263
|
-
<div className="flex items-center gap-2 mb-2">
|
|
264
|
-
<Sparkles className="h-3 w-3 text-primary" />
|
|
265
|
-
<span className="text-xs font-medium text-muted-foreground">AI Suggestions</span>
|
|
266
|
-
</div>
|
|
267
|
-
<div className="flex gap-2">
|
|
268
|
-
{suggestions.map(item => (
|
|
269
|
-
<motion.button
|
|
270
|
-
key={item.id}
|
|
271
|
-
initial={{ opacity: 0, scale: 0.9 }}
|
|
272
|
-
animate={{ opacity: 1, scale: 1 }}
|
|
273
|
-
whileHover={{ scale: 1.05 }}
|
|
274
|
-
whileTap={{ scale: 0.95 }}
|
|
275
|
-
onClick={() => onSelect(item)}
|
|
276
|
-
className="flex items-center gap-1 px-2 py-1 text-xs bg-primary/10 hover:bg-primary/20 rounded-md transition-colors"
|
|
277
|
-
>
|
|
278
|
-
{item.icon}
|
|
279
|
-
<span>{item.label}</span>
|
|
280
|
-
</motion.button>
|
|
281
|
-
))}
|
|
282
|
-
</div>
|
|
283
|
-
</div>
|
|
284
|
-
)
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Enhanced Command Component Props
|
|
288
|
-
interface CommandProProps
|
|
289
|
-
extends Omit<React.ComponentProps<typeof CommandPrimitive>, 'onSelect'>,
|
|
290
|
-
VariantProps<typeof commandVariantsPro> {
|
|
291
|
-
items?: CommandItemData[]
|
|
292
|
-
onItemSelect?: (item: CommandItemData) => void
|
|
293
|
-
enableAI?: boolean
|
|
294
|
-
enableVoice?: boolean
|
|
295
|
-
enableFuzzySearch?: boolean
|
|
296
|
-
enableAISuggestions?: boolean
|
|
297
|
-
enableHistory?: boolean
|
|
298
|
-
maxHistoryItems?: number
|
|
299
|
-
placeholder?: string
|
|
300
|
-
emptyMessage?: string
|
|
301
|
-
showShortcuts?: boolean
|
|
302
|
-
categories?: string[]
|
|
303
|
-
onVoiceCommand?: (transcript: string) => void
|
|
304
|
-
aiConfig?: CommandAIConfig
|
|
305
|
-
persistAISettings?: boolean
|
|
306
|
-
onAICommand?: (command: string, result: string) => void
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Get AI provider instance
|
|
310
|
-
const getAIProvider = (settings: AISettingsType): AIProvider | null => {
|
|
311
|
-
if (!settings.apiKey) return null;
|
|
312
|
-
|
|
313
|
-
try {
|
|
314
|
-
return createAIProvider(settings.provider, {
|
|
315
|
-
apiKey: settings.apiKey,
|
|
316
|
-
model: settings.model,
|
|
317
|
-
temperature: settings.temperature,
|
|
318
|
-
maxTokens: settings.maxTokens
|
|
319
|
-
});
|
|
320
|
-
} catch (error) {
|
|
321
|
-
console.error('Failed to create AI provider:', error);
|
|
322
|
-
return null;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Main AI-Enhanced Command Component
|
|
327
|
-
export const MoonUICommandPro = React.forwardRef<
|
|
328
|
-
React.ElementRef<typeof CommandPrimitive>,
|
|
329
|
-
CommandProProps
|
|
330
|
-
>(({
|
|
331
|
-
className,
|
|
332
|
-
variant,
|
|
333
|
-
size,
|
|
334
|
-
items = [],
|
|
335
|
-
onItemSelect,
|
|
336
|
-
enableAI = false,
|
|
337
|
-
enableVoice = true,
|
|
338
|
-
enableFuzzySearch = true,
|
|
339
|
-
enableAISuggestions = true,
|
|
340
|
-
enableHistory = true,
|
|
341
|
-
maxHistoryItems = 10,
|
|
342
|
-
placeholder = "Search commands or type...",
|
|
343
|
-
emptyMessage = "No results found.",
|
|
344
|
-
showShortcuts = true,
|
|
345
|
-
categories,
|
|
346
|
-
onVoiceCommand,
|
|
347
|
-
aiConfig = {},
|
|
348
|
-
persistAISettings = true,
|
|
349
|
-
onAICommand,
|
|
350
|
-
...props
|
|
351
|
-
}, ref) => {
|
|
352
|
-
const [search, setSearch] = useState('')
|
|
353
|
-
const [selectedCategory, setSelectedCategory] = useState<string | null>(null)
|
|
354
|
-
const [isAISettingsOpen, setIsAISettingsOpen] = useState(false)
|
|
355
|
-
const [isProcessing, setIsProcessing] = useState(false)
|
|
356
|
-
|
|
357
|
-
// AI Settings
|
|
358
|
-
const [aiSettings, setAiSettings] = useState<AISettingsType>(() => {
|
|
359
|
-
if (persistAISettings && typeof window !== 'undefined') {
|
|
360
|
-
try {
|
|
361
|
-
const stored = localStorage.getItem('moonui-ai-settings');
|
|
362
|
-
if (stored) {
|
|
363
|
-
const parsed = JSON.parse(stored);
|
|
364
|
-
return {
|
|
365
|
-
provider: (aiConfig.provider !== undefined ? aiConfig.provider : parsed.provider || 'openai') as 'openai' | 'claude' | 'gemini',
|
|
366
|
-
apiKey: aiConfig.apiKey !== undefined ? aiConfig.apiKey : parsed.apiKey || '',
|
|
367
|
-
model: aiConfig.model !== undefined ? aiConfig.model : parsed.model || 'gpt-3.5-turbo',
|
|
368
|
-
temperature: aiConfig.temperature !== undefined ? aiConfig.temperature : parsed.temperature ?? 0.7,
|
|
369
|
-
maxTokens: aiConfig.maxTokens !== undefined ? aiConfig.maxTokens : parsed.maxTokens ?? 1000,
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
} catch (e) {
|
|
373
|
-
console.error('Failed to load AI settings from localStorage:', e);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return {
|
|
378
|
-
provider: (aiConfig.provider || 'openai') as 'openai' | 'claude' | 'gemini',
|
|
379
|
-
apiKey: aiConfig.apiKey || '',
|
|
380
|
-
model: aiConfig.model || 'gpt-3.5-turbo',
|
|
381
|
-
temperature: aiConfig.temperature ?? 0.7,
|
|
382
|
-
maxTokens: aiConfig.maxTokens ?? 1000,
|
|
383
|
-
};
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
const { history, addToHistory } = useCommandHistory(enableHistory, maxHistoryItems)
|
|
387
|
-
const { isListening, transcript, toggleListening } = useVoiceCommand(enableVoice && enableAI, (text) => {
|
|
388
|
-
setSearch(text)
|
|
389
|
-
onVoiceCommand?.(text)
|
|
390
|
-
if (enableAI) {
|
|
391
|
-
handleNaturalLanguageCommand(text)
|
|
392
|
-
}
|
|
393
|
-
})
|
|
394
|
-
|
|
395
|
-
// Filter items by category
|
|
396
|
-
const filteredByCategory = useMemo(() => {
|
|
397
|
-
if (!selectedCategory) return items
|
|
398
|
-
return items.filter(item => item.category === selectedCategory)
|
|
399
|
-
}, [items, selectedCategory])
|
|
400
|
-
|
|
401
|
-
// Apply fuzzy search
|
|
402
|
-
const searchResults = useFuzzySearch(filteredByCategory, search, enableFuzzySearch)
|
|
403
|
-
|
|
404
|
-
// Natural language command processing
|
|
405
|
-
const handleNaturalLanguageCommand = async (text: string) => {
|
|
406
|
-
if (!enableAI || !aiSettings.apiKey || isProcessing) return
|
|
407
|
-
|
|
408
|
-
setIsProcessing(true)
|
|
409
|
-
try {
|
|
410
|
-
const provider = getAIProvider(aiSettings)
|
|
411
|
-
if (!provider) {
|
|
412
|
-
throw new Error('Failed to initialize AI provider')
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// Process natural language command
|
|
416
|
-
const prompt = `Convert this natural language command to a specific action: "${text}".
|
|
417
|
-
Available commands: ${items.map(item => item.label).join(', ')}.
|
|
418
|
-
Respond with just the closest matching command name, nothing else.`
|
|
419
|
-
|
|
420
|
-
const result = await provider.generateText(prompt)
|
|
421
|
-
|
|
422
|
-
// Find matching command
|
|
423
|
-
const matchingCommand = items.find(item =>
|
|
424
|
-
item.label.toLowerCase().includes(result.toLowerCase()) ||
|
|
425
|
-
result.toLowerCase().includes(item.label.toLowerCase())
|
|
426
|
-
)
|
|
427
|
-
|
|
428
|
-
if (matchingCommand) {
|
|
429
|
-
handleSelect(matchingCommand)
|
|
430
|
-
onAICommand?.(text, matchingCommand.label)
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
} catch (error) {
|
|
434
|
-
console.error('Natural language processing error:', error)
|
|
435
|
-
} finally {
|
|
436
|
-
setIsProcessing(false)
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Handle item selection
|
|
441
|
-
const handleSelect = useCallback((item: CommandItemData) => {
|
|
442
|
-
addToHistory(item)
|
|
443
|
-
item.action?.()
|
|
444
|
-
onItemSelect?.(item)
|
|
445
|
-
}, [addToHistory, onItemSelect])
|
|
446
|
-
|
|
447
|
-
// Group items by category
|
|
448
|
-
const groupedItems = useMemo(() => {
|
|
449
|
-
const groups: Record<string, CommandItemData[]> = {}
|
|
450
|
-
|
|
451
|
-
searchResults.forEach(item => {
|
|
452
|
-
const category = item.category || 'Other'
|
|
453
|
-
if (!groups[category]) groups[category] = []
|
|
454
|
-
groups[category].push(item)
|
|
455
|
-
})
|
|
456
|
-
|
|
457
|
-
return groups
|
|
458
|
-
}, [searchResults])
|
|
459
|
-
|
|
460
|
-
return (
|
|
461
|
-
<>
|
|
462
|
-
<CommandPrimitive
|
|
463
|
-
ref={ref}
|
|
464
|
-
className={cn(commandVariantsPro({ variant, size }), className)}
|
|
465
|
-
{...props}
|
|
466
|
-
>
|
|
467
|
-
{/* Search Input with Voice and AI */}
|
|
468
|
-
<div className="flex items-center border-b px-3">
|
|
469
|
-
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
|
470
|
-
<CommandPrimitive.Input
|
|
471
|
-
value={search}
|
|
472
|
-
onValueChange={setSearch}
|
|
473
|
-
onKeyDown={(e) => {
|
|
474
|
-
if (e.key === 'Enter' && enableAI && search) {
|
|
475
|
-
e.preventDefault()
|
|
476
|
-
handleNaturalLanguageCommand(search)
|
|
477
|
-
}
|
|
478
|
-
}}
|
|
479
|
-
className="flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
|
480
|
-
placeholder={placeholder}
|
|
481
|
-
/>
|
|
482
|
-
|
|
483
|
-
{/* Voice Command Button */}
|
|
484
|
-
{enableVoice && enableAI && (
|
|
485
|
-
<TooltipProvider>
|
|
486
|
-
<Tooltip>
|
|
487
|
-
<TooltipTrigger asChild>
|
|
488
|
-
<Button
|
|
489
|
-
variant="ghost"
|
|
490
|
-
size="sm"
|
|
491
|
-
onClick={toggleListening}
|
|
492
|
-
className={cn(
|
|
493
|
-
"ml-2",
|
|
494
|
-
isListening && "text-primary animate-pulse"
|
|
495
|
-
)}
|
|
496
|
-
>
|
|
497
|
-
{isListening ? (
|
|
498
|
-
<Mic className="h-4 w-4" />
|
|
499
|
-
) : (
|
|
500
|
-
<MicOff className="h-4 w-4" />
|
|
501
|
-
)}
|
|
502
|
-
</Button>
|
|
503
|
-
</TooltipTrigger>
|
|
504
|
-
<TooltipContent>
|
|
505
|
-
{isListening ? "Listening..." : "Voice command"}
|
|
506
|
-
</TooltipContent>
|
|
507
|
-
</Tooltip>
|
|
508
|
-
</TooltipProvider>
|
|
509
|
-
)}
|
|
510
|
-
|
|
511
|
-
{/* AI Settings Button */}
|
|
512
|
-
{enableAI && (
|
|
513
|
-
<TooltipProvider>
|
|
514
|
-
<Tooltip>
|
|
515
|
-
<TooltipTrigger asChild>
|
|
516
|
-
<Button
|
|
517
|
-
variant="ghost"
|
|
518
|
-
size="sm"
|
|
519
|
-
onClick={() => setIsAISettingsOpen(true)}
|
|
520
|
-
className="ml-1"
|
|
521
|
-
>
|
|
522
|
-
<Settings className="h-4 w-4" />
|
|
523
|
-
</Button>
|
|
524
|
-
</TooltipTrigger>
|
|
525
|
-
<TooltipContent>
|
|
526
|
-
AI Settings
|
|
527
|
-
</TooltipContent>
|
|
528
|
-
</Tooltip>
|
|
529
|
-
</TooltipProvider>
|
|
530
|
-
)}
|
|
531
|
-
</div>
|
|
532
|
-
|
|
533
|
-
{/* Category Filters */}
|
|
534
|
-
{categories && categories.length > 0 && (
|
|
535
|
-
<div className="flex gap-2 px-3 py-2 border-b">
|
|
536
|
-
<Button
|
|
537
|
-
variant={selectedCategory === null ? "primary" : "outline"}
|
|
538
|
-
size="sm"
|
|
539
|
-
onClick={() => setSelectedCategory(null)}
|
|
540
|
-
className="h-7 text-xs"
|
|
541
|
-
>
|
|
542
|
-
All
|
|
543
|
-
</Button>
|
|
544
|
-
{categories.map(cat => (
|
|
545
|
-
<Button
|
|
546
|
-
key={cat}
|
|
547
|
-
variant={selectedCategory === cat ? "primary" : "outline"}
|
|
548
|
-
size="sm"
|
|
549
|
-
onClick={() => setSelectedCategory(cat)}
|
|
550
|
-
className="h-7 text-xs"
|
|
551
|
-
>
|
|
552
|
-
{cat}
|
|
553
|
-
</Button>
|
|
554
|
-
))}
|
|
555
|
-
</div>
|
|
556
|
-
)}
|
|
557
|
-
|
|
558
|
-
{/* AI Suggestions */}
|
|
559
|
-
{enableAI && enableAISuggestions && !search && (
|
|
560
|
-
<AISuggestions
|
|
561
|
-
items={items}
|
|
562
|
-
onSelect={handleSelect}
|
|
563
|
-
history={history}
|
|
564
|
-
/>
|
|
565
|
-
)}
|
|
566
|
-
|
|
567
|
-
{/* Recent Commands */}
|
|
568
|
-
{enableHistory && history.length > 0 && !search && (
|
|
569
|
-
<div className="px-3 py-2 border-b">
|
|
570
|
-
<div className="flex items-center gap-2 mb-2">
|
|
571
|
-
<Clock className="h-3 w-3 text-muted-foreground" />
|
|
572
|
-
<span className="text-xs font-medium text-muted-foreground">Recent Commands</span>
|
|
573
|
-
</div>
|
|
574
|
-
<div className="space-y-1">
|
|
575
|
-
{history.slice(0, 3).map(item => (
|
|
576
|
-
<button
|
|
577
|
-
key={item.id}
|
|
578
|
-
onClick={() => {
|
|
579
|
-
const cmd = items.find(i => i.id === item.id)
|
|
580
|
-
if (cmd) handleSelect(cmd)
|
|
581
|
-
}}
|
|
582
|
-
className="flex items-center justify-between w-full px-2 py-1 text-xs hover:bg-accent rounded-sm transition-colors"
|
|
583
|
-
>
|
|
584
|
-
<span>{item.command}</span>
|
|
585
|
-
{item.category && (
|
|
586
|
-
<Badge variant="outline" className="text-[10px] h-4">
|
|
587
|
-
{item.category}
|
|
588
|
-
</Badge>
|
|
589
|
-
)}
|
|
590
|
-
</button>
|
|
591
|
-
))}
|
|
592
|
-
</div>
|
|
593
|
-
</div>
|
|
594
|
-
)}
|
|
595
|
-
|
|
596
|
-
{/* Command List */}
|
|
597
|
-
<CommandPrimitive.List className="max-h-[300px] overflow-y-auto overflow-x-hidden p-2">
|
|
598
|
-
{searchResults.length === 0 ? (
|
|
599
|
-
<CommandPrimitive.Empty className="py-6 text-center text-sm text-muted-foreground">
|
|
600
|
-
{emptyMessage}
|
|
601
|
-
</CommandPrimitive.Empty>
|
|
602
|
-
) : (
|
|
603
|
-
<AnimatePresence>
|
|
604
|
-
{Object.entries(groupedItems).map(([category, categoryItems]) => (
|
|
605
|
-
<motion.div
|
|
606
|
-
key={category}
|
|
607
|
-
initial={{ opacity: 0, y: 10 }}
|
|
608
|
-
animate={{ opacity: 1, y: 0 }}
|
|
609
|
-
exit={{ opacity: 0, y: -10 }}
|
|
610
|
-
>
|
|
611
|
-
<CommandPrimitive.Group
|
|
612
|
-
heading={category}
|
|
613
|
-
className="overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground"
|
|
614
|
-
>
|
|
615
|
-
{categoryItems.map(item => (
|
|
616
|
-
<CommandPrimitive.Item
|
|
617
|
-
key={item.id}
|
|
618
|
-
value={item.value}
|
|
619
|
-
onSelect={() => handleSelect(item)}
|
|
620
|
-
className="relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50"
|
|
621
|
-
>
|
|
622
|
-
<div className="flex items-center gap-2 flex-1">
|
|
623
|
-
{item.icon && (
|
|
624
|
-
<span className="shrink-0">{item.icon}</span>
|
|
625
|
-
)}
|
|
626
|
-
<span>{item.label}</span>
|
|
627
|
-
</div>
|
|
628
|
-
{showShortcuts && item.shortcut && (
|
|
629
|
-
<div className="ml-auto flex gap-0.5">
|
|
630
|
-
{item.shortcut.map((key, i) => (
|
|
631
|
-
<kbd
|
|
632
|
-
key={i}
|
|
633
|
-
className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100"
|
|
634
|
-
>
|
|
635
|
-
{key}
|
|
636
|
-
</kbd>
|
|
637
|
-
))}
|
|
638
|
-
</div>
|
|
639
|
-
)}
|
|
640
|
-
</CommandPrimitive.Item>
|
|
641
|
-
))}
|
|
642
|
-
</CommandPrimitive.Group>
|
|
643
|
-
</motion.div>
|
|
644
|
-
))}
|
|
645
|
-
</AnimatePresence>
|
|
646
|
-
)}
|
|
647
|
-
</CommandPrimitive.List>
|
|
648
|
-
|
|
649
|
-
{/* AI Processing Indicator */}
|
|
650
|
-
{isProcessing && (
|
|
651
|
-
<div className="px-3 py-2 border-t">
|
|
652
|
-
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
653
|
-
<RefreshCw className="h-3 w-3 animate-spin" />
|
|
654
|
-
<span>Processing natural language command...</span>
|
|
655
|
-
</div>
|
|
656
|
-
</div>
|
|
657
|
-
)}
|
|
658
|
-
|
|
659
|
-
{/* Natural Language Hint */}
|
|
660
|
-
{enableAI && (
|
|
661
|
-
<div className="px-3 py-2 border-t">
|
|
662
|
-
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
663
|
-
<Zap className="h-3 w-3" />
|
|
664
|
-
<span>Tip: You can use natural language commands like "open settings"</span>
|
|
665
|
-
</div>
|
|
666
|
-
</div>
|
|
667
|
-
)}
|
|
668
|
-
</CommandPrimitive>
|
|
669
|
-
|
|
670
|
-
{/* AI Settings Modal */}
|
|
671
|
-
{enableAI && (
|
|
672
|
-
<Dialog open={isAISettingsOpen} onOpenChange={setIsAISettingsOpen}>
|
|
673
|
-
<DialogContent className="sm:max-w-[425px]">
|
|
674
|
-
<DialogHeader>
|
|
675
|
-
<DialogTitle>AI Settings</DialogTitle>
|
|
676
|
-
<DialogDescription>
|
|
677
|
-
Configure your AI provider and API settings for enhanced command processing.
|
|
678
|
-
</DialogDescription>
|
|
679
|
-
</DialogHeader>
|
|
680
|
-
<div className="grid gap-4 py-4">
|
|
681
|
-
<div className="grid gap-2">
|
|
682
|
-
<Label htmlFor="provider">Provider</Label>
|
|
683
|
-
<Select
|
|
684
|
-
value={aiSettings.provider}
|
|
685
|
-
onValueChange={(value: 'openai' | 'claude' | 'gemini') => {
|
|
686
|
-
const defaultModels = {
|
|
687
|
-
openai: 'gpt-3.5-turbo',
|
|
688
|
-
claude: 'claude-3-sonnet-20240229',
|
|
689
|
-
gemini: 'gemini-2.0-flash'
|
|
690
|
-
};
|
|
691
|
-
const newSettings = {
|
|
692
|
-
...aiSettings,
|
|
693
|
-
provider: value,
|
|
694
|
-
model: defaultModels[value] || 'gpt-3.5-turbo'
|
|
695
|
-
};
|
|
696
|
-
setAiSettings(newSettings);
|
|
697
|
-
if (persistAISettings) {
|
|
698
|
-
localStorage.setItem('moonui-ai-settings', JSON.stringify(newSettings));
|
|
699
|
-
}
|
|
700
|
-
}}
|
|
701
|
-
>
|
|
702
|
-
<SelectTrigger>
|
|
703
|
-
<SelectValue />
|
|
704
|
-
</SelectTrigger>
|
|
705
|
-
<SelectContent>
|
|
706
|
-
<SelectItem value="openai">OpenAI</SelectItem>
|
|
707
|
-
<SelectItem value="claude">Claude (Anthropic)</SelectItem>
|
|
708
|
-
<SelectItem value="gemini">Gemini (Google)</SelectItem>
|
|
709
|
-
</SelectContent>
|
|
710
|
-
</Select>
|
|
711
|
-
</div>
|
|
712
|
-
<div className="grid gap-2">
|
|
713
|
-
<Label htmlFor="apiKey">API Key</Label>
|
|
714
|
-
<Input
|
|
715
|
-
id="apiKey"
|
|
716
|
-
type="password"
|
|
717
|
-
value={aiSettings.apiKey}
|
|
718
|
-
onChange={(e) => {
|
|
719
|
-
const newSettings = { ...aiSettings, apiKey: e.target.value };
|
|
720
|
-
setAiSettings(newSettings);
|
|
721
|
-
if (persistAISettings) {
|
|
722
|
-
localStorage.setItem('moonui-ai-settings', JSON.stringify(newSettings));
|
|
723
|
-
}
|
|
724
|
-
}}
|
|
725
|
-
placeholder="sk-..."
|
|
726
|
-
/>
|
|
727
|
-
</div>
|
|
728
|
-
<div className="grid gap-2">
|
|
729
|
-
<Label htmlFor="model">Model</Label>
|
|
730
|
-
<Select
|
|
731
|
-
value={aiSettings.model}
|
|
732
|
-
onValueChange={(value) => {
|
|
733
|
-
const newSettings = { ...aiSettings, model: value };
|
|
734
|
-
setAiSettings(newSettings);
|
|
735
|
-
if (persistAISettings) {
|
|
736
|
-
localStorage.setItem('moonui-ai-settings', JSON.stringify(newSettings));
|
|
737
|
-
}
|
|
738
|
-
}}
|
|
739
|
-
>
|
|
740
|
-
<SelectTrigger>
|
|
741
|
-
<SelectValue />
|
|
742
|
-
</SelectTrigger>
|
|
743
|
-
<SelectContent>
|
|
744
|
-
{aiSettings.provider === 'openai' && (
|
|
745
|
-
<>
|
|
746
|
-
<SelectItem value="gpt-4">GPT-4</SelectItem>
|
|
747
|
-
<SelectItem value="gpt-3.5-turbo">GPT-3.5 Turbo</SelectItem>
|
|
748
|
-
</>
|
|
749
|
-
)}
|
|
750
|
-
{aiSettings.provider === 'claude' && (
|
|
751
|
-
<>
|
|
752
|
-
<SelectItem value="claude-3-opus">Claude 3 Opus</SelectItem>
|
|
753
|
-
<SelectItem value="claude-3-sonnet">Claude 3 Sonnet</SelectItem>
|
|
754
|
-
<SelectItem value="claude-3-haiku">Claude 3 Haiku</SelectItem>
|
|
755
|
-
</>
|
|
756
|
-
)}
|
|
757
|
-
{aiSettings.provider === 'gemini' && (
|
|
758
|
-
<>
|
|
759
|
-
<SelectItem value="gemini-2.0-flash">Gemini 2.0 Flash</SelectItem>
|
|
760
|
-
<SelectItem value="gemini-1.5-flash">Gemini 1.5 Flash</SelectItem>
|
|
761
|
-
<SelectItem value="gemini-1.5-pro">Gemini 1.5 Pro</SelectItem>
|
|
762
|
-
</>
|
|
763
|
-
)}
|
|
764
|
-
{false && (
|
|
765
|
-
<>
|
|
766
|
-
<SelectItem value="command">Command</SelectItem>
|
|
767
|
-
<SelectItem value="command-light">Command Light</SelectItem>
|
|
768
|
-
</>
|
|
769
|
-
)}
|
|
770
|
-
</SelectContent>
|
|
771
|
-
</Select>
|
|
772
|
-
</div>
|
|
773
|
-
</div>
|
|
774
|
-
<div className="flex justify-end gap-2">
|
|
775
|
-
<Button
|
|
776
|
-
variant="outline"
|
|
777
|
-
onClick={() => setIsAISettingsOpen(false)}
|
|
778
|
-
>
|
|
779
|
-
Cancel
|
|
780
|
-
</Button>
|
|
781
|
-
<Button onClick={() => setIsAISettingsOpen(false)}>
|
|
782
|
-
Save Settings
|
|
783
|
-
</Button>
|
|
784
|
-
</div>
|
|
785
|
-
</DialogContent>
|
|
786
|
-
</Dialog>
|
|
787
|
-
)}
|
|
788
|
-
</>
|
|
789
|
-
)
|
|
790
|
-
})
|
|
791
|
-
MoonUICommandPro.displayName = CommandPrimitive.displayName
|
|
792
|
-
|
|
793
|
-
// Enhanced Dialog wrapper for AI Command
|
|
794
|
-
interface CommandDialogProProps extends React.ComponentProps<typeof Dialog> {
|
|
795
|
-
commandProps?: CommandProProps
|
|
796
|
-
children?: React.ReactNode
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
export const MoonUICommandDialogPro = ({
|
|
800
|
-
children,
|
|
801
|
-
commandProps,
|
|
802
|
-
...props
|
|
803
|
-
}: CommandDialogProProps) => {
|
|
804
|
-
return (
|
|
805
|
-
<Dialog {...props}>
|
|
806
|
-
<DialogContent className="overflow-hidden p-0 shadow-2xl" hideCloseButton>
|
|
807
|
-
<DialogTitle className="sr-only">AI Command Menu</DialogTitle>
|
|
808
|
-
<MoonUICommandPro {...commandProps}>
|
|
809
|
-
{children}
|
|
810
|
-
</MoonUICommandPro>
|
|
811
|
-
</DialogContent>
|
|
812
|
-
</Dialog>
|
|
813
|
-
)
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
// Basic Command Components (for backward compatibility)
|
|
817
|
-
interface CommandInputProps
|
|
818
|
-
extends React.ComponentProps<typeof CommandPrimitive.Input> {}
|
|
819
|
-
|
|
820
|
-
export const MoonUICommandInputPro = React.forwardRef<
|
|
821
|
-
React.ElementRef<typeof CommandPrimitive.Input>,
|
|
822
|
-
CommandInputProps
|
|
823
|
-
>(({ className, ...props }, ref) => (
|
|
824
|
-
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
|
|
825
|
-
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
|
826
|
-
<CommandPrimitive.Input
|
|
827
|
-
ref={ref}
|
|
828
|
-
className={cn(
|
|
829
|
-
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
|
830
|
-
className
|
|
831
|
-
)}
|
|
832
|
-
{...props}
|
|
833
|
-
/>
|
|
834
|
-
</div>
|
|
835
|
-
))
|
|
836
|
-
MoonUICommandInputPro.displayName = CommandPrimitive.Input.displayName
|
|
837
|
-
|
|
838
|
-
interface CommandListProps
|
|
839
|
-
extends React.ComponentProps<typeof CommandPrimitive.List> {}
|
|
840
|
-
|
|
841
|
-
export const MoonUICommandListPro = React.forwardRef<
|
|
842
|
-
React.ElementRef<typeof CommandPrimitive.List>,
|
|
843
|
-
CommandListProps
|
|
844
|
-
>(({ className, ...props }, ref) => (
|
|
845
|
-
<CommandPrimitive.List
|
|
846
|
-
ref={ref}
|
|
847
|
-
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
|
|
848
|
-
{...props}
|
|
849
|
-
/>
|
|
850
|
-
))
|
|
851
|
-
MoonUICommandListPro.displayName = CommandPrimitive.List.displayName
|
|
852
|
-
|
|
853
|
-
interface CommandEmptyProps
|
|
854
|
-
extends React.ComponentProps<typeof CommandPrimitive.Empty> {}
|
|
855
|
-
|
|
856
|
-
export const MoonUICommandEmptyPro = React.forwardRef<
|
|
857
|
-
React.ElementRef<typeof CommandPrimitive.Empty>,
|
|
858
|
-
CommandEmptyProps
|
|
859
|
-
>(({ className, ...props }, ref) => (
|
|
860
|
-
<CommandPrimitive.Empty
|
|
861
|
-
ref={ref}
|
|
862
|
-
className={cn("py-6 text-center text-sm text-muted-foreground", className)}
|
|
863
|
-
{...props}
|
|
864
|
-
/>
|
|
865
|
-
))
|
|
866
|
-
MoonUICommandEmptyPro.displayName = CommandPrimitive.Empty.displayName
|
|
867
|
-
|
|
868
|
-
interface CommandGroupProps
|
|
869
|
-
extends React.ComponentProps<typeof CommandPrimitive.Group> {}
|
|
870
|
-
|
|
871
|
-
export const MoonUICommandGroupPro = React.forwardRef<
|
|
872
|
-
React.ElementRef<typeof CommandPrimitive.Group>,
|
|
873
|
-
CommandGroupProps
|
|
874
|
-
>(({ className, ...props }, ref) => (
|
|
875
|
-
<CommandPrimitive.Group
|
|
876
|
-
ref={ref}
|
|
877
|
-
className={cn(
|
|
878
|
-
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
|
879
|
-
className
|
|
880
|
-
)}
|
|
881
|
-
{...props}
|
|
882
|
-
/>
|
|
883
|
-
))
|
|
884
|
-
MoonUICommandGroupPro.displayName = CommandPrimitive.Group.displayName
|
|
885
|
-
|
|
886
|
-
interface CommandSeparatorProps
|
|
887
|
-
extends React.ComponentProps<typeof CommandPrimitive.Separator> {}
|
|
888
|
-
|
|
889
|
-
export const MoonUICommandSeparatorPro = React.forwardRef<
|
|
890
|
-
React.ElementRef<typeof CommandPrimitive.Separator>,
|
|
891
|
-
CommandSeparatorProps
|
|
892
|
-
>(({ className, ...props }, ref) => (
|
|
893
|
-
<CommandPrimitive.Separator
|
|
894
|
-
ref={ref}
|
|
895
|
-
className={cn("-mx-1 h-px bg-border", className)}
|
|
896
|
-
{...props}
|
|
897
|
-
/>
|
|
898
|
-
))
|
|
899
|
-
MoonUICommandSeparatorPro.displayName = CommandPrimitive.Separator.displayName
|
|
900
|
-
|
|
901
|
-
interface CommandItemProps
|
|
902
|
-
extends React.ComponentProps<typeof CommandPrimitive.Item> {}
|
|
903
|
-
|
|
904
|
-
export const MoonUICommandItemPro = React.forwardRef<
|
|
905
|
-
React.ElementRef<typeof CommandPrimitive.Item>,
|
|
906
|
-
CommandItemProps
|
|
907
|
-
>(({ className, ...props }, ref) => (
|
|
908
|
-
<CommandPrimitive.Item
|
|
909
|
-
ref={ref}
|
|
910
|
-
className={cn(
|
|
911
|
-
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
|
|
912
|
-
className
|
|
913
|
-
)}
|
|
914
|
-
{...props}
|
|
915
|
-
/>
|
|
916
|
-
))
|
|
917
|
-
MoonUICommandItemPro.displayName = CommandPrimitive.Item.displayName
|
|
918
|
-
|
|
919
|
-
export const MoonUICommandShortcutPro = ({
|
|
920
|
-
className,
|
|
921
|
-
...props
|
|
922
|
-
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
|
923
|
-
return (
|
|
924
|
-
<span
|
|
925
|
-
className={cn(
|
|
926
|
-
"ml-auto text-xs tracking-widest text-muted-foreground",
|
|
927
|
-
className
|
|
928
|
-
)}
|
|
929
|
-
{...props}
|
|
930
|
-
/>
|
|
931
|
-
)
|
|
932
|
-
}
|
|
933
|
-
MoonUICommandShortcutPro.displayName = "CommandShortcutPro"
|
|
934
|
-
|
|
935
|
-
// Additional exports for convenience
|
|
936
|
-
export {
|
|
937
|
-
commandVariantsPro as commandVariants,
|
|
938
|
-
MoonUICommandPro as Command,
|
|
939
|
-
MoonUICommandDialogPro as CommandDialog,
|
|
940
|
-
MoonUICommandInputPro as CommandInput,
|
|
941
|
-
MoonUICommandListPro as CommandList,
|
|
942
|
-
MoonUICommandEmptyPro as CommandEmpty,
|
|
943
|
-
MoonUICommandGroupPro as CommandGroup,
|
|
944
|
-
MoonUICommandSeparatorPro as CommandSeparator,
|
|
945
|
-
MoonUICommandItemPro as CommandItem,
|
|
946
|
-
MoonUICommandShortcutPro as CommandShortcut
|
|
947
|
-
}
|
|
948
|
-
|