diff --git a/src/components/skills/view/ProviderSkills.tsx b/src/components/skills/view/ProviderSkills.tsx index 099452a3..df864262 100644 --- a/src/components/skills/view/ProviderSkills.tsx +++ b/src/components/skills/view/ProviderSkills.tsx @@ -19,6 +19,9 @@ import { cn } from '../../../lib/utils'; import { Badge, Button, + Dialog, + DialogContent, + DialogTitle, Input, } from '../../../shared/view/ui'; import { useProviderSkills } from '../hooks/useProviderSkills'; @@ -212,7 +215,7 @@ export default function ProviderSkills({ selectedProvider, currentProjects }: Pr const [submitError, setSubmitError] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [searchQuery, setSearchQuery] = useState(''); - const [isAddPanelOpen, setIsAddPanelOpen] = useState(false); + const [isAddDialogOpen, setIsAddDialogOpen] = useState(false); const [showInstallPath, setShowInstallPath] = useState(false); const fileInputRef = useRef(null); const folderInputRef = useRef(null); @@ -225,7 +228,7 @@ export default function ProviderSkills({ selectedProvider, currentProjects }: Pr setSubmitError(null); setIsSubmitting(false); setSearchQuery(''); - setIsAddPanelOpen(false); + setIsAddDialogOpen(false); setShowInstallPath(false); }, [selectedProvider]); @@ -354,7 +357,7 @@ export default function ProviderSkills({ selectedProvider, currentProjects }: Pr }))); await addSkills({ entries }); setQueuedFiles([]); - setIsAddPanelOpen(false); + setIsAddDialogOpen(false); } catch (error) { setSubmitError(error instanceof Error ? error.message : 'Failed to import skills'); } finally { @@ -362,8 +365,22 @@ export default function ProviderSkills({ selectedProvider, currentProjects }: Pr } }, [addSkills, queuedFiles]); + const handleAddDialogOpenChange = useCallback((open: boolean) => { + if (open) { + setSubmitError(null); + setShowInstallPath(false); + setIsAddDialogOpen(true); + return; + } + + setQueuedFiles([]); + setSubmitError(null); + setShowInstallPath(false); + setIsAddDialogOpen(false); + }, []); + const uploadPanel = ( -
+
)} -
- - Folder uploads keep the selected folder name; standalone files use the `name` in `SKILL.md`. - -
- - -
-
); @@ -558,11 +545,7 @@ export default function ProviderSkills({ selectedProvider, currentProjects }: Pr type="button" size="sm" className="w-full sm:w-auto" - onClick={() => { - setSubmitError(null); - setShowInstallPath(false); - setIsAddPanelOpen((current) => !current); - }} + onClick={() => handleAddDialogOpenChange(true)} > Add Skill @@ -586,15 +569,89 @@ export default function ProviderSkills({ selectedProvider, currentProjects }: Pr )}
- {isAddPanelOpen && uploadPanel} + + + Add {providerName} Skill +
+
+
+ +
+
+
Add {providerName} Skill
+
+ Upload a SKILL.md file or a complete skill folder. +
+
+ +
+
- {(submitError || loadError) && ( +
+ {uploadPanel} +
+ +
+
+ {(submitError || loadError || saveStatus === 'success') ? ( +
+ {submitError || loadError || 'Skills saved successfully.'} +
+ ) : ( + + Folder uploads keep the selected folder name; standalone files use the `name` in `SKILL.md`. + + )} +
+
+ + +
+
+
+
+ + {!isAddDialogOpen && (submitError || loadError) && (
{submitError || loadError}
)} - {saveStatus === 'success' && !isAddPanelOpen && ( + {saveStatus === 'success' && !isAddDialogOpen && (
Skills saved successfully. diff --git a/src/shared/view/ui/Dialog.tsx b/src/shared/view/ui/Dialog.tsx index a3fb3740..f40a7a20 100644 --- a/src/shared/view/ui/Dialog.tsx +++ b/src/shared/view/ui/Dialog.tsx @@ -92,12 +92,13 @@ DialogTrigger.displayName = 'DialogTrigger'; interface DialogContentProps extends React.HTMLAttributes { onEscapeKeyDown?: () => void; onPointerDownOutside?: () => void; + wrapperClassName?: string; } const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'; const DialogContent = React.forwardRef( - ({ className, children, onEscapeKeyDown, onPointerDownOutside, ...props }, ref) => { + ({ className, children, onEscapeKeyDown, onPointerDownOutside, wrapperClassName, ...props }, ref) => { const { open, onOpenChange, triggerRef } = useDialog(); const contentRef = React.useRef(null); const previousFocusRef = React.useRef(null); @@ -171,7 +172,7 @@ const DialogContent = React.forwardRef( if (!open) return null; return createPortal( -
+
{/* Overlay */}