Browse Source

refactor: general UI improvements (#2987)

Dicha Zelianivan Arkana 8 months ago
parent
commit
883cb927a3

+ 276 - 393
webview-ui/src/components/prompts/PromptsView.tsx

@@ -1,14 +1,6 @@
-import React, { useState, useEffect, useMemo, useCallback } from "react"
+import React, { useState, useEffect, useMemo, useCallback, useRef } from "react"
 import { Button } from "@/components/ui/button"
-import {
-	VSCodeTextArea,
-	VSCodeDropdown,
-	VSCodeOption,
-	VSCodeTextField,
-	VSCodeCheckbox,
-	VSCodeRadioGroup,
-	VSCodeRadio,
-} from "@vscode/webview-ui-toolkit/react"
+import { VSCodeCheckbox, VSCodeRadioGroup, VSCodeRadio } from "@vscode/webview-ui-toolkit/react"
 
 import { useExtensionState } from "@src/context/ExtensionStateContext"
 import {
@@ -29,6 +21,25 @@ import { Tab, TabContent, TabHeader } from "../common/Tab"
 import i18next from "i18next"
 import { useAppTranslation } from "@src/i18n/TranslationContext"
 import { Trans } from "react-i18next"
+import {
+	Select,
+	SelectContent,
+	SelectItem,
+	SelectTrigger,
+	SelectValue,
+	Textarea,
+	Popover,
+	PopoverContent,
+	PopoverTrigger,
+	Command,
+	CommandInput,
+	CommandList,
+	CommandEmpty,
+	CommandItem,
+	CommandGroup,
+	Input,
+} from "../ui"
+import { ChevronsUpDown, X } from "lucide-react"
 
 // Get all available groups that should show in prompts view
 const availableGroups = (Object.keys(TOOL_GROUPS) as ToolGroup[]).filter((group) => !TOOL_GROUPS[group].alwaysAvailable)
@@ -78,9 +89,14 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 	const [isToolsEditMode, setIsToolsEditMode] = useState(false)
 	const [showConfigMenu, setShowConfigMenu] = useState(false)
 	const [isCreateModeDialogOpen, setIsCreateModeDialogOpen] = useState(false)
-	const [activeSupportTab, setActiveSupportTab] = useState<SupportPromptType>("ENHANCE")
+	const [activeSupportOption, setActiveSupportOption] = useState<SupportPromptType>("ENHANCE")
 	const [isSystemPromptDisclosureOpen, setIsSystemPromptDisclosureOpen] = useState(false)
 
+	// State for mode selection popover and search
+	const [open, setOpen] = useState(false)
+	const [searchValue, setSearchValue] = useState("")
+	const searchInputRef = useRef<HTMLInputElement>(null)
+
 	// Direct update functions
 	const updateAgentPrompt = useCallback(
 		(mode: Mode, promptData: PromptComponent) => {
@@ -144,9 +160,24 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 			// Exit tools edit mode when switching modes
 			setIsToolsEditMode(false)
 		},
-		[visualMode, switchMode, setIsToolsEditMode],
+		[visualMode, switchMode],
 	)
 
+	// Handler for popover open state change
+	const onOpenChange = useCallback((open: boolean) => {
+		setOpen(open)
+		// Reset search when closing the popover
+		if (!open) {
+			setTimeout(() => setSearchValue(""), 100)
+		}
+	}, [])
+
+	// Handler for clearing search input
+	const onClearSearch = useCallback(() => {
+		setSearchValue("")
+		searchInputRef.current?.focus()
+	}, [])
+
 	// Helper function to get current mode's config
 	const getCurrentMode = useCallback((): ModeConfig | undefined => {
 		const findMode = (m: ModeConfig): boolean => m.slug === visualMode
@@ -480,45 +511,95 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 						{t("prompts:modes.createModeHelpText")}
 					</div>
 
-					<div className="flex gap-2 items-center mb-3 flex-wrap py-1">
-						{modes.map((modeConfig) => {
-							const isActive = visualMode === modeConfig.slug
-							return (
-								<button
-									key={modeConfig.slug}
-									data-testid={`${modeConfig.slug}-tab`}
-									data-active={isActive ? "true" : "false"}
-									onClick={() => handleModeSwitch(modeConfig)}
-									className={`px-2 py-1 border-none rounded cursor-pointer font-bold ${
-										isActive
-											? "bg-vscode-button-background text-vscode-button-foreground opacity-100"
-											: "bg-transparent text-vscode-foreground opacity-80"
-									}`}>
-									{modeConfig.name}
-								</button>
-							)
-						})}
+					<div className="flex items-center gap-1 mb-3">
+						<Popover open={open} onOpenChange={onOpenChange}>
+							<PopoverTrigger asChild>
+								<Button
+									variant="combobox"
+									role="combobox"
+									aria-expanded={open}
+									className="grow justify-between"
+									data-testid="mode-select-trigger">
+									<div>{getCurrentMode()?.name || t("prompts:modes.selectMode")}</div>
+									<ChevronsUpDown className="opacity-50" />
+								</Button>
+							</PopoverTrigger>
+							<PopoverContent className="p-0 w-[var(--radix-popover-trigger-width)]">
+								<Command>
+									<div className="relative">
+										<CommandInput
+											ref={searchInputRef}
+											value={searchValue}
+											onValueChange={setSearchValue}
+											placeholder={t("prompts:modes.selectMode")}
+											className="h-9 mr-4"
+											data-testid="mode-search-input"
+										/>
+										{searchValue.length > 0 && (
+											<div className="absolute right-2 top-0 bottom-0 flex items-center justify-center">
+												<X
+													className="text-vscode-input-foreground opacity-50 hover:opacity-100 size-4 p-0.5 cursor-pointer"
+													onClick={onClearSearch}
+												/>
+											</div>
+										)}
+									</div>
+									<CommandList>
+										<CommandEmpty>
+											{searchValue && (
+												<div className="py-2 px-1 text-sm">
+													{t("prompts:modes.noMatchFound")}
+												</div>
+											)}
+										</CommandEmpty>
+										<CommandGroup>
+											{modes
+												.filter((modeConfig) =>
+													searchValue
+														? modeConfig.name
+																.toLowerCase()
+																.includes(searchValue.toLowerCase())
+														: true,
+												)
+												.map((modeConfig) => (
+													<CommandItem
+														key={modeConfig.slug}
+														value={modeConfig.slug}
+														onSelect={() => {
+															handleModeSwitch(modeConfig)
+															setOpen(false)
+														}}
+														data-testid={`mode-option-${modeConfig.slug}`}>
+														<div className="flex items-center justify-between w-full">
+															<span>{modeConfig.name}</span>
+															<span className="text-foreground">{modeConfig.slug}</span>
+														</div>
+													</CommandItem>
+												))}
+										</CommandGroup>
+									</CommandList>
+								</Command>
+							</PopoverContent>
+						</Popover>
 					</div>
 				</div>
 
-				<div style={{ marginBottom: "20px" }}>
+				<div className="mb-5">
 					{/* Only show name and delete for custom modes */}
 					{visualMode && findModeBySlug(visualMode, customModes) && (
 						<div className="flex gap-3 mb-4">
 							<div className="flex-1">
 								<div className="font-bold mb-1">{t("prompts:createModeDialog.name.label")}</div>
 								<div className="flex gap-2">
-									<VSCodeTextField
+									<Input
+										type="text"
 										value={getModeProperty(findModeBySlug(visualMode, customModes), "name") ?? ""}
-										onChange={(e: Event | React.FormEvent<HTMLElement>) => {
-											const target =
-												(e as CustomEvent)?.detail?.target ||
-												((e as any).target as HTMLInputElement)
+										onChange={(e) => {
 											const customMode = findModeBySlug(visualMode, customModes)
 											if (customMode) {
 												updateCustomMode(visualMode, {
 													...customMode,
-													name: target.value,
+													name: e.target.value,
 													source: customMode.source || "global",
 												})
 											}
@@ -541,7 +622,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 							</div>
 						</div>
 					)}
-					<div style={{ marginBottom: "16px" }}>
+					<div className="mb-4">
 						<div className="flex justify-between items-center mb-1">
 							<div className="font-bold">{t("prompts:roleDefinition.title")}</div>
 							{!findModeBySlug(visualMode, customModes) && (
@@ -563,7 +644,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 						<div className="text-sm text-vscode-descriptionForeground mb-2">
 							{t("prompts:roleDefinition.description")}
 						</div>
-						<VSCodeTextArea
+						<Textarea
 							value={(() => {
 								const customMode = findModeBySlug(visualMode, customModes)
 								const prompt = customModePrompts?.[visualMode] as PromptComponent
@@ -575,7 +656,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 							})()}
 							onChange={(e) => {
 								const value =
-									(e as CustomEvent)?.detail?.target?.value ||
+									(e as unknown as CustomEvent)?.detail?.target?.value ||
 									((e as any).target as HTMLTextAreaElement).value
 								const customMode = findModeBySlug(visualMode, customModes)
 								if (customMode) {
@@ -592,35 +673,35 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 									})
 								}
 							}}
+							className="resize-y w-full"
 							rows={4}
-							resize="vertical"
-							style={{ width: "100%" }}
 							data-testid={`${getCurrentMode()?.slug || "code"}-prompt-textarea`}
 						/>
 					</div>
 					{/* Mode settings */}
 					<>
-						<div style={{ marginBottom: "12px" }}>
-							<div style={{ fontWeight: "bold", marginBottom: "4px" }}>
-								{t("prompts:apiConfiguration.title")}
-							</div>
-							<div style={{ marginBottom: "8px" }}>
-								<VSCodeDropdown
-									value={currentApiConfigName || ""}
-									onChange={(e: any) => {
-										const value = e.detail?.target?.value || e.target?.value
+						<div className="mb-3">
+							<div className="font-bold mb-1">{t("prompts:apiConfiguration.title")}</div>
+							<div className="mb-2">
+								<Select
+									value={currentApiConfigName}
+									onValueChange={(value) => {
 										vscode.postMessage({
 											type: "loadApiConfiguration",
 											text: value,
 										})
-									}}
-									className="w-full">
-									{(listApiConfigMeta || []).map((config) => (
-										<VSCodeOption key={config.id} value={config.name}>
-											{config.name}
-										</VSCodeOption>
-									))}
-								</VSCodeDropdown>
+									}}>
+									<SelectTrigger className="w-full">
+										<SelectValue placeholder={t("settings:common.select")} />
+									</SelectTrigger>
+									<SelectContent>
+										{(listApiConfigMeta || []).map((config) => (
+											<SelectItem key={config.id} value={config.name}>
+												{config.name}
+											</SelectItem>
+										))}
+									</SelectContent>
+								</Select>
 								<div className="text-xs mt-1.5 text-vscode-descriptionForeground">
 									{t("prompts:apiConfiguration.select")}
 								</div>
@@ -721,15 +802,9 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 					</>
 
 					{/* Role definition for both built-in and custom modes */}
-					<div style={{ marginBottom: "8px" }}>
-						<div
-							style={{
-								display: "flex",
-								justifyContent: "space-between",
-								alignItems: "center",
-								marginBottom: "4px",
-							}}>
-							<div style={{ fontWeight: "bold" }}>{t("prompts:customInstructions.title")}</div>
+					<div className="mb-2">
+						<div className="flex justify-between items-center mb-1">
+							<div className="font-bold">{t("prompts:customInstructions.title")}</div>
 							{!findModeBySlug(visualMode, customModes) && (
 								<Button
 									variant="ghost"
@@ -746,17 +821,12 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 								</Button>
 							)}
 						</div>
-						<div
-							style={{
-								fontSize: "13px",
-								color: "var(--vscode-descriptionForeground)",
-								marginBottom: "8px",
-							}}>
+						<div className="text-[13px] text-vscode-descriptionForeground mb-2">
 							{t("prompts:customInstructions.description", {
 								modeName: getCurrentMode()?.name || "Code",
 							})}
 						</div>
-						<VSCodeTextArea
+						<Textarea
 							value={(() => {
 								const customMode = findModeBySlug(visualMode, customModes)
 								const prompt = customModePrompts?.[visualMode] as PromptComponent
@@ -768,7 +838,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 							})()}
 							onChange={(e) => {
 								const value =
-									(e as CustomEvent)?.detail?.target?.value ||
+									(e as unknown as CustomEvent)?.detail?.target?.value ||
 									((e as any).target as HTMLTextAreaElement).value
 								const customMode = findModeBySlug(visualMode, customModes)
 								if (customMode) {
@@ -788,16 +858,10 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 								}
 							}}
 							rows={4}
-							resize="vertical"
-							style={{ width: "100%" }}
+							className="w-full resize-y"
 							data-testid={`${getCurrentMode()?.slug || "code"}-custom-instructions-textarea`}
 						/>
-						<div
-							style={{
-								fontSize: "12px",
-								color: "var(--vscode-descriptionForeground)",
-								marginTop: "5px",
-							}}>
+						<div className="text-xs text-vscode-descriptionForeground mt-1.5">
 							<Trans
 								i18nKey="prompts:customInstructions.loadFromFile"
 								values={{
@@ -807,11 +871,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 								components={{
 									span: (
 										<span
-											style={{
-												color: "var(--vscode-textLink-foreground)",
-												cursor: "pointer",
-												textDecoration: "underline",
-											}}
+											className="text-vscode-textLink-foreground cursor-pointer underline"
 											onClick={() => {
 												const currentMode = getCurrentMode()
 												if (!currentMode) return
@@ -834,13 +894,8 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 					</div>
 				</div>
 
-				<div
-					style={{
-						paddingBottom: "40px",
-						marginBottom: "20px",
-						borderBottom: "1px solid var(--vscode-input-border)",
-					}}>
-					<div style={{ display: "flex", gap: "8px" }}>
+				<div className="pb-4 border-b border-vscode-input-border">
+					<div className="flex gap-2">
 						<Button
 							variant="default"
 							onClick={() => {
@@ -874,7 +929,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 					</div>
 
 					{/* Custom System Prompt Disclosure */}
-					<div className="mt-12">
+					<div className="mt-4">
 						<button
 							onClick={() => setIsSystemPromptDisclosureOpen(!isSystemPromptDisclosureOpen)}
 							className="flex items-center text-xs text-vscode-foreground hover:text-vscode-textLink-foreground focus:outline-none"
@@ -918,18 +973,18 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 				</div>
 
 				<div className="pb-5 border-b border-vscode-input-border">
-					<h3 style={{ color: "var(--vscode-foreground)", marginBottom: "12px" }}>
-						{t("prompts:globalCustomInstructions.title")}
-					</h3>
+					<h3 className="text-vscode-foreground mb-3">{t("prompts:globalCustomInstructions.title")}</h3>
 
 					<div className="text-sm text-vscode-descriptionForeground mb-2">
-						{t("prompts:globalCustomInstructions.description", { language: i18next.language })}
+						{t("prompts:globalCustomInstructions.description", {
+							language: i18next.language,
+						})}
 					</div>
-					<VSCodeTextArea
-						value={customInstructions ?? ""}
+					<Textarea
+						value={customInstructions}
 						onChange={(e) => {
 							const value =
-								(e as CustomEvent)?.detail?.target?.value ||
+								(e as unknown as CustomEvent)?.detail?.target?.value ||
 								((e as any).target as HTMLTextAreaElement).value
 							setCustomInstructions(value || undefined)
 							vscode.postMessage({
@@ -938,21 +993,16 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 							})
 						}}
 						rows={4}
-						resize="vertical"
-						className="w-full"
+						className="w-full resize-y"
 						data-testid="global-custom-instructions-textarea"
 					/>
-					<div className="text-xs text-vscode-descriptionForeground mt-1.5 mb-10">
+					<div className="text-xs text-vscode-descriptionForeground mt-1.5">
 						<Trans
 							i18nKey="prompts:globalCustomInstructions.loadFromFile"
 							components={{
 								span: (
 									<span
-										style={{
-											color: "var(--vscode-textLink-foreground)",
-											cursor: "pointer",
-											textDecoration: "underline",
-										}}
+										className="text-vscode-textLink-foreground cursor-pointer underline"
 										onClick={() =>
 											vscode.postMessage({
 												type: "openFile",
@@ -970,156 +1020,113 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 					</div>
 				</div>
 
-				<div
-					style={{
-						marginTop: "20px",
-						paddingBottom: "60px",
-						borderBottom: "1px solid var(--vscode-input-border)",
-					}}>
-					<h3 style={{ color: "var(--vscode-foreground)", marginBottom: "12px" }}>
-						{t("prompts:supportPrompts.title")}
-					</h3>
-					<div
-						style={{
-							display: "flex",
-							gap: "8px",
-							alignItems: "center",
-							marginBottom: "12px",
-							flexWrap: "wrap",
-							padding: "4px 0",
-						}}>
-						{Object.keys(supportPrompt.default).map((type) => (
-							<button
-								key={type}
-								data-testid={`${type}-tab`}
-								data-active={activeSupportTab === type ? "true" : "false"}
-								onClick={() => setActiveSupportTab(type as SupportPromptType)}
-								style={{
-									padding: "4px 8px",
-									border: "none",
-									background: activeSupportTab === type ? "var(--vscode-button-background)" : "none",
-									color:
-										activeSupportTab === type
-											? "var(--vscode-button-foreground)"
-											: "var(--vscode-foreground)",
-									cursor: "pointer",
-									opacity: activeSupportTab === type ? 1 : 0.8,
-									borderRadius: "3px",
-									fontWeight: "bold",
-								}}>
-								{t(`prompts:supportPrompts.types.${type}.label`)}
-							</button>
-						))}
+				<div className="mt-5 pb-15 border-b border-vscode-input-border">
+					<h3 className="text-vscode-foreground mb-3">{t("prompts:supportPrompts.title")}</h3>
+					<div className="flex gap-4 items-center flex-wrap py-1">
+						<Select
+							value={activeSupportOption}
+							onValueChange={(type) => setActiveSupportOption(type as SupportPromptType)}>
+							<SelectTrigger className="w-full" data-testid="support-prompt-select-trigger">
+								<SelectValue placeholder={t("settings:common.select")} />
+							</SelectTrigger>
+							<SelectContent>
+								{Object.keys(supportPrompt.default).map((type) => (
+									<SelectItem key={type} value={type} data-testid={`${type}-option`}>
+										{t(`prompts:supportPrompts.types.${type}.label`)}
+									</SelectItem>
+								))}
+							</SelectContent>
+						</Select>
 					</div>
 
 					{/* Support prompt description */}
-					<div
-						style={{
-							fontSize: "13px",
-							color: "var(--vscode-descriptionForeground)",
-							margin: "8px 0 16px",
-						}}>
-						{t(`prompts:supportPrompts.types.${activeSupportTab}.description`)}
+					<div className="text-[13px] text-vscode-descriptionForeground my-2 mb-4">
+						{t(`prompts:supportPrompts.types.${activeSupportOption}.description`)}
 					</div>
 
-					{/* Show active tab content */}
-					<div key={activeSupportTab}>
-						<div
-							style={{
-								display: "flex",
-								justifyContent: "space-between",
-								alignItems: "center",
-								marginBottom: "4px",
-							}}>
-							<div style={{ fontWeight: "bold" }}>{t("prompts:supportPrompts.prompt")}</div>
+					<div key={activeSupportOption}>
+						<div className="flex justify-between items-center mb-1">
+							<div className="font-bold">{t("prompts:supportPrompts.prompt")}</div>
 							<Button
 								variant="ghost"
 								size="icon"
-								onClick={() => handleSupportReset(activeSupportTab)}
-								title={t("prompts:supportPrompts.resetPrompt", { promptType: activeSupportTab })}>
+								onClick={() => handleSupportReset(activeSupportOption)}
+								title={t("prompts:supportPrompts.resetPrompt", {
+									promptType: activeSupportOption,
+								})}>
 								<span className="codicon codicon-discard"></span>
 							</Button>
 						</div>
 
-						<VSCodeTextArea
-							value={getSupportPromptValue(activeSupportTab)}
+						<Textarea
+							value={getSupportPromptValue(activeSupportOption)}
 							onChange={(e) => {
 								const value =
-									(e as CustomEvent)?.detail?.target?.value ||
+									(e as unknown as CustomEvent)?.detail?.target?.value ||
 									((e as any).target as HTMLTextAreaElement).value
 								const trimmedValue = value.trim()
-								updateSupportPrompt(activeSupportTab, trimmedValue || undefined)
+								updateSupportPrompt(activeSupportOption, trimmedValue || undefined)
 							}}
 							rows={6}
-							resize="vertical"
-							style={{ width: "100%" }}
+							className="resize-y w-full"
 						/>
 
-						{activeSupportTab === "ENHANCE" && (
+						{activeSupportOption === "ENHANCE" && (
 							<>
 								<div>
-									<div
-										style={{
-											color: "var(--vscode-foreground)",
-											fontSize: "13px",
-											marginBottom: "20px",
-											marginTop: "5px",
-										}}></div>
-									<div style={{ marginBottom: "12px" }}>
-										<div style={{ marginBottom: "8px" }}>
-											<div style={{ fontWeight: "bold", marginBottom: "4px" }}>
+									<div className="text-vscode-foreground text-[13px] mb-5 mt-1.5"></div>
+									<div className="mb-3">
+										<div className="mb-2">
+											<div className="font-bold mb-1">
 												{t("prompts:supportPrompts.enhance.apiConfiguration")}
 											</div>
-											<div
-												style={{
-													fontSize: "13px",
-													color: "var(--vscode-descriptionForeground)",
-												}}>
+											<div className="text-[13px] text-vscode-descriptionForeground">
 												{t("prompts:supportPrompts.enhance.apiConfigDescription")}
 											</div>
 										</div>
-										<VSCodeDropdown
-											value={enhancementApiConfigId || ""}
-											data-testid="api-config-dropdown"
-											onChange={(e: any) => {
-												const value = e.detail?.target?.value || e.target?.value
-												setEnhancementApiConfigId(value)
+										<Select
+											value={enhancementApiConfigId || "-"}
+											onValueChange={(value) => {
+												// normalise to empty string for empty value
+												// because we can't use it directly for the select element
+												setEnhancementApiConfigId(value === "-" ? "" : value)
 												vscode.postMessage({
 													type: "enhancementApiConfigId",
 													text: value,
 												})
-											}}
-											style={{ width: "300px" }}>
-											<VSCodeOption value="">
-												{t("prompts:supportPrompts.enhance.useCurrentConfig")}
-											</VSCodeOption>
-											{(listApiConfigMeta || []).map((config) => (
-												<VSCodeOption key={config.id} value={config.id}>
-													{config.name}
-												</VSCodeOption>
-											))}
-										</VSCodeDropdown>
+											}}>
+											<SelectTrigger data-testid="api-config-select" className="w-full">
+												<SelectValue
+													placeholder={t("prompts:supportPrompts.enhance.useCurrentConfig")}
+												/>
+											</SelectTrigger>
+											<SelectContent>
+												<SelectItem value="-">
+													{t("prompts:supportPrompts.enhance.useCurrentConfig")}
+												</SelectItem>
+												{(listApiConfigMeta || []).map((config) => (
+													<SelectItem
+														key={config.id}
+														value={config.id}
+														data-testid={`${config.id}-option`}>
+														{config.name}
+													</SelectItem>
+												))}
+											</SelectContent>
+										</Select>
 									</div>
 								</div>
 
-								<div style={{ marginTop: "12px" }}>
-									<VSCodeTextArea
+								<div className="mt-4">
+									<Textarea
 										value={testPrompt}
 										onChange={(e) => setTestPrompt((e.target as HTMLTextAreaElement).value)}
 										placeholder={t("prompts:supportPrompts.enhance.testPromptPlaceholder")}
 										rows={3}
-										resize="vertical"
-										style={{ width: "100%" }}
+										className="w-full resize-y"
 										data-testid="test-prompt-textarea"
 									/>
-									<div
-										style={{
-											marginTop: "8px",
-											display: "flex",
-											justifyContent: "flex-start",
-											alignItems: "center",
-											gap: 8,
-										}}>
+									<div className="mt-2 flex justify-start items-center gap-2">
 										<Button
 											variant="default"
 											onClick={handleTestEnhancement}
@@ -1135,92 +1142,50 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 			</TabContent>
 
 			{isCreateModeDialogOpen && (
-				<div
-					style={{
-						position: "fixed",
-						inset: 0,
-						display: "flex",
-						justifyContent: "flex-end",
-						backgroundColor: "rgba(0, 0, 0, 0.5)",
-						zIndex: 1000,
-					}}>
-					<div
-						style={{
-							width: "calc(100vw - 100px)",
-							height: "100%",
-							backgroundColor: "var(--vscode-editor-background)",
-							boxShadow: "-2px 0 5px rgba(0, 0, 0, 0.2)",
-							display: "flex",
-							flexDirection: "column",
-							position: "relative",
-						}}>
-						<div
-							style={{
-								flex: 1,
-								padding: "20px",
-								overflowY: "auto",
-								minHeight: 0,
-							}}>
+				<div className="fixed inset-0 flex justify-end bg-black/50 z-[1000]">
+					<div className="w-[calc(100vw-100px)] h-full bg-vscode-editor-background shadow-md flex flex-col relative">
+						<div className="flex-1 p-5 overflow-y-auto min-h-0">
 							<Button
 								variant="ghost"
 								size="icon"
 								onClick={() => setIsCreateModeDialogOpen(false)}
-								style={{
-									position: "absolute",
-									top: "20px",
-									right: "20px",
-								}}>
+								className="absolute top-5 right-5">
 								<span className="codicon codicon-close"></span>
 							</Button>
-							<h2 style={{ margin: "0 0 16px" }}>{t("prompts:createModeDialog.title")}</h2>
-							<div style={{ marginBottom: "16px" }}>
-								<div style={{ fontWeight: "bold", marginBottom: "4px" }}>
-									{t("prompts:createModeDialog.name.label")}
-								</div>
-								<VSCodeTextField
+							<h2 className="mb-4">{t("prompts:createModeDialog.title")}</h2>
+							<div className="mb-4">
+								<div className="font-bold mb-1">{t("prompts:createModeDialog.name.label")}</div>
+								<Input
+									type="text"
 									value={newModeName}
-									onChange={(e: Event | React.FormEvent<HTMLElement>) => {
-										const target =
-											(e as CustomEvent)?.detail?.target ||
-											((e as any).target as HTMLInputElement)
-										handleNameChange(target.value)
+									onChange={(e) => {
+										handleNameChange(e.target.value)
 									}}
-									style={{ width: "100%" }}
+									className="w-full"
 								/>
 								{nameError && (
 									<div className="text-xs text-vscode-errorForeground mt-1">{nameError}</div>
 								)}
 							</div>
-							<div style={{ marginBottom: "16px" }}>
-								<div style={{ fontWeight: "bold", marginBottom: "4px" }}>
-									{t("prompts:createModeDialog.slug.label")}
-								</div>
-								<VSCodeTextField
+							<div className="mb-4">
+								<div className="font-bold mb-1">{t("prompts:createModeDialog.slug.label")}</div>
+								<Input
+									type="text"
 									value={newModeSlug}
-									onChange={(e: Event | React.FormEvent<HTMLElement>) => {
-										const target =
-											(e as CustomEvent)?.detail?.target ||
-											((e as any).target as HTMLInputElement)
-										setNewModeSlug(target.value)
+									onChange={(e) => {
+										setNewModeSlug(e.target.value)
 									}}
-									style={{ width: "100%" }}
+									className="w-full"
 								/>
-								<div
-									style={{
-										fontSize: "12px",
-										color: "var(--vscode-descriptionForeground)",
-										marginTop: "4px",
-									}}>
+								<div className="text-xs text-vscode-descriptionForeground mt-1">
 									{t("prompts:createModeDialog.slug.description")}
 								</div>
 								{slugError && (
 									<div className="text-xs text-vscode-errorForeground mt-1">{slugError}</div>
 								)}
 							</div>
-							<div style={{ marginBottom: "16px" }}>
-								<div style={{ fontWeight: "bold", marginBottom: "4px" }}>
-									{t("prompts:createModeDialog.saveLocation.label")}
-								</div>
+							<div className="mb-4">
+								<div className="font-bold mb-1">{t("prompts:createModeDialog.saveLocation.label")}</div>
 								<div className="text-sm text-vscode-descriptionForeground mb-2">
 									{t("prompts:createModeDialog.saveLocation.description")}
 								</div>
@@ -1233,12 +1198,7 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 									}}>
 									<VSCodeRadio value="global">
 										{t("prompts:createModeDialog.saveLocation.global.label")}
-										<div
-											style={{
-												fontSize: "12px",
-												color: "var(--vscode-descriptionForeground)",
-												marginTop: "2px",
-											}}>
+										<div className="text-xs text-vscode-descriptionForeground mt-0.5">
 											{t("prompts:createModeDialog.saveLocation.global.description")}
 										</div>
 									</VSCodeRadio>
@@ -1263,17 +1223,13 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 									}}>
 									{t("prompts:createModeDialog.roleDefinition.description")}
 								</div>
-								<VSCodeTextArea
+								<Textarea
 									value={newModeRoleDefinition}
 									onChange={(e) => {
-										const value =
-											(e as CustomEvent)?.detail?.target?.value ||
-											((e as any).target as HTMLTextAreaElement).value
-										setNewModeRoleDefinition(value)
+										setNewModeRoleDefinition(e.target.value)
 									}}
 									rows={4}
-									resize="vertical"
-									style={{ width: "100%" }}
+									className="w-full resize-y"
 								/>
 								{roleDefinitionError && (
 									<div className="text-xs text-vscode-errorForeground mt-1">
@@ -1281,24 +1237,12 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 									</div>
 								)}
 							</div>
-							<div style={{ marginBottom: "16px" }}>
-								<div style={{ fontWeight: "bold", marginBottom: "4px" }}>
-									{t("prompts:createModeDialog.tools.label")}
-								</div>
-								<div
-									style={{
-										fontSize: "13px",
-										color: "var(--vscode-descriptionForeground)",
-										marginBottom: "8px",
-									}}>
+							<div className="mb-4">
+								<div className="font-bold mb-1">{t("prompts:createModeDialog.tools.label")}</div>
+								<div className="text-[13px] text-vscode-descriptionForeground mb-2">
 									{t("prompts:createModeDialog.tools.description")}
 								</div>
-								<div
-									style={{
-										display: "grid",
-										gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))",
-										gap: "8px",
-									}}>
+								<div className="grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))] gap-2">
 									{availableGroups.map((group) => (
 										<VSCodeCheckbox
 											key={group}
@@ -1323,41 +1267,24 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 									<div className="text-xs text-vscode-errorForeground mt-1">{groupsError}</div>
 								)}
 							</div>
-							<div style={{ marginBottom: "16px" }}>
-								<div style={{ fontWeight: "bold", marginBottom: "4px" }}>
+							<div className="mb-4">
+								<div className="font-bold mb-1">
 									{t("prompts:createModeDialog.customInstructions.label")}
 								</div>
-								<div
-									style={{
-										fontSize: "13px",
-										color: "var(--vscode-descriptionForeground)",
-										marginBottom: "8px",
-									}}>
+								<div className="text-[13px] text-vscode-descriptionForeground mb-2">
 									{t("prompts:createModeDialog.customInstructions.description")}
 								</div>
-								<VSCodeTextArea
+								<Textarea
 									value={newModeCustomInstructions}
 									onChange={(e) => {
-										const value =
-											(e as CustomEvent)?.detail?.target?.value ||
-											((e as any).target as HTMLTextAreaElement).value
-										setNewModeCustomInstructions(value)
+										setNewModeCustomInstructions(e.target.value)
 									}}
 									rows={4}
-									resize="vertical"
-									style={{ width: "100%" }}
+									className="w-full resize-y"
 								/>
 							</div>
 						</div>
-						<div
-							style={{
-								display: "flex",
-								justifyContent: "flex-end",
-								padding: "12px 20px",
-								gap: "8px",
-								borderTop: "1px solid var(--vscode-editor-lineHighlightBorder)",
-								backgroundColor: "var(--vscode-editor-background)",
-							}}>
+						<div className="flex justify-end p-3 px-5 gap-2 border-t border-vscode-editor-lineHighlightBorder bg-vscode-editor-background">
 							<Button variant="secondary" onClick={() => setIsCreateModeDialogOpen(false)}>
 								{t("prompts:createModeDialog.buttons.cancel")}
 							</Button>
@@ -1370,71 +1297,27 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 			)}
 
 			{isDialogOpen && (
-				<div
-					style={{
-						position: "fixed",
-						inset: 0,
-						display: "flex",
-						justifyContent: "flex-end",
-						backgroundColor: "rgba(0, 0, 0, 0.5)",
-						zIndex: 1000,
-					}}>
-					<div
-						style={{
-							width: "calc(100vw - 100px)",
-							height: "100%",
-							backgroundColor: "var(--vscode-editor-background)",
-							boxShadow: "-2px 0 5px rgba(0, 0, 0, 0.2)",
-							display: "flex",
-							flexDirection: "column",
-							position: "relative",
-						}}>
-						<div
-							style={{
-								flex: 1,
-								padding: "20px",
-								overflowY: "auto",
-								minHeight: 0,
-							}}>
+				<div className="fixed inset-0 flex justify-end bg-black/50 z-[1000]">
+					<div className="w-[calc(100vw-100px)] h-full bg-vscode-editor-background shadow-md flex flex-col relative">
+						<div className="flex-1 p-5 overflow-y-auto min-h-0">
 							<Button
 								variant="ghost"
 								size="icon"
 								onClick={() => setIsDialogOpen(false)}
-								style={{
-									position: "absolute",
-									top: "20px",
-									right: "20px",
-								}}>
+								className="absolute top-5 right-5">
 								<span className="codicon codicon-close"></span>
 							</Button>
-							<h2 style={{ margin: "0 0 16px" }}>
+							<h2 className="mb-4">
 								{selectedPromptTitle ||
-									t("prompts:systemPrompt.title", { modeName: getCurrentMode()?.name || "Code" })}
+									t("prompts:systemPrompt.title", {
+										modeName: getCurrentMode()?.name || "Code",
+									})}
 							</h2>
-							<pre
-								style={{
-									padding: "8px",
-									whiteSpace: "pre-wrap",
-									wordBreak: "break-word",
-									fontFamily: "var(--vscode-editor-font-family)",
-									fontSize: "var(--vscode-editor-font-size)",
-									color: "var(--vscode-editor-foreground)",
-									backgroundColor: "var(--vscode-editor-background)",
-									border: "1px solid var(--vscode-editor-lineHighlightBorder)",
-									borderRadius: "4px",
-									overflowY: "auto",
-								}}>
+							<pre className="p-2 whitespace-pre-wrap break-words font-mono text-vscode-editor-font-size text-vscode-editor-foreground bg-vscode-editor-background border border-vscode-editor-lineHighlightBorder rounded overflow-y-auto">
 								{selectedPromptContent}
 							</pre>
 						</div>
-						<div
-							style={{
-								display: "flex",
-								justifyContent: "flex-end",
-								padding: "12px 20px",
-								borderTop: "1px solid var(--vscode-editor-lineHighlightBorder)",
-								backgroundColor: "var(--vscode-editor-background)",
-							}}>
+						<div className="flex justify-end p-3 px-5 border-t border-vscode-editor-lineHighlightBorder bg-vscode-editor-background">
 							<Button variant="secondary" onClick={() => setIsDialogOpen(false)}>
 								{t("prompts:createModeDialog.close")}
 							</Button>

+ 77 - 62
webview-ui/src/components/prompts/__tests__/PromptsView.test.tsx

@@ -10,6 +10,22 @@ jest.mock("@src/utils/vscode", () => ({
 	},
 }))
 
+// Mock all lucide-react icons with a proxy to handle any icon requested
+jest.mock("lucide-react", () => {
+	return new Proxy(
+		{},
+		{
+			get: function (obj, prop) {
+				// Return a component factory for any icon that's requested
+				if (prop === "__esModule") {
+					return true
+				}
+				return () => <div data-testid={`${String(prop)}-icon`}>{String(prop)}</div>
+			},
+		},
+	)
+})
+
 const mockExtensionState = {
 	customModePrompts: {},
 	listApiConfigMeta: [
@@ -19,6 +35,9 @@ const mockExtensionState = {
 	enhancementApiConfigId: "",
 	setEnhancementApiConfigId: jest.fn(),
 	mode: "code",
+	customModes: [],
+	customSupportPrompts: [],
+	currentApiConfigName: "",
 	customInstructions: "Initial instructions",
 	setCustomInstructions: jest.fn(),
 }
@@ -32,69 +51,67 @@ const renderPromptsView = (props = {}) => {
 	)
 }
 
+class MockResizeObserver {
+	observe() {}
+	unobserve() {}
+	disconnect() {}
+}
+
+global.ResizeObserver = MockResizeObserver
+
+Element.prototype.scrollIntoView = jest.fn()
+
 describe("PromptsView", () => {
 	beforeEach(() => {
 		jest.clearAllMocks()
 	})
 
-	it("renders all mode tabs", () => {
-		renderPromptsView()
-		expect(screen.getByTestId("code-tab")).toBeInTheDocument()
-		expect(screen.getByTestId("ask-tab")).toBeInTheDocument()
-		expect(screen.getByTestId("architect-tab")).toBeInTheDocument()
+	it("displays the current mode name in the select trigger", () => {
+		renderPromptsView({ mode: "code" })
+		const selectTrigger = screen.getByTestId("mode-select-trigger")
+		expect(selectTrigger).toHaveTextContent("Code")
 	})
 
-	it("defaults to current mode as active tab", () => {
-		renderPromptsView({ mode: "ask" })
-
-		const codeTab = screen.getByTestId("code-tab")
-		const askTab = screen.getByTestId("ask-tab")
-		const architectTab = screen.getByTestId("architect-tab")
-
-		expect(askTab).toHaveAttribute("data-active", "true")
-		expect(codeTab).toHaveAttribute("data-active", "false")
-		expect(architectTab).toHaveAttribute("data-active", "false")
+	it("opens the mode selection popover when the trigger is clicked", async () => {
+		renderPromptsView()
+		const selectTrigger = screen.getByTestId("mode-select-trigger")
+		fireEvent.click(selectTrigger)
+		await waitFor(() => {
+			expect(selectTrigger).toHaveAttribute("aria-expanded", "true")
+		})
 	})
 
-	it("switches between tabs correctly", async () => {
-		const { rerender } = render(
-			<ExtensionStateContext.Provider value={{ ...mockExtensionState, mode: "code" } as any}>
-				<PromptsView onDone={jest.fn()} />
-			</ExtensionStateContext.Provider>,
-		)
-
-		const codeTab = screen.getByTestId("code-tab")
-		const askTab = screen.getByTestId("ask-tab")
-		const architectTab = screen.getByTestId("architect-tab")
+	it("filters mode options based on search input", async () => {
+		renderPromptsView()
+		const selectTrigger = screen.getByTestId("mode-select-trigger")
+		fireEvent.click(selectTrigger)
 
-		// Initial state matches current mode (code)
-		expect(codeTab).toHaveAttribute("data-active", "true")
-		expect(askTab).toHaveAttribute("data-active", "false")
-		expect(architectTab).toHaveAttribute("data-active", "false")
+		const searchInput = screen.getByTestId("mode-search-input")
+		fireEvent.change(searchInput, { target: { value: "ask" } })
 
-		// Click Ask tab and update context
-		fireEvent.click(askTab)
-		rerender(
-			<ExtensionStateContext.Provider value={{ ...mockExtensionState, mode: "ask" } as any}>
-				<PromptsView onDone={jest.fn()} />
-			</ExtensionStateContext.Provider>,
-		)
+		await waitFor(() => {
+			expect(screen.getByTestId("mode-option-ask")).toBeInTheDocument()
+			expect(screen.queryByTestId("mode-option-code")).not.toBeInTheDocument()
+			expect(screen.queryByTestId("mode-option-architect")).not.toBeInTheDocument()
+		})
+	})
 
-		expect(askTab).toHaveAttribute("data-active", "true")
-		expect(codeTab).toHaveAttribute("data-active", "false")
-		expect(architectTab).toHaveAttribute("data-active", "false")
+	it("selects a mode from the dropdown and sends update message", async () => {
+		renderPromptsView()
+		const selectTrigger = screen.getByTestId("mode-select-trigger")
+		fireEvent.click(selectTrigger)
 
-		// Click Architect tab and update context
-		fireEvent.click(architectTab)
-		rerender(
-			<ExtensionStateContext.Provider value={{ ...mockExtensionState, mode: "architect" } as any}>
-				<PromptsView onDone={jest.fn()} />
-			</ExtensionStateContext.Provider>,
-		)
+		const askOption = await waitFor(() => screen.getByTestId("mode-option-ask"))
+		fireEvent.click(askOption)
 
-		expect(architectTab).toHaveAttribute("data-active", "true")
-		expect(askTab).toHaveAttribute("data-active", "false")
-		expect(codeTab).toHaveAttribute("data-active", "false")
+		expect(mockExtensionState.setEnhancementApiConfigId).not.toHaveBeenCalled() // Ensure this is not called by mode switch
+		expect(vscode.postMessage).toHaveBeenCalledWith({
+			type: "mode",
+			text: "ask",
+		})
+		await waitFor(() => {
+			expect(selectTrigger).toHaveAttribute("aria-expanded", "false")
+		})
 	})
 
 	it("handles prompt changes correctly", async () => {
@@ -159,21 +176,19 @@ describe("PromptsView", () => {
 	it("handles API configuration selection", async () => {
 		renderPromptsView()
 
-		// Click the ENHANCE tab first to show the API config dropdown
-		const enhanceTab = screen.getByTestId("ENHANCE-tab")
-		fireEvent.click(enhanceTab)
+		const trigger = screen.getByTestId("support-prompt-select-trigger")
+		fireEvent.click(trigger)
 
-		// Wait for the ENHANCE tab click to take effect
-		const dropdown = await waitFor(() => screen.getByTestId("api-config-dropdown"))
-		fireEvent.change(dropdown, {
-			target: { value: "config1" },
-		})
+		const enhanceOption = await waitFor(() => screen.getByTestId("ENHANCE-option"))
+		fireEvent.click(enhanceOption)
 
-		expect(mockExtensionState.setEnhancementApiConfigId).toHaveBeenCalledWith("config1")
-		expect(vscode.postMessage).toHaveBeenCalledWith({
-			type: "enhancementApiConfigId",
-			text: "config1",
-		})
+		const apiConfig = await waitFor(() => screen.getByTestId("api-config-select"))
+		fireEvent.click(apiConfig)
+
+		const config1 = await waitFor(() => screen.getByTestId("config1-option"))
+		fireEvent.click(config1)
+
+		expect(mockExtensionState.setEnhancementApiConfigId).toHaveBeenCalledWith("config1") // Ensure this is not called by mode switch
 	})
 
 	it("handles clearing custom instructions correctly", async () => {

+ 6 - 6
webview-ui/src/components/settings/AutoApproveSettings.tsx

@@ -2,9 +2,9 @@ import { HTMLAttributes, useState } from "react"
 import { X } from "lucide-react"
 
 import { useAppTranslation } from "@/i18n/TranslationContext"
-import { VSCodeTextField, VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
+import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
 import { vscode } from "@/utils/vscode"
-import { Button, Slider } from "@/components/ui"
+import { Button, Input, Slider } from "@/components/ui"
 
 import { SetCachedStateField } from "./types"
 import { SectionHeader } from "./SectionHeader"
@@ -203,9 +203,9 @@ export const AutoApproveSettings = ({
 						</div>
 
 						<div className="flex gap-2">
-							<VSCodeTextField
+							<Input
 								value={commandInput}
-								onInput={(e: any) => setCommandInput(e.target.value)}
+								onChange={(e: any) => setCommandInput(e.target.value)}
 								onKeyDown={(e: any) => {
 									if (e.key === "Enter") {
 										e.preventDefault()
@@ -216,7 +216,7 @@ export const AutoApproveSettings = ({
 								className="grow"
 								data-testid="command-input"
 							/>
-							<Button onClick={handleAddCommand} data-testid="add-command-button">
+							<Button className="h-8" onClick={handleAddCommand} data-testid="add-command-button">
 								{t("settings:autoApprove.execute.addButton")}
 							</Button>
 						</div>
@@ -234,7 +234,7 @@ export const AutoApproveSettings = ({
 									}}>
 									<div className="flex flex-row items-center gap-1">
 										<div>{cmd}</div>
-										<X className="text-primary-foreground scale-75" />
+										<X className="text-foreground scale-75" />
 									</div>
 								</Button>
 							))}

+ 2 - 2
webview-ui/src/components/settings/ContextManagementSettings.tsx

@@ -4,7 +4,7 @@ import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
 import { Database } from "lucide-react"
 
 import { cn } from "@/lib/utils"
-import { Slider } from "@/components/ui"
+import { Input, Slider } from "@/components/ui"
 
 import { SetCachedStateField } from "./types"
 import { SectionHeader } from "./SectionHeader"
@@ -96,7 +96,7 @@ export const ContextManagementSettings = ({
 					<div className="flex flex-col gap-2">
 						<span className="font-medium">{t("settings:contextManagement.maxReadFile.label")}</span>
 						<div className="flex items-center gap-4">
-							<input
+							<Input
 								type="number"
 								pattern="-?[0-9]*"
 								className="w-24 bg-vscode-input-background text-vscode-input-foreground border border-vscode-input-border px-2 py-1 rounded text-right [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none disabled:opacity-50"

+ 2 - 2
webview-ui/src/components/ui/alert-dialog.tsx

@@ -90,7 +90,7 @@ function AlertDialogAction({ className, ...props }: React.ComponentProps<typeof
 		<AlertDialogPrimitive.Action
 			className={cn(
 				buttonVariants(),
-				"bg-vscode-button-background text-vscode-button-foreground hover:bg-vscode-button-hoverBackground border border-transparent h-6 px-3 py-1",
+				"bg-vscode-button-background text-vscode-button-foreground hover:bg-vscode-button-hoverBackground h-6 px-3 py-1 border",
 				className,
 			)}
 			{...props}
@@ -103,7 +103,7 @@ function AlertDialogCancel({ className, ...props }: React.ComponentProps<typeof
 		<AlertDialogPrimitive.Cancel
 			className={cn(
 				buttonVariants({ variant: "outline" }),
-				"bg-vscode-button-secondaryBackground text-vscode-button-secondaryForeground hover:bg-vscode-button-secondaryHoverBackground border border-vscode-button-border h-6 px-3 py-1",
+				"bg-vscode-button-secondaryBackground text-vscode-button-secondaryForeground hover:bg-vscode-button-secondaryHoverBackground h-6 px-3 py-1 border",
 				className,
 			)}
 			{...props}

+ 4 - 5
webview-ui/src/components/ui/button.tsx

@@ -9,13 +9,12 @@ const buttonVariants = cva(
 	{
 		variants: {
 			variant: {
-				default:
-					"border border-vscode-input-border bg-primary text-primary-foreground shadow hover:bg-primary/90",
-				destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
+				default: "border border-vscode-input-border bg-primary text-primary-foreground hover:bg-primary/90",
+				destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
 				outline:
-					"border border-vscode-input-border bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
+					"border border-vscode-input-border bg-transparent hover:bg-accent hover:text-accent-foreground",
 				secondary:
-					"border border-vscode-input-border bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
+					"border border-vscode-input-border bg-secondary text-secondary-foreground hover:bg-secondary/80",
 				ghost: "hover:bg-accent hover:text-accent-foreground",
 				link: "text-primary underline-offset-4 hover:underline",
 				combobox:

+ 2 - 2
webview-ui/src/components/ui/slider.tsx

@@ -11,10 +11,10 @@ const Slider = React.forwardRef<
 		ref={ref}
 		className={cn("relative flex w-full touch-none select-none items-center", className)}
 		{...props}>
-		<SliderPrimitive.Track className="relative w-full h-[8px] grow overflow-hidden bg-accent border border-[#767676] dark:border-[#858585] rounded-sm">
+		<SliderPrimitive.Track className="relative w-full h-[8px] grow overflow-hidden bg-accent rounded-sm border">
 			<SliderPrimitive.Range className="absolute h-full bg-vscode-button-background" />
 		</SliderPrimitive.Track>
-		<SliderPrimitive.Thumb className="block h-3 w-3 rounded-full border border-primary/50 bg-primary shadow transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
+		<SliderPrimitive.Thumb className="block h-3 w-3 rounded-full border border-primary/50 bg-vscode-button-background transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
 	</SliderPrimitive.Root>
 ))
 Slider.displayName = SliderPrimitive.Root.displayName

+ 2 - 2
webview-ui/src/components/ui/textarea.tsx

@@ -7,8 +7,8 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<"tex
 		return (
 			<textarea
 				className={cn(
-					"flex min-h-[60px] w-full rounded-xs px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus:outline-0 focus-visible:outline-none focus-visible:border-vscode-focusBorder disabled:cursor-not-allowed disabled:opacity-50",
-					"border-[var(--vscode-input-border,var(--vscode-input-background))] focus-visible:border-vscode-focusBorder",
+					"flex min-h-[60px] w-full rounded-xs px-3 py-2 text-base placeholder:text-muted-foreground focus:outline-0 focus-visible:outline-none focus-visible:border-vscode-focusBorder disabled:cursor-not-allowed disabled:opacity-50",
+					"border border-[var(--vscode-input-border,var(--vscode-input-background))] focus-visible:border-vscode-focusBorder",
 					"bg-vscode-input-background",
 					"text-vscode-input-foreground",
 					className,

+ 2 - 1
webview-ui/src/i18n/locales/ca/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Editar configuració de modes",
 		"editGlobalModes": "Editar modes globals",
 		"editProjectModes": "Editar modes de projecte (.roomodes)",
-		"createModeHelpText": "Feu clic a + per crear un nou mode personalitzat, o simplement demaneu a Roo al xat que en creï un per a vostè!"
+		"createModeHelpText": "Feu clic a + per crear un nou mode personalitzat, o simplement demaneu a Roo al xat que en creï un per a vostè!",
+		"selectMode": "Cerqueu modes"
 	},
 	"apiConfiguration": {
 		"title": "Configuració d'API",

+ 2 - 1
webview-ui/src/i18n/locales/de/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Moduskonfiguration bearbeiten",
 		"editGlobalModes": "Globale Modi bearbeiten",
 		"editProjectModes": "Projektmodi bearbeiten (.roomodes)",
-		"createModeHelpText": "Klicke auf +, um einen neuen benutzerdefinierten Modus zu erstellen, oder bitte Roo einfach im Chat, einen für dich zu erstellen!"
+		"createModeHelpText": "Klicke auf +, um einen neuen benutzerdefinierten Modus zu erstellen, oder bitte Roo einfach im Chat, einen für dich zu erstellen!",
+		"selectMode": "Modi suchen"
 	},
 	"apiConfiguration": {
 		"title": "API-Konfiguration",

+ 2 - 1
webview-ui/src/i18n/locales/en/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Edit modes configuration",
 		"editGlobalModes": "Edit Global Modes",
 		"editProjectModes": "Edit Project Modes (.roomodes)",
-		"createModeHelpText": "Hit the + to create a new custom mode, or just ask Roo in chat to create one for you!"
+		"createModeHelpText": "Hit the + to create a new custom mode, or just ask Roo in chat to create one for you!",
+		"selectMode": "Search modes"
 	},
 	"apiConfiguration": {
 		"title": "API Configuration",

+ 2 - 1
webview-ui/src/i18n/locales/es/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Editar configuración de modos",
 		"editGlobalModes": "Editar modos globales",
 		"editProjectModes": "Editar modos del proyecto (.roomodes)",
-		"createModeHelpText": "¡Haz clic en + para crear un nuevo modo personalizado, o simplemente pídele a Roo en el chat que te cree uno!"
+		"createModeHelpText": "¡Haz clic en + para crear un nuevo modo personalizado, o simplemente pídele a Roo en el chat que te cree uno!",
+		"selectMode": "Buscar modos"
 	},
 	"apiConfiguration": {
 		"title": "Configuración de API",

+ 2 - 1
webview-ui/src/i18n/locales/fr/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Modifier la configuration des modes",
 		"editGlobalModes": "Modifier les modes globaux",
 		"editProjectModes": "Modifier les modes du projet (.roomodes)",
-		"createModeHelpText": "Cliquez sur + pour créer un nouveau mode personnalisé, ou demandez simplement à Roo dans le chat de vous en créer un !"
+		"createModeHelpText": "Cliquez sur + pour créer un nouveau mode personnalisé, ou demandez simplement à Roo dans le chat de vous en créer un !",
+		"selectMode": "Rechercher les modes"
 	},
 	"apiConfiguration": {
 		"title": "Configuration API",

+ 2 - 1
webview-ui/src/i18n/locales/hi/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "मोड कॉन्फ़िगरेशन संपादित करें",
 		"editGlobalModes": "ग्लोबल मोड्स संपादित करें",
 		"editProjectModes": "प्रोजेक्ट मोड्स संपादित करें (.roomodes)",
-		"createModeHelpText": "नया कस्टम मोड बनाने के लिए + पर क्लिक करें, या बस चैट में Roo से आपके लिए एक बनाने को कहें!"
+		"createModeHelpText": "नया कस्टम मोड बनाने के लिए + पर क्लिक करें, या बस चैट में Roo से आपके लिए एक बनाने को कहें!",
+		"selectMode": "मोड खोजें"
 	},
 	"apiConfiguration": {
 		"title": "API कॉन्फ़िगरेशन",

+ 2 - 1
webview-ui/src/i18n/locales/it/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Modifica configurazione modalità",
 		"editGlobalModes": "Modifica modalità globali",
 		"editProjectModes": "Modifica modalità di progetto (.roomodes)",
-		"createModeHelpText": "Clicca sul + per creare una nuova modalità personalizzata, o chiedi semplicemente a Roo nella chat di crearne una per te!"
+		"createModeHelpText": "Clicca sul + per creare una nuova modalità personalizzata, o chiedi semplicemente a Roo nella chat di crearne una per te!",
+		"selectMode": "Cerca modalità"
 	},
 	"apiConfiguration": {
 		"title": "Configurazione API",

+ 2 - 1
webview-ui/src/i18n/locales/ja/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "モード設定を編集",
 		"editGlobalModes": "グローバルモードを編集",
 		"editProjectModes": "プロジェクトモードを編集 (.roomodes)",
-		"createModeHelpText": "+ をクリックして新しいカスタムモードを作成するか、チャットで Roo に作成を依頼してください!"
+		"createModeHelpText": "+ をクリックして新しいカスタムモードを作成するか、チャットで Roo に作成を依頼してください!",
+		"selectMode": "モードを検索"
 	},
 	"apiConfiguration": {
 		"title": "API設定",

+ 2 - 1
webview-ui/src/i18n/locales/ko/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "모드 구성 편집",
 		"editGlobalModes": "전역 모드 편집",
 		"editProjectModes": "프로젝트 모드 편집 (.roomodes)",
-		"createModeHelpText": "새 커스텀 모드를 만들려면 + 버튼을 클릭하거나, 채팅에서 Roo에게 만들어달라고 요청하세요!"
+		"createModeHelpText": "새 커스텀 모드를 만들려면 + 버튼을 클릭하거나, 채팅에서 Roo에게 만들어달라고 요청하세요!",
+		"selectMode": "모드 검색"
 	},
 	"apiConfiguration": {
 		"title": "API 구성",

+ 2 - 1
webview-ui/src/i18n/locales/pl/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Edytuj konfigurację trybów",
 		"editGlobalModes": "Edytuj tryby globalne",
 		"editProjectModes": "Edytuj tryby projektu (.roomodes)",
-		"createModeHelpText": "Kliknij +, aby utworzyć nowy niestandardowy tryb, lub po prostu poproś Roo w czacie, aby utworzył go dla Ciebie!"
+		"createModeHelpText": "Kliknij +, aby utworzyć nowy niestandardowy tryb, lub po prostu poproś Roo w czacie, aby utworzył go dla Ciebie!",
+		"selectMode": "Szukaj trybów"
 	},
 	"apiConfiguration": {
 		"title": "Konfiguracja API",

+ 2 - 1
webview-ui/src/i18n/locales/pt-BR/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Editar configuração de modos",
 		"editGlobalModes": "Editar modos globais",
 		"editProjectModes": "Editar modos do projeto (.roomodes)",
-		"createModeHelpText": "Clique em + para criar um novo modo personalizado, ou simplesmente peça ao Roo no chat para criar um para você!"
+		"createModeHelpText": "Clique em + para criar um novo modo personalizado, ou simplesmente peça ao Roo no chat para criar um para você!",
+		"selectMode": "Buscar modos"
 	},
 	"apiConfiguration": {
 		"title": "Configuração de API",

+ 2 - 1
webview-ui/src/i18n/locales/ru/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Редактировать конфигурацию режимов",
 		"editGlobalModes": "Редактировать глобальные режимы",
 		"editProjectModes": "Редактировать режимы проекта (.roomodes)",
-		"createModeHelpText": "Нажмите +, чтобы создать новый пользовательский режим, или просто попросите Roo в чате создать его для вас!"
+		"createModeHelpText": "Нажмите +, чтобы создать новый пользовательский режим, или просто попросите Roo в чате создать его для вас!",
+		"selectMode": "Поиск режимов"
 	},
 	"apiConfiguration": {
 		"title": "Конфигурация API",

+ 2 - 1
webview-ui/src/i18n/locales/tr/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Mod yapılandırmasını düzenle",
 		"editGlobalModes": "Global modları düzenle",
 		"editProjectModes": "Proje modlarını düzenle (.roomodes)",
-		"createModeHelpText": "Yeni bir özel mod oluşturmak için + düğmesine tıklayın veya sohbette Roo'dan sizin için bir tane oluşturmasını isteyin!"
+		"createModeHelpText": "Yeni bir özel mod oluşturmak için + düğmesine tıklayın veya sohbette Roo'dan sizin için bir tane oluşturmasını isteyin!",
+		"selectMode": "Modları Ara"
 	},
 	"apiConfiguration": {
 		"title": "API Yapılandırması",

+ 2 - 1
webview-ui/src/i18n/locales/vi/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "Chỉnh sửa cấu hình chế độ",
 		"editGlobalModes": "Chỉnh sửa chế độ toàn cục",
 		"editProjectModes": "Chỉnh sửa chế độ dự án (.roomodes)",
-		"createModeHelpText": "Nhấn + để tạo chế độ tùy chỉnh mới, hoặc chỉ cần yêu cầu Roo trong chat tạo một chế độ cho bạn!"
+		"createModeHelpText": "Nhấn + để tạo chế độ tùy chỉnh mới, hoặc chỉ cần yêu cầu Roo trong chat tạo một chế độ cho bạn!",
+		"selectMode": "Tìm kiếm chế độ"
 	},
 	"apiConfiguration": {
 		"title": "Cấu hình API",

+ 2 - 1
webview-ui/src/i18n/locales/zh-CN/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "模式设置",
 		"editGlobalModes": "修改全局模式",
 		"editProjectModes": "编辑项目模式 (.roomodes)",
-		"createModeHelpText": "点击 + 创建模式,或在对话时让Roo创建一个新模式。"
+		"createModeHelpText": "点击 + 创建模式,或在对话时让Roo创建一个新模式。",
+		"selectMode": "搜索模式"
 	},
 	"apiConfiguration": {
 		"title": "API配置",

+ 2 - 1
webview-ui/src/i18n/locales/zh-TW/prompts.json

@@ -7,7 +7,8 @@
 		"editModesConfig": "編輯模式設定",
 		"editGlobalModes": "編輯全域模式",
 		"editProjectModes": "編輯專案模式 (.roomodes)",
-		"createModeHelpText": "點選 + 建立新的自訂模式,或者在聊天中直接請 Roo 為您建立!"
+		"createModeHelpText": "點選 + 建立新的自訂模式,或者在聊天中直接請 Roo 為您建立!",
+		"selectMode": "搜尋模式"
 	},
 	"apiConfiguration": {
 		"title": "API 設定",