Add collapsible-card-header component to consolidate and improve folding

This commit is contained in:
2026-01-16 13:26:30 +00:00
parent 6f6e5d9696
commit e1aaa24186
3 changed files with 219 additions and 118 deletions

View File

@@ -10,15 +10,16 @@
*/
import React from 'react';
import { FormNumericInput } from './ui/form-numeric-input';
import { Card, CardContent, CardHeader, CardTitle } from './ui/card';
import { Button } from './ui/button';
import { Switch } from './ui/switch';
import { Card, CardContent } from './ui/card';
import { Label } from './ui/label';
import { Switch } from './ui/switch';
import { Separator } from './ui/separator';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select';
import { Button } from './ui/button';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/tooltip';
import { ChevronDown, ChevronUp, Info } from 'lucide-react';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select';
import { FormNumericInput } from './ui/form-numeric-input';
import CollapsibleCardHeader from './ui/collapsible-card-header';
import { Info } from 'lucide-react';
import { getDefaultState } from '../constants/defaults';
/**
@@ -124,6 +125,46 @@ const Settings = ({
const [isPharmacokineticExpanded, setIsPharmacokineticExpanded] = React.useState(true);
const [isAdvancedExpanded, setIsAdvancedExpanded] = React.useState(false);
// Load and persist settings card expansion states
React.useEffect(() => {
const savedStates = localStorage.getItem('settingsCardStates_v1');
if (savedStates) {
try {
const states = JSON.parse(savedStates);
if (states.diagram !== undefined) setIsDiagramExpanded(states.diagram);
if (states.simulation !== undefined) setIsSimulationExpanded(states.simulation);
if (states.pharmacokinetic !== undefined) setIsPharmacokineticExpanded(states.pharmacokinetic);
if (states.advanced !== undefined) setIsAdvancedExpanded(states.advanced);
} catch (e) {
console.warn('Failed to load settings card states:', e);
}
}
}, []);
const updateDiagramExpanded = (value: boolean) => {
setIsDiagramExpanded(value);
saveCardStates({ diagram: value, simulation: isSimulationExpanded, pharmacokinetic: isPharmacokineticExpanded, advanced: isAdvancedExpanded });
};
const updateSimulationExpanded = (value: boolean) => {
setIsSimulationExpanded(value);
saveCardStates({ diagram: isDiagramExpanded, simulation: value, pharmacokinetic: isPharmacokineticExpanded, advanced: isAdvancedExpanded });
};
const updatePharmacokineticExpanded = (value: boolean) => {
setIsPharmacokineticExpanded(value);
saveCardStates({ diagram: isDiagramExpanded, simulation: isSimulationExpanded, pharmacokinetic: value, advanced: isAdvancedExpanded });
};
const updateAdvancedExpanded = (value: boolean) => {
setIsAdvancedExpanded(value);
saveCardStates({ diagram: isDiagramExpanded, simulation: isSimulationExpanded, pharmacokinetic: isPharmacokineticExpanded, advanced: value });
};
const saveCardStates = (states: any) => {
localStorage.setItem('settingsCardStates_v1', JSON.stringify(states));
};
// Create defaults object for translation interpolation
const defaultsForT = getDefaultsForTranslation(pkParams, therapeuticRange, uiSettings);
@@ -158,12 +199,11 @@ const Settings = ({
<div className="space-y-4">
{/* Diagram Settings Card */}
<Card>
<CardHeader className="cursor-pointer pb-3" onClick={() => setIsDiagramExpanded(!isDiagramExpanded)}>
<div className="flex items-center justify-between">
<CardTitle className="text-lg">{t('diagramSettings')}</CardTitle>
{isDiagramExpanded ? <ChevronUp className="h-5 w-5" /> : <ChevronDown className="h-5 w-5" />}
</div>
</CardHeader>
<CollapsibleCardHeader
title={t('diagramSettings')}
isCollapsed={!isDiagramExpanded}
onToggle={() => updateDiagramExpanded(!isDiagramExpanded)}
/>
{isDiagramExpanded && (
<CardContent className="space-y-4">
<div className="space-y-3">
@@ -431,12 +471,11 @@ const Settings = ({
{/* Simulation Settings Card */}
<Card>
<CardHeader className="cursor-pointer pb-3" onClick={() => setIsSimulationExpanded(!isSimulationExpanded)}>
<div className="flex items-center justify-between">
<CardTitle className="text-lg">{t('simulationSettings')}</CardTitle>
{isSimulationExpanded ? <ChevronUp className="h-5 w-5" /> : <ChevronDown className="h-5 w-5" />}
</div>
</CardHeader>
<CollapsibleCardHeader
title={t('simulationSettings')}
isCollapsed={!isSimulationExpanded}
onToggle={() => updateSimulationExpanded(!isSimulationExpanded)}
/>
{isSimulationExpanded && (
<CardContent className="space-y-4">
<div className="space-y-2">
@@ -507,12 +546,11 @@ const Settings = ({
{/* Pharmacokinetic Settings Card */}
<Card>
<CardHeader className="cursor-pointer pb-3" onClick={() => setIsPharmacokineticExpanded(!isPharmacokineticExpanded)}>
<div className="flex items-center justify-between">
<CardTitle className="text-lg">{t('pharmacokineticsSettings')}</CardTitle>
{isPharmacokineticExpanded ? <ChevronUp className="h-5 w-5" /> : <ChevronDown className="h-5 w-5" />}
</div>
</CardHeader>
<CollapsibleCardHeader
title={t('pharmacokineticsSettings')}
isCollapsed={!isPharmacokineticExpanded}
onToggle={() => updatePharmacokineticExpanded(!isPharmacokineticExpanded)}
/>
{isPharmacokineticExpanded && (
<CardContent className="space-y-4">
<h3 className="text-lg font-semibold">{t('dAmphetamineParameters')}</h3>
@@ -627,12 +665,11 @@ const Settings = ({
{/* Advanced Settings Card */}
<Card>
<CardHeader className="cursor-pointer pb-3" onClick={() => setIsAdvancedExpanded(!isAdvancedExpanded)}>
<div className="flex items-center justify-between">
<CardTitle className="text-lg">{t('advancedSettings')}</CardTitle>
{isAdvancedExpanded ? <ChevronUp className="h-5 w-5" /> : <ChevronDown className="h-5 w-5" />}
</div>
</CardHeader>
<CollapsibleCardHeader
title={t('advancedSettings')}
isCollapsed={!isAdvancedExpanded}
onToggle={() => updateAdvancedExpanded(!isAdvancedExpanded)}
/>
{isAdvancedExpanded && (
<CardContent className="space-y-4">
<div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-md p-3 text-sm">