Skip to content

Commit 46ae66c

Browse files
committed
feat: simplify slash commands popover and add settings navigation
- Added gear icon to slash commands list for settings access - Created SlashCommandItemSimple component for cleaner popover UI - Updated SlashCommandsList to focus on command selection - Added translation for manage commands tooltip
1 parent 0430998 commit 46ae66c

File tree

3 files changed

+58
-133
lines changed

3 files changed

+58
-133
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from "react"
2+
3+
import type { Command } from "@roo/ExtensionMessage"
4+
5+
interface SlashCommandItemSimpleProps {
6+
command: Command
7+
onClick?: (command: Command) => void
8+
}
9+
10+
export const SlashCommandItemSimple: React.FC<SlashCommandItemSimpleProps> = ({ command, onClick }) => {
11+
return (
12+
<div
13+
className="px-4 py-2 text-sm flex items-center hover:bg-vscode-list-hoverBackground cursor-pointer"
14+
onClick={() => onClick?.(command)}>
15+
{/* Command name */}
16+
<div className="flex-1 min-w-0">
17+
<div>
18+
<span className="truncate text-vscode-foreground">/{command.name}</span>
19+
{command.description && (
20+
<div className="text-xs text-vscode-descriptionForeground truncate mt-0.5">
21+
{command.description}
22+
</div>
23+
)}
24+
</div>
25+
</div>
26+
</div>
27+
)
28+
}
Lines changed: 29 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,34 @@
1-
import React, { useState } from "react"
2-
import { Plus, Globe, Folder, Settings } from "lucide-react"
1+
import React from "react"
2+
import { Globe, Folder, Settings } from "lucide-react"
33

44
import type { Command } from "@roo/ExtensionMessage"
55

66
import { useAppTranslation } from "@/i18n/TranslationContext"
77
import { useExtensionState } from "@/context/ExtensionStateContext"
8-
import {
9-
AlertDialog,
10-
AlertDialogAction,
11-
AlertDialogCancel,
12-
AlertDialogContent,
13-
AlertDialogDescription,
14-
AlertDialogFooter,
15-
AlertDialogHeader,
16-
AlertDialogTitle,
17-
Button,
18-
} from "@/components/ui"
8+
import { Button, StandardTooltip } from "@/components/ui"
199
import { vscode } from "@/utils/vscode"
2010

21-
import { SlashCommandItem } from "./SlashCommandItem"
11+
import { SlashCommandItemSimple } from "./SlashCommandItemSimple"
2212

2313
interface SlashCommandsListProps {
2414
commands: Command[]
2515
onRefresh: () => void
2616
}
2717

