Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-settings-search-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---

Fixed UI issues in Settings search bar: clipping of results and layout shift when expanding
46 changes: 27 additions & 19 deletions webview-ui/src/components/settings/SettingsSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useRef, useEffect, useState, useCallback } from "react"
import type { LucideIcon } from "lucide-react"

import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { useSettingsSearch, SearchResult, SearchableSettingData } from "./useSettingsSearch"
import { SectionName } from "./SettingsView"
import { SettingsSearchInput } from "./SettingsSearchInput"
Expand Down Expand Up @@ -98,26 +99,33 @@ export function SettingsSearch({ index, onNavigate, sections }: SettingsSearchPr
}, [highlightedResultId, isOpen])

return (
<div className="relative justify-end">
<SettingsSearchInput
value={searchQuery}
onChange={setSearchQuery}
onFocus={() => setIsOpen(true)}
onBlur={() => setTimeout(() => setIsOpen(false), 200)}
onKeyDown={handleSearchKeyDown}
inputRef={inputRef}
/>
{searchQuery && isOpen && (
<div className="absolute top-full min-w-[300px] right-0 mt-2 border border-vscode-dropdown-border bg-vscode-dropdown-background rounded-2xl overflow-hidden shadow-xl z-50">
<SettingsSearchResults
results={results}
query={searchQuery}
onSelectResult={handleSelectResult}
sections={sections}
highlightedResultId={highlightedResultId}
<Popover open={searchQuery !== "" && isOpen} modal={false}>
<PopoverTrigger asChild>
<div className="relative justify-end">
<SettingsSearchInput
value={searchQuery}
onChange={setSearchQuery}
onFocus={() => setIsOpen(true)}
onKeyDown={handleSearchKeyDown}
inputRef={inputRef}
/>
</div>
)}
</div>
</PopoverTrigger>
<PopoverContent
className="min-w-[300px] p-0 border-vscode-dropdown-border bg-vscode-dropdown-background rounded-2xl overflow-hidden shadow-xl"
align="end"
side="bottom"
sideOffset={8}
onOpenAutoFocus={(e) => e.preventDefault()}
onCloseAutoFocus={(e) => e.preventDefault()}>
<SettingsSearchResults
results={results}
query={searchQuery}
onSelectResult={handleSelectResult}
sections={sections}
highlightedResultId={highlightedResultId}
/>
</PopoverContent>
</Popover>
)
}
56 changes: 31 additions & 25 deletions webview-ui/src/components/settings/SettingsSearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,33 +41,39 @@ export function SettingsSearchInput({
const isWide = isExpanded || !!value

return (
<div className="relative flex items-center justify-end">
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 size-3.5 text-vscode-descriptionForeground pointer-events-none z-10" />
<Input
ref={inputRef}
data-testid="settings-search-input"
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
onFocus={handleFocus}
onBlur={handleBlur}
onKeyDown={onKeyDown}
placeholder={isWide ? t("settings:search.placeholder") : ""}
<div className="relative flex items-center justify-end w-8">
<div
className={cn(
"pl-8 h-7 text-sm rounded-full border border-vscode-input-border bg-vscode-input-background focus:border-vscode-focusBorder transition-all duration-200 ease-in-out",
isWide ? "w-40 pr-2.5" : "w-8 pr-0 cursor-pointer",
value && "pr-7",
"absolute right-0 flex items-center transition-all duration-200 ease-in-out",
isWide ? "w-40" : "w-8",
)}>
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 size-3.5 text-vscode-descriptionForeground pointer-events-none z-10" />
<Input
ref={inputRef}
data-testid="settings-search-input"
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
onFocus={handleFocus}
onBlur={handleBlur}
onKeyDown={onKeyDown}
placeholder={isWide ? t("settings:search.placeholder") : ""}
className={cn(
"pl-8 h-7 text-sm rounded-full border border-vscode-input-border bg-vscode-input-background focus:border-vscode-focusBorder transition-all duration-200 ease-in-out w-full",
isWide ? "pr-2.5" : "pr-0 cursor-pointer",
value && "pr-7",
)}
/>
{value && (
<button
type="button"
onClick={() => onChange("")}
className="absolute cursor-pointer right-2 top-1/2 -translate-y-1/2 text-vscode-descriptionForeground hover:text-vscode-foreground focus:outline-none"
aria-label="Clear search">
<X className="size-3.5" />
</button>
)}
/>
{value && (
<button
type="button"
onClick={() => onChange("")}
className="absolute cursor-pointer right-2 top-1/2 -translate-y-1/2 text-vscode-descriptionForeground hover:text-vscode-foreground focus:outline-none"
aria-label="Clear search">
<X className="size-3.5" />
</button>
)}
</div>
</div>
)
}
Loading