feat(FN-671): add disclosure toggle to QuickEntryBox

- Add disclosure state with expanded/collapsed toggle button
- Implement disclosure pattern CSS styles for visual feedback
- Update QuickEntryBox to support expandable/collapsible interface
- Fix CSS variable reference: use --card-hover instead of non-existent --background-hover
- Set default disclosure state to expanded (true) for backward compatibility
- Add comprehensive tests for disclosure state, toggle behavior, and interactions
This commit is contained in:
gsxdsm
2026-04-01 00:00:46 -07:00
parent 4ef12b36b7
commit 265bcede89
3 changed files with 278 additions and 75 deletions

View File

@@ -8,6 +8,7 @@ import { CustomModelDropdown } from "./CustomModelDropdown";
import { ModelSelectionModal } from "./ModelSelectionModal";
const STORAGE_KEY = "kb-quick-entry-text";
const DISCLOSURE_STORAGE_KEY = "kb-quick-entry-expanded";
interface QuickEntryBoxProps {
onCreate?: (input: TaskCreateInput) => Promise<void>;
@@ -57,7 +58,17 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
return "";
});
const [isSubmitting, setIsSubmitting] = useState(false);
// isExpanded controls textarea height styling (auto-resize)
const [isExpanded, setIsExpanded] = useState(false);
// isDisclosureExpanded controls visibility of the controls panel (Deps, Models, etc.)
const [isDisclosureExpanded, setIsDisclosureExpanded] = useState(() => {
if (typeof window !== "undefined") {
const saved = localStorage.getItem(DISCLOSURE_STORAGE_KEY);
// Default to true (expanded) for backward compatibility - only collapse if explicitly set to "false"
return saved !== "false";
}
return true;
});
const textareaRef = useRef<HTMLTextAreaElement>(null);
const justResetRef = useRef(false);
@@ -139,6 +150,13 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
}
}, [description]);
// Persist disclosure state to localStorage whenever it changes
useEffect(() => {
if (typeof window !== "undefined") {
localStorage.setItem(DISCLOSURE_STORAGE_KEY, isDisclosureExpanded.toString());
}
}, [isDisclosureExpanded]);
// Cleanup on unmount
useEffect(() => {
return () => {
@@ -206,7 +224,8 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
setIsModelModalOpen(false);
setIsRefineMenuOpen(false);
setIsRefining(false);
setIsExpanded(false); // Collapse on reset
setIsExpanded(false); // Collapse textarea height on reset
// Note: isDisclosureExpanded is NOT reset - user preference persists
justResetRef.current = true;
if (textareaRef.current) {
textareaRef.current.style.height = "auto";
@@ -292,8 +311,9 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
localStorage.removeItem(STORAGE_KEY);
}
}
// Collapse on escape
// Collapse textarea and disclosure on escape
setIsExpanded(false);
setIsDisclosureExpanded(false);
textareaRef.current?.blur();
}
},
@@ -304,6 +324,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
showDeps,
isModelModalOpen,
isRefineMenuOpen,
setIsDisclosureExpanded,
],
);
@@ -427,15 +448,16 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
}
}, [availableModels]);
// Show expanded controls only when manually expanded (isExpanded)
const showExpandedControls = isExpanded;
// Show expanded controls based on disclosure state (user preference), not textarea focus
const showExpandedControls = isDisclosureExpanded;
const toggleExpanded = useCallback(() => {
setIsDisclosureExpanded((prev) => !prev);
setIsExpanded((prev) => !prev);
}, []);
return (
<div className={`quick-entry-box ${isExpanded ? "quick-entry-box--expanded" : "quick-entry-box--collapsed"}`} data-testid="quick-entry-box">
<div className={`quick-entry-box ${isDisclosureExpanded ? "quick-entry-box--expanded" : "quick-entry-box--collapsed"}`} data-testid="quick-entry-box">
<div className="quick-entry-main-row">
<textarea
ref={textareaRef}
@@ -455,12 +477,12 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
type="button"
className="btn btn-sm quick-entry-toggle"
onClick={toggleExpanded}
aria-expanded={isExpanded}
aria-expanded={isDisclosureExpanded}
aria-controls="quick-entry-controls"
data-testid="quick-entry-toggle"
title={isExpanded ? "Collapse" : "Expand"}
title={isDisclosureExpanded ? "Collapse" : "Expand"}
>
{isExpanded ? <ChevronUp size={14} /> : <ChevronDown size={14} />}
{isDisclosureExpanded ? <ChevronUp size={14} /> : <ChevronDown size={14} />}
</button>
</div>
{showExpandedControls && (