diff --git a/frontend/src/components/SettingsPanel.jsx b/frontend/src/components/SettingsPanel.jsx index 8b60e7f..1e29299 100644 --- a/frontend/src/components/SettingsPanel.jsx +++ b/frontend/src/components/SettingsPanel.jsx @@ -23,7 +23,6 @@ export default function SettingsPanel({ settings, onSave, onClose }) { minimal_mode: settings?.minimal_mode ?? false, }); - // SOLVES (#581): Persistent Collapse State Hooks const [isExpanded, setIsExpanded] = useState(() => { const savedState = localStorage.getItem("localmind_settings_expanded"); return savedState !== null ? JSON.parse(savedState) : true; @@ -51,6 +50,19 @@ export default function SettingsPanel({ settings, onSave, onClose }) { localStorage.setItem("localmind_settings_drafts", JSON.stringify(drafts)); }, [drafts]); + // FIXED (#578): Global keyboard listener listening for Escape key panel dismiss signals + useEffect(() => { + function handleKeyDown(e) { + if (e.key === "Escape") { + onClose(); + } + } + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [onClose]); + + const isEmptyState = !settings || Object.keys(settings).length === 0; + function set(key, val) { setForm(p => ({ ...p, [key]: val })); if (errors[key]) { @@ -105,28 +117,30 @@ export default function SettingsPanel({ settings, onSave, onClose }) { }; return ( - /* FIXED (#580): Changed top wrapper from a generic
to a semantic section landmark region */
- {/* FIXED (#580): Transformed paragraph into a proper heading paired to the section landmark label */}

- - {/* SOLVES (#581): Persistent Collapse Button Controller */}
- +
{errors.global && ( @@ -135,19 +149,17 @@ export default function SettingsPanel({ settings, onSave, onClose }) {
)} - {/* SOLVES (#581): Controlled expanded layout rendering window wrapper */} {isExpanded && ( <> - {/* FIXED (#580): Provided unique htmlId properties to bind labels explicitly to inputs */}
- set("default_model", e.target.value)} className="sel focus:ring-2 focus:ring-purple-500"> {MODELS.map(m => )} - + - set("default_language", e.target.value)} className="sel focus:ring-2 focus:ring-purple-500"> {LANGUAGES.map(l => )} @@ -155,29 +167,29 @@ export default function SettingsPanel({ settings, onSave, onClose }) { set("temperature", parseFloat(e.target.value))} - className="w-full accent-purple-500" /> + className="w-full accent-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500 rounded" /> set("rag_top_k", parseInt(e.target.value))} - className="w-full accent-purple-500" /> + className="w-full accent-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500 rounded" /> set("rag_chunk_overlap", parseInt(e.target.value))} - className="w-full accent-purple-500" /> + className="w-full accent-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500 rounded" /> set("max_history_turns", parseInt(e.target.value))} - className="w-full accent-purple-500" /> + className="w-full accent-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500 rounded" /> - set("theme", e.target.value)} className="sel focus:ring-2 focus:ring-purple-500"> @@ -193,7 +205,7 @@ export default function SettingsPanel({ settings, onSave, onClose }) { type="checkbox" checked={form.minimal_mode} onChange={e => set("minimal_mode", e.target.checked)} - className="accent-purple-500" + className="accent-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-500 rounded" /> Low-bandwidth mode @@ -209,13 +221,13 @@ export default function SettingsPanel({ settings, onSave, onClose }) { value={newDraft} onChange={e => setNewDraft(e.target.value)} placeholder="Type a canned prompt snippet or scratchpad note..." - className="flex-1 bg-gray-800 text-gray-200 border border-gray-700 rounded-lg px-3 py-1 text-xs outline-none focus:border-purple-500 placeholder-gray-600" + className="flex-1 bg-gray-800 text-gray-200 border border-gray-700 rounded-lg px-3 py-1 text-xs outline-none focus:border-purple-500 placeholder-gray-600 focus:ring-2 focus:ring-purple-500" onKeyDown={e => e.key === "Enter" && handleAddDraft()} /> @@ -231,7 +243,7 @@ export default function SettingsPanel({ settings, onSave, onClose }) { @@ -247,14 +259,14 @@ export default function SettingsPanel({ settings, onSave, onClose }) { type="button" onClick={handleSave} disabled={isSaving} - className="text-xs bg-purple-700 hover:bg-purple-600 disabled:bg-gray-800 text-white px-4 py-1.5 rounded-lg transition font-medium shadow-md" + className="text-xs bg-purple-700 hover:bg-purple-600 disabled:bg-gray-800 text-white px-4 py-1.5 rounded-lg transition font-medium shadow-md focus:outline-none focus:ring-2 focus:ring-purple-500" > {isSaving ? "Saving..." : "Save Settings"} @@ -263,7 +275,7 @@ export default function SettingsPanel({ settings, onSave, onClose }) {