diff --git a/src/components/SlashCommandPicker.tsx b/src/components/SlashCommandPicker.tsx index b1efec7..36bab2a 100644 --- a/src/components/SlashCommandPicker.tsx +++ b/src/components/SlashCommandPicker.tsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useRef } from "react"; import { motion } from "framer-motion"; import { Button } from "@/components/ui/button"; +import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { api } from "@/lib/api"; import { X, @@ -11,7 +12,9 @@ import { Zap, FileCode, Terminal, - AlertCircle + AlertCircle, + User, + Building2 } from "lucide-react"; import type { SlashCommand } from "@/lib/api"; import { cn } from "@/lib/utils"; @@ -81,6 +84,7 @@ export const SlashCommandPicker: React.FC = ({ const [error, setError] = useState(null); const [selectedIndex, setSelectedIndex] = useState(0); const [searchQuery, setSearchQuery] = useState(initialQuery); + const [activeTab, setActiveTab] = useState("custom"); const commandListRef = useRef(null); @@ -89,7 +93,7 @@ export const SlashCommandPicker: React.FC = ({ loadCommands(); }, [projectPath]); - // Filter commands based on search query + // Filter commands based on search query and active tab useEffect(() => { if (!commands.length) { setFilteredCommands([]); @@ -97,11 +101,23 @@ export const SlashCommandPicker: React.FC = ({ } const query = searchQuery.toLowerCase(); + let filteredByTab: SlashCommand[]; - if (!query) { - setFilteredCommands(commands); + // Filter by active tab + if (activeTab === "default") { + // No default/built-in commands yet + filteredByTab = []; } else { - const filtered = commands.filter(cmd => { + // Show all custom commands (both user and project) + filteredByTab = commands; + } + + // Then filter by search query + let filtered: SlashCommand[]; + if (!query) { + filtered = filteredByTab; + } else { + filtered = filteredByTab.filter(cmd => { // Match against command name if (cmd.name.toLowerCase().includes(query)) return true; @@ -134,13 +150,13 @@ export const SlashCommandPicker: React.FC = ({ // Then alphabetically return a.name.localeCompare(b.name); }); - - setFilteredCommands(filtered); } + setFilteredCommands(filtered); + // Reset selected index when filtered list changes setSelectedIndex(0); - }, [searchQuery, commands]); + }, [searchQuery, commands, activeTab]); // Keyboard navigation useEffect(() => { @@ -205,9 +221,17 @@ export const SlashCommandPicker: React.FC = ({ onSelect(command); }; - // Group commands by namespace (or "Commands" if no namespace) + // Group commands by scope and namespace for the Custom tab const groupedCommands = filteredCommands.reduce((acc, cmd) => { - const key = cmd.namespace || "Commands"; + let key: string; + if (cmd.scope === "user") { + key = cmd.namespace ? `User Commands: ${cmd.namespace}` : "User Commands"; + } else if (cmd.scope === "project") { + key = cmd.namespace ? `Project Commands: ${cmd.namespace}` : "Project Commands"; + } else { + key = cmd.namespace || "Commands"; + } + if (!acc[key]) { acc[key] = []; } @@ -254,6 +278,16 @@ export const SlashCommandPicker: React.FC = ({ + + {/* Tabs */} +
+ + + Default + Custom + + +
{/* Command List */} @@ -271,163 +305,187 @@ export const SlashCommandPicker: React.FC = ({ )} - {!isLoading && !error && filteredCommands.length === 0 && ( -
- - - {searchQuery ? 'No commands found' : 'No commands available'} - - {!searchQuery && ( -

- Create commands in .claude/commands/ or ~/.claude/commands/ -

- )} -
- )} - - {!isLoading && !error && filteredCommands.length > 0 && ( -
- {/* If no grouping needed, show flat list */} - {Object.keys(groupedCommands).length === 1 ? ( -
- {filteredCommands.map((command, index) => { - const Icon = getCommandIcon(command); - const isSelected = index === selectedIndex; - - return ( - - ); - })} + {!isLoading && !error && ( + <> + {/* Default Tab Content */} + {activeTab === "default" && ( +
+ + + No default commands available + +

+ Default commands are built-in system commands +

- ) : ( - // Show grouped by scope/namespace -
- {Object.entries(groupedCommands).map(([groupKey, groupCommands]) => ( -
-

- {groupKey} -

- -
- {groupCommands.map((command) => { - const Icon = getCommandIcon(command); - const globalIndex = filteredCommands.indexOf(command); - const isSelected = globalIndex === selectedIndex; - - return ( - - ); - })} -
+ )} + + {/* Custom Tab Content */} + {activeTab === "custom" && ( + <> + {filteredCommands.length === 0 && ( +
+ + + {searchQuery ? 'No commands found' : 'No custom commands available'} + + {!searchQuery && ( +

+ Create commands in .claude/commands/ or ~/.claude/commands/ +

+ )}
- ))} -
+ )} + + {filteredCommands.length > 0 && ( +
+ {/* If no grouping needed, show flat list */} + {Object.keys(groupedCommands).length === 1 ? ( +
+ {filteredCommands.map((command, index) => { + const Icon = getCommandIcon(command); + const isSelected = index === selectedIndex; + + return ( + + ); + })} +
+ ) : ( + // Show grouped by scope/namespace +
+ {Object.entries(groupedCommands).map(([groupKey, groupCommands]) => ( +
+

+ {groupKey.startsWith("User Commands") && } + {groupKey.startsWith("Project Commands") && } + {groupKey} +

+ +
+ {groupCommands.map((command) => { + const Icon = getCommandIcon(command); + const globalIndex = filteredCommands.indexOf(command); + const isSelected = globalIndex === selectedIndex; + + return ( + + ); + })} +
+
+ ))} +
+ )} +
+ )} + )} -
+ )}