diff --git a/CODE-AUDIT.md b/CODE-AUDIT.md index 4ad973f..2f5bade 100644 --- a/CODE-AUDIT.md +++ b/CODE-AUDIT.md @@ -386,7 +386,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n - [ ] **L5 — Inline `style={{}}` vs makeStyles** (25× across 8 files; SettingsView 14×). Notably Sidebar's active-nav inset shadow and DownloadOptionsForm's hint caption use inline styles where a class exists elsewhere. -- [ ] **L6 — Control height mismatch.** `Select` is a fixed 32px sitting beside `size="large"` +- [x] **L6 — Control height mismatch.** `Select` is a fixed 32px sitting beside `size="large"` (~40px) Input/Buttons in DownloadBar. - [x] **L7 — `canceled` and `paused` share the 'warning' badge color** (QueueItem) — visually ambiguous. @@ -399,7 +399,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n Consider a central constants module. - [x] **L11 — "Queue (N)" overcounts.** DownloadsView's header count is `items.length` (includes completed/error/canceled), not the active queue. -- [ ] **L12 — Command palette polish.** No scroll-into-view for keyboard selection in the 50vh +- [x] **L12 — Command palette polish.** No scroll-into-view for keyboard selection in the 50vh list; `role="dialog"` without `aria-modal`/focus-trap; Esc handled only on the input. - [x] **L13 — Destructive actions lack confirmation.** "Clear history", "Clear log", "Remove source" are one-click — inconsistent with the careful confirm on backup import. diff --git a/src/renderer/src/components/CommandPalette.tsx b/src/renderer/src/components/CommandPalette.tsx index f3bd05f..ba0e525 100644 --- a/src/renderer/src/components/CommandPalette.tsx +++ b/src/renderer/src/components/CommandPalette.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { makeStyles, mergeClasses, tokens, shorthands } from '@fluentui/react-components' import { useFocusStyles } from './ui/focusRing' @@ -11,7 +11,7 @@ export interface PaletteAction { } const useStyles = makeStyles({ - // A plain fixed overlay — NOT a Fluent Dialog, since this app avoids Fluent's + // A plain fixed overlay -- NOT a Fluent Dialog, since this app avoids Fluent's // portal-based overlays (GPU/driver blank-overlay issue, see Select.tsx). backdrop: { position: 'fixed', @@ -95,6 +95,7 @@ export function CommandPalette({ const [q, setQ] = useState('') const [sel, setSel] = useState(0) const inputRef = useRef(null) + const listRef = useRef(null) const filtered = actions.filter((a) => a.label.toLowerCase().includes(q.trim().toLowerCase())) @@ -104,6 +105,10 @@ export function CommandPalette({ useEffect(() => { setSel(0) }, [q]) + useEffect(() => { + const btn = listRef.current?.querySelector(`[data-sel="true"]`) + btn?.scrollIntoView({ block: 'nearest' }) + }, [sel]) function onKeyDown(e: React.KeyboardEvent): void { if (e.key === 'Escape') { @@ -141,7 +146,7 @@ export function CommandPalette({ placeholder="Type a command…" aria-label="Command palette search" /> -
+
{filtered.length === 0 ? (
No matching commands
) : ( @@ -149,6 +154,7 @@ export function CommandPalette({