28-
export const SlashCommandsList: React.FC<SlashCommandsListProps> = ({ commands, onRefresh }) => {
18+
export const SlashCommandsList: React.FC<SlashCommandsListProps> = ({ commands }) => {
2919
const { t } = useAppTranslation()
3020
const { cwd } = useExtensionState()
31-
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)
32-
const [commandToDelete, setCommandToDelete] = useState<Command | null>(null)
33-
const [globalNewName, setGlobalNewName] = useState("")
34-
const [workspaceNewName, setWorkspaceNewName] = useState("")
3521

3622
// Check if we're in a workspace/project
3723
const hasWorkspace = Boolean(cwd)
3824

39-
const handleDeleteClick = (command: Command) => {
40-
setCommandToDelete(command)
41-
setDeleteDialogOpen(true)
42-
}
43-
44-
const handleDeleteConfirm = () => {
45-
if (commandToDelete) {
46-
vscode.postMessage({
47-
type: "deleteCommand",
48-
text: commandToDelete.name,
49-
values: { source: commandToDelete.source },
50-
})
51-
setDeleteDialogOpen(false)
52-
setCommandToDelete(null)
53-
// Refresh the commands list after deletion
54-
setTimeout(onRefresh, 100)
55-
}
56-
}
57-
58-
const handleDeleteCancel = () => {
59-
setDeleteDialogOpen(false)
60-
setCommandToDelete(null)
61-
}
62-
63-
const handleCreateCommand = (source: "global" | "project", name: string) => {
64-
if (!name.trim()) return
65-
66-
// Append .md if not already present
67-
const fileName = name.trim().endsWith(".md") ? name.trim() : `${name.trim()}.md`
68-
25+
const handleOpenSettings = () => {
26+
// Send message to open settings with the slashCommands tab
6927
vscode.postMessage({
70-
type: "createCommand",
71-
text: fileName,
72-
values: { source },
28+
type: "switchTab",
29+
tab: "settings",
30+
values: { section: "slashCommands" },
7331
})
74-
75-
// Clear the input and refresh
76-
if (source === "global") {
77-
setGlobalNewName("")
78-
} else {
79-
setWorkspaceNewName("")
80-
}
81-
setTimeout(onRefresh, 500)
8232
}
8333

8434
const handleCommandClick = (command: Command) => {
@@ -96,6 +46,22 @@ export const SlashCommandsList: React.FC<SlashCommandsListProps> = ({ commands,
9646

9747
return (
9848
<>
49+
{/* Header with settings button */}
50+
<div className="flex items-center justify-between px-3 py-2 border-b border-vscode-dropdown-border">
51+
<span className="text-xs font-medium text-vscode-descriptionForeground">
52+
{t("chat:slashCommands.title")}
53+
</span>
54+
<StandardTooltip content={t("chat:slashCommands.manageCommands")}>
55+
<Button
56+
variant="ghost"
57+
size="icon"
58+
onClick={handleOpenSettings}
59+
className="h-6 w-6 p-0 opacity-60 hover:opacity-100">
60+
<Settings className="w-3.5 h-3.5" />
61+
</Button>
62+
</StandardTooltip>
63+
</div>
64+
9965
{/* Commands list */}
10066
<div className="max-h-[300px] overflow-y-auto">
10167
<div className="py-1">
@@ -105,37 +71,12 @@ export const SlashCommandsList: React.FC<SlashCommandsListProps> = ({ commands,
10571
{t("chat:slashCommands.globalCommands")}
10672
</div>
10773
{globalCommands.map((command) => (
108-
<SlashCommandItem
74+
<SlashCommandItemSimple
10975
key={`global-${command.name}`}
11076
command={command}
111-
onDelete={handleDeleteClick}
11277
onClick={handleCommandClick}
11378
/>
11479
))}
115-
{/* New global command input */}
116-
<div className="px-4 py-2 flex items-center gap-2 hover:bg-vscode-list-hoverBackground">
117-
<input
118-
type="text"
119-
value={globalNewName}
120-
onChange={(e) => setGlobalNewName(e.target.value)}
121-
placeholder={t("chat:slashCommands.newGlobalCommandPlaceholder")}
122-
className="flex-1 bg-transparent text-vscode-input-foreground placeholder-vscode-input-placeholderForeground border-none outline-none focus:outline-0 text-sm"
123-
tabIndex={-1}
124-
onKeyDown={(e) => {
125-
if (e.key === "Enter") {
126-
handleCreateCommand("global", globalNewName)
127-
}
128-
}}
129-
/>
130-
<Button
131-
variant="ghost"
132-
size="icon"
133-
onClick={() => handleCreateCommand("global", globalNewName)}
134-
disabled={!globalNewName.trim()}
135-
className="size-6 flex items-center justify-center opacity-60 hover:opacity-100">
136-
<Plus className="w-4 h-4" />
137-
</Button>
138-
</div>
13980

14081
{/* Workspace Commands Section - Only show if in a workspace */}
14182
{hasWorkspace && (
@@ -145,37 +86,12 @@ export const SlashCommandsList: React.FC<SlashCommandsListProps> = ({ commands,
14586
{t("chat:slashCommands.workspaceCommands")}
14687
</div>
14788
{projectCommands.map((command) => (
148-
<SlashCommandItem
89+
<SlashCommandItemSimple
14990
key={`project-${command.name}`}
15091
command={command}
151-
onDelete={handleDeleteClick}
15292
onClick={handleCommandClick}
15393
/>
15494
))}
155-
{/* New workspace command input */}
156-
<div className="px-4 py-2 flex items-center gap-2 hover:bg-vscode-list-hoverBackground">
157-
<input
158-
type="text"
159-
value={workspaceNewName}
160-
onChange={(e) => setWorkspaceNewName(e.target.value)}
161-
placeholder={t("chat:slashCommands.newWorkspaceCommandPlaceholder")}
162-
className="flex-1 bg-transparent text-vscode-input-foreground placeholder-vscode-input-placeholderForeground border-none outline-none focus:outline-0 text-sm"
163-
tabIndex={-1}
164-
onKeyDown={(e) => {
165-
if (e.key === "Enter") {
166-
handleCreateCommand("project", workspaceNewName)
167-
}
168-
}}
169-
/>
170-
<Button
171-
variant="ghost"
172-
size="icon"
173-
onClick={() => handleCreateCommand("project", workspaceNewName)}
174-
disabled={!workspaceNewName.trim()}
175-
className="size-6 flex items-center justify-center opacity-60 hover:opacity-100">
176-
<Plus className="w-4 h-4" />
177-
</Button>
178-
</div>
17995
</>
18096
)}
18197

@@ -187,36 +103,16 @@ export const SlashCommandsList: React.FC<SlashCommandsListProps> = ({ commands,
187103
{t("chat:slashCommands.builtInCommands")}
188104
</div>
189105
{builtInCommands.map((command) => (
190-
<SlashCommandItem
106+
<SlashCommandItemSimple
191107
key={`built-in-${command.name}`}
192108
command={command}
193-
onDelete={handleDeleteClick}
194109
onClick={handleCommandClick}
195110
/>
196111
))}
197112
</>
198113
)}
199114
</div>
200115
</div>
201-
202-
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
203-
<AlertDialogContent>
204-
<AlertDialogHeader>
205-
<AlertDialogTitle>{t("chat:slashCommands.deleteDialog.title")}</AlertDialogTitle>
206-
<AlertDialogDescription>
207-
{t("chat:slashCommands.deleteDialog.description", { name: commandToDelete?.name })}
208-
</AlertDialogDescription>
209-
</AlertDialogHeader>
210-
<AlertDialogFooter>
211-
<AlertDialogCancel onClick={handleDeleteCancel}>
212-
{t("chat:slashCommands.deleteDialog.cancel")}
213-
</AlertDialogCancel>
214-
<AlertDialogAction onClick={handleDeleteConfirm}>
215-
{t("chat:slashCommands.deleteDialog.confirm")}
216-
</AlertDialogAction>
217-
</AlertDialogFooter>
218-
</AlertDialogContent>
219-
</AlertDialog>
220116
</>
221117
)
222118
}

webview-ui/src/i18n/locales/en/chat.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@
369369
"tooltip": "Manage slash commands",
370370
"title": "Slash Commands",
371371
"description": "Use built-in slash commands or create custom ones for quick access to frequently used prompts and workflows. <DocsLink>Docs</DocsLink>",
372+
"manageCommands": "Manage slash commands in settings",
372373
"builtInCommands": "Built-in Commands",
373374
"globalCommands": "Global Commands",
374375
"workspaceCommands": "Workspace Commands",

0 commit comments

Comments
 (0)