From 31935fe317dab57d182b259e34b102b7f7dba891 Mon Sep 17 00:00:00 2001 From: d-oit Date: Mon, 10 Aug 2026 11:34:49 +0200 Subject: [PATCH 1/3] feat(ux): implement consistent visual focus indicators across all web UI components Replace focus:outline-none focus:ring-2 with the focus-visible outline pattern across History, KeyboardShortcutsModal, MainHeader, MetadataBar, ProfileCombobox, ResultCard, SearchSection and Sidebar so keyboard users get a consistent visible focus ring while mouse users keep a clean UI. --- web/app/components/History.tsx | 10 +++++----- web/app/components/KeyboardShortcutsModal.tsx | 2 +- web/app/components/MainHeader.tsx | 6 +++--- web/app/components/MetadataBar.tsx | 6 +++--- web/app/components/ProfileCombobox.tsx | 4 ++-- web/app/components/ResultCard.tsx | 8 ++++---- web/app/components/SearchSection.tsx | 8 ++++---- web/app/components/Sidebar.tsx | 20 +++++++++---------- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/web/app/components/History.tsx b/web/app/components/History.tsx index 265d283c..b30cf522 100644 --- a/web/app/components/History.tsx +++ b/web/app/components/History.tsx @@ -106,7 +106,7 @@ export default function History({ onLoad }: HistoryProps) {
- + Help
diff --git a/web/app/components/MetadataBar.tsx b/web/app/components/MetadataBar.tsx index c218f90b..cfa493b3 100644 --- a/web/app/components/MetadataBar.tsx +++ b/web/app/components/MetadataBar.tsx @@ -53,7 +53,7 @@ export function MetadataBar({
diff --git a/web/app/components/ProfileCombobox.tsx b/web/app/components/ProfileCombobox.tsx index fa0e4ee9..cedc6e30 100644 --- a/web/app/components/ProfileCombobox.tsx +++ b/web/app/components/ProfileCombobox.tsx @@ -118,7 +118,7 @@ export default function ProfileCombobox({ id: providedId, value, onChange, optio ref={triggerRef} onClick={() => (open ? handleClose() : handleOpen())} onKeyDown={handleKeyDown} - className="w-full bg-[#141414] border-2 border-border-muted px-3 py-2 text-left flex items-center justify-between text-[12px] min-h-[44px] hover:border-border-strong focus:border-accent" + className="w-full bg-[#141414] border-2 border-border-muted px-3 py-2 text-left flex items-center justify-between text-[12px] min-h-[44px] hover:border-border-strong focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" aria-haspopup="listbox" aria-expanded={open} aria-controls={open ? listboxId : undefined} @@ -143,7 +143,7 @@ export default function ProfileCombobox({ id: providedId, value, onChange, optio id={`${listboxId}-option-${option.id}`} onClick={() => handleSelect(option.id)} onKeyDown={handleKeyDown} - className={`w-full px-3 py-2 text-left hover:bg-accent hover:text-background transition-colors flex flex-col focus:outline-none focus:bg-accent focus:text-background ${ + className={`w-full px-3 py-2 text-left hover:bg-accent hover:text-background transition-colors flex flex-col focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 focus:bg-accent focus:text-background ${ option.id === value ? "bg-[#222] text-accent" : "text-foreground" } ${index === activeIndex ? "ring-inset ring-2 ring-accent" : ""}`} role="option" diff --git a/web/app/components/ResultCard.tsx b/web/app/components/ResultCard.tsx index a32403f3..8820cceb 100644 --- a/web/app/components/ResultCard.tsx +++ b/web/app/components/ResultCard.tsx @@ -20,7 +20,7 @@ const ResultHeader = ({ id, title, url, normalizedUrl }: { id: string; title: st href={url} target="_blank" rel="noreferrer" - className="text-accent text-[15px] hover:underline" + className="text-accent text-[15px] hover:underline focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" > {title} @@ -76,7 +76,7 @@ export default function ResultCard({ result, onCopy, onHelpfulToggle, helpful }:
@@ -46,7 +46,7 @@ const SearchActions = ({ @@ -122,13 +122,13 @@ export function SearchSection({ aria-invalid={Boolean(error)} aria-errormessage={error ? "search-error" : undefined} enterKeyHint="search" - className="w-full bg-transparent text-[20px] sm:text-[24px] text-foreground placeholder:text-text-dim tracking-tight pr-10" + className="w-full bg-transparent text-[20px] sm:text-[24px] text-foreground placeholder:text-text-dim tracking-tight pr-10 focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" /> {query && (
@@ -167,7 +167,7 @@ export default function Sidebar({ const tooltipId = `provider-hint-${provider.id}`; const showHint = needsKey || (provider.id === "duckduckgo" && mistralActive); - let buttonClasses = "px-2 py-1 text-[10px] border-2 transition-colors min-h-[36px] "; + let buttonClasses = "px-2 py-1 text-[10px] border-2 transition-colors min-h-[36px] focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 "; if (isActive) { if (isManual) { buttonClasses += "bg-accent text-background border-accent font-bold"; @@ -227,7 +227,7 @@ export default function Sidebar({ onClick={() => setApiKeysOpen(!apiKeysOpen)} aria-expanded={apiKeysOpen} aria-controls="api-keys-panel" - className="text-[11px] text-text-muted hover:text-foreground text-left min-h-[44px] py-2" + className="text-[11px] text-text-muted hover:text-foreground text-left min-h-[44px] py-2 focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" > API Keys @@ -239,7 +239,7 @@ export default function Sidebar({ type="checkbox" checked={skipCache} onChange={(e) => setSkipCache(e.target.checked)} - className="w-5 h-5 bg-[#141414] border-2 border-border-muted accent-accent" + className="w-5 h-5 bg-[#141414] border-2 border-border-muted accent-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" /> Skip cache @@ -249,7 +249,7 @@ export default function Sidebar({ type="checkbox" checked={deepResearch} onChange={(e) => setDeepResearch(e.target.checked)} - className="w-5 h-5 bg-[#141414] border-2 border-border-muted accent-accent" + className="w-5 h-5 bg-[#141414] border-2 border-border-muted accent-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2" /> Deep research @@ -267,7 +267,7 @@ export default function Sidebar({ value={value} onChange={(e) => handleKeyChange(key, e.target.value)} placeholder={hasServer && !value ? "Using server key" : "sk-..."} - className="bg-[#141414] border-2 border-border-muted px-2 py-2 text-[12px] text-foreground placeholder:text-text-dim focus:border-accent min-h-[44px]" + className="bg-[#141414] border-2 border-border-muted px-2 py-2 text-[12px] text-foreground placeholder:text-text-dim focus:border-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 min-h-[44px]" /> ); From 4570bcc0308644622ad3b64038d30bf24b13b006 Mon Sep 17 00:00:00 2001 From: d-oit Date: Mon, 10 Aug 2026 12:11:57 +0200 Subject: [PATCH 2/3] chore(ux): no-op to refresh DeepSource analysis with config ignore From bda98311b00eb043ba1eef1535e08da87c39f07a Mon Sep 17 00:00:00 2001 From: d-oit Date: Mon, 10 Aug 2026 12:17:51 +0200 Subject: [PATCH 3/3] chore(ux): refresh DeepSource after baseline config merge