Fix minor dark mode issues and language/theme selection alignement

This commit is contained in:
2026-02-02 11:21:20 +00:00
parent 3e3ca3621c
commit 8e74fe576f
4 changed files with 177 additions and 161 deletions

View File

@@ -144,6 +144,8 @@ const MedPlanAssistant = () => {
onAccept={handleAcceptDisclaimer} onAccept={handleAcceptDisclaimer}
currentLanguage={currentLanguage} currentLanguage={currentLanguage}
onLanguageChange={changeLanguage} onLanguageChange={changeLanguage}
currentTheme={uiSettings.theme || 'system'}
onThemeChange={(theme: 'light' | 'dark' | 'system') => updateUiSetting('theme', theme)}
t={t} t={t}
/> />
@@ -166,162 +168,162 @@ const MedPlanAssistant = () => {
<div className="max-w-7xl mx-auto"> <div className="max-w-7xl mx-auto">
<header className="mb-8"> <header className="mb-8">
<div className="flex justify-between items-start gap-4"> <div className="flex justify-between items-start gap-4">
<div> <div className="">
<h1 className="text-3xl md:text-4xl font-bold tracking-tight">{t('appTitle')}</h1> <h1 className="text-3xl md:text-4xl font-bold tracking-tight">{t('appTitle')}</h1>
</div>
<div className="flex flex-wrap-reverse gap-2 justify-end">
<ThemeSelector
currentTheme={uiSettings.theme || 'system'}
onThemeChange={(theme: 'light' | 'dark' | 'system') => updateUiSetting('theme', theme)}
t={t}
/>
<LanguageSelector currentLanguage={currentLanguage} onLanguageChange={changeLanguage} t={t} />
</div>
</div> </div>
<div className="flex flex-wrap gap-2 justify-end"> <p className="text-muted-foreground mt-1">{t('appSubtitle')}</p>
<ThemeSelector </header>
currentTheme={uiSettings.theme || 'system'}
onThemeChange={(theme: 'light' | 'dark' | 'system') => updateUiSetting('theme', theme)} <div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
{/* Both Columns - Chart */}
<div className={`xl:col-span-2 bg-card p-6 rounded-lg border min-h-[600px] flex flex-col ${uiSettings.stickyChart ? 'sticky top-2 z-30 shadow-lg' : ''}`}
style={uiSettings.stickyChart ? { borderColor: 'hsl(var(--primary))' } : {}}>
<div className="flex flex-wrap items-center gap-3 justify-between mb-4">
<div className="flex flex-wrap justify-center gap-2">
<Tooltip>
<TooltipTrigger asChild>
<Button
onClick={() => updateUiSetting('chartView', 'damph')}
variant={chartView === 'damph' ? 'default' : 'secondary'}
>
{t(useCompactButtons ? 'dAmphetamineShort' : 'dAmphetamine')}
</Button>
</TooltipTrigger>
<TooltipContent>
<p className="text-xs max-w-xs">{t('chartViewDamphTooltip')}</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
onClick={() => updateUiSetting('chartView', 'ldx')}
variant={chartView === 'ldx' ? 'default' : 'secondary'}
>
{t(useCompactButtons ? 'lisdexamfetamineShort' : 'lisdexamfetamine')}
</Button>
</TooltipTrigger>
<TooltipContent>
<p className="text-xs max-w-xs">{t('chartViewLdxTooltip')}</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
onClick={() => updateUiSetting('chartView', 'both')}
variant={chartView === 'both' ? 'default' : 'secondary'}
>
{t('both')}
</Button>
</TooltipTrigger>
<TooltipContent>
<p className="text-xs max-w-xs">{t('chartViewBothTooltip')}</p>
</TooltipContent>
</Tooltip>
</div>
<IconButtonWithTooltip
onClick={() => updateUiSetting('stickyChart', !uiSettings.stickyChart)}
icon={uiSettings.stickyChart ? <Pin size={16} /> : <PinOff size={16} />}
tooltip={uiSettings.stickyChart ? t('unpinChart') : t('pinChart')}
variant={uiSettings.stickyChart ? 'default' : 'outline'}
size="sm"
className="shrink-0"
/>
</div>
<SimulationChart
combinedProfile={combinedProfile}
templateProfile={showTemplateDay ? templateProfile : null}
chartView={chartView}
showDayTimeOnXAxis={showDayTimeOnXAxis}
showDayReferenceLines={showDayReferenceLines}
showTherapeuticRange={uiSettings.showTherapeuticRange ?? true}
therapeuticRange={therapeuticRange}
simulationDays={simulationDays}
displayedDays={displayedDays}
yAxisMin={yAxisMin}
yAxisMax={yAxisMax}
days={days}
t={t} t={t}
/> />
<LanguageSelector currentLanguage={currentLanguage} onLanguageChange={changeLanguage} t={t} />
</div> </div>
</div>
<p className="text-muted-foreground mt-1">{t('appSubtitle')}</p>
</header>
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6"> {/* Left Column - Controls */}
<div className="xl:col-span-1 space-y-6">
{/* Both Columns - Chart */} <DaySchedule
<div className={`xl:col-span-2 bg-card p-6 rounded-lg border min-h-[600px] flex flex-col ${uiSettings.stickyChart ? 'sticky top-2 z-30 shadow-lg' : ''}`} days={days}
style={uiSettings.stickyChart ? { borderColor: 'hsl(var(--primary))' } : {}}> doseIncrement={doseIncrement}
<div className="flex flex-wrap items-center gap-3 justify-between mb-4"> onAddDay={addDay}
<div className="flex flex-wrap justify-center gap-2"> onRemoveDay={removeDay}
<Tooltip> onAddDose={addDoseToDay}
<TooltipTrigger asChild> onRemoveDose={removeDoseFromDay}
<Button onUpdateDose={updateDoseInDay}
onClick={() => updateUiSetting('chartView', 'damph')} onUpdateDoseField={updateDoseFieldInDay}
variant={chartView === 'damph' ? 'default' : 'secondary'} onSortDoses={sortDosesInDay}
> t={t}
{t(useCompactButtons ? 'dAmphetamineShort' : 'dAmphetamine')}
</Button>
</TooltipTrigger>
<TooltipContent>
<p className="text-xs max-w-xs">{t('chartViewDamphTooltip')}</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
onClick={() => updateUiSetting('chartView', 'ldx')}
variant={chartView === 'ldx' ? 'default' : 'secondary'}
>
{t(useCompactButtons ? 'lisdexamfetamineShort' : 'lisdexamfetamine')}
</Button>
</TooltipTrigger>
<TooltipContent>
<p className="text-xs max-w-xs">{t('chartViewLdxTooltip')}</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
onClick={() => updateUiSetting('chartView', 'both')}
variant={chartView === 'both' ? 'default' : 'secondary'}
>
{t('both')}
</Button>
</TooltipTrigger>
<TooltipContent>
<p className="text-xs max-w-xs">{t('chartViewBothTooltip')}</p>
</TooltipContent>
</Tooltip>
</div>
<IconButtonWithTooltip
onClick={() => updateUiSetting('stickyChart', !uiSettings.stickyChart)}
icon={uiSettings.stickyChart ? <Pin size={16} /> : <PinOff size={16} />}
tooltip={uiSettings.stickyChart ? t('unpinChart') : t('pinChart')}
variant={uiSettings.stickyChart ? 'default' : 'outline'}
size="sm"
className="shrink-0"
/> />
</div> </div>
<SimulationChart {/* Right Column - Settings */}
combinedProfile={combinedProfile} <div className="xl:col-span-1 space-y-6">
templateProfile={showTemplateDay ? templateProfile : null} <Settings
chartView={chartView} pkParams={pkParams}
showDayTimeOnXAxis={showDayTimeOnXAxis} therapeuticRange={therapeuticRange}
showDayReferenceLines={showDayReferenceLines} uiSettings={uiSettings}
showTherapeuticRange={uiSettings.showTherapeuticRange ?? true} days={days}
therapeuticRange={therapeuticRange} doseIncrement={doseIncrement}
simulationDays={simulationDays} onUpdatePkParams={(key: any, value: any) => updateNestedState('pkParams', key, value)}
displayedDays={displayedDays} onUpdateTherapeuticRange={(key: any, value: any) => updateNestedState('therapeuticRange', key, value)}
yAxisMin={yAxisMin} onUpdateUiSetting={updateUiSetting}
yAxisMax={yAxisMax} onReset={handleReset}
days={days} onImportDays={(importedDays: any) => updateState('days', importedDays)}
t={t} onOpenDataManagement={() => setShowDataManagement(true)}
/> t={t}
</div> />
{/* Left Column - Controls */}
<div className="xl:col-span-1 space-y-6">
<DaySchedule
days={days}
doseIncrement={doseIncrement}
onAddDay={addDay}
onRemoveDay={removeDay}
onAddDose={addDoseToDay}
onRemoveDose={removeDoseFromDay}
onUpdateDose={updateDoseInDay}
onUpdateDoseField={updateDoseFieldInDay}
onSortDoses={sortDosesInDay}
t={t}
/>
</div>
{/* Right Column - Settings */}
<div className="xl:col-span-1 space-y-6">
<Settings
pkParams={pkParams}
therapeuticRange={therapeuticRange}
uiSettings={uiSettings}
days={days}
doseIncrement={doseIncrement}
onUpdatePkParams={(key: any, value: any) => updateNestedState('pkParams', key, value)}
onUpdateTherapeuticRange={(key: any, value: any) => updateNestedState('therapeuticRange', key, value)}
onUpdateUiSetting={updateUiSetting}
onReset={handleReset}
onImportDays={(importedDays: any) => updateState('days', importedDays)}
onOpenDataManagement={() => setShowDataManagement(true)}
t={t}
/>
</div>
</div>
<footer className="mt-8 p-4 bg-muted rounded-lg text-sm text-muted-foreground border">
<div className="space-y-3">
<div>
<h3 className="font-semibold mb-2 text-foreground">{t('importantNote')}</h3>
<p>{t('disclaimer')}</p>
</div> </div>
<div className="flex items-center justify-between">
<Button </div>
variant="outline"
size="sm" <footer className="mt-8 p-4 bg-muted rounded-lg text-sm text-muted-foreground border">
onClick={handleOpenDisclaimer} <div className="space-y-3">
> <div>
{t('disclaimerModalFooterLink')} <h3 className="font-semibold mb-2 text-foreground">{t('importantNote')}</h3>
</Button> <p>{t('disclaimer')}</p>
<div className="flex items-center gap-3"> </div>
<span className="text-xs text-muted-foreground" title={`Version: ${APP_VERSION}${APP_VERSION.endsWith('-dirty') ? ' (uncommitted changes)' : ''}`}> <div className="flex items-center justify-between">
v{APP_VERSION} <Button
</span> variant="outline"
<a size="sm"
href={PROJECT_REPOSITORY_URL} onClick={handleOpenDisclaimer}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center w-8 h-8 rounded-md hover:bg-accent text-foreground hover:text-accent-foreground transition-colors"
title={t('footerProjectRepo')}
> >
<GitBranch size={18} /> {t('disclaimerModalFooterLink')}
</a> </Button>
<div className="flex items-center gap-3">
<span className="text-xs text-muted-foreground" title={`Version: ${APP_VERSION}${APP_VERSION.endsWith('-dirty') ? ' (uncommitted changes)' : ''}`}>
v{APP_VERSION}
</span>
<a
href={PROJECT_REPOSITORY_URL}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center w-8 h-8 rounded-md hover:bg-accent text-foreground hover:text-accent-foreground transition-colors"
title={t('footerProjectRepo')}
>
<GitBranch size={18} />
</a>
</div>
</div> </div>
</div> </div>
</div> </footer>
</footer>
</div> </div>
</div> </div>
</TooltipProvider> </TooltipProvider>

View File

@@ -152,7 +152,7 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
> >
<Badge <Badge
variant="outline" variant="outline"
className={`text-xs ${doseCountDiff > 0 ? 'bg-blue-50' : 'bg-orange-50'}`} className={`text-xs ${doseCountDiff > 0 ? 'bg-blue-100 dark:bg-blue-900/40 dark:text-blue-200' : 'bg-orange-100 dark:bg-orange-900/40 dark:text-orange-200'}`}
> >
{doseCountDiff > 0 ? <TrendingUp className="h-3 w-3 inline mr-1" /> : <TrendingDown className="h-3 w-3 inline mr-1" />} {doseCountDiff > 0 ? <TrendingUp className="h-3 w-3 inline mr-1" /> : <TrendingDown className="h-3 w-3 inline mr-1" />}
{day.doses.length} {day.doses.length === 1 ? t('dose') : t('doses')} {day.doses.length} {day.doses.length === 1 ? t('dose') : t('doses')}
@@ -179,7 +179,7 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
> >
<Badge <Badge
variant="outline" variant="outline"
className={`text-xs ${totalMgDiff > 0 ? 'bg-blue-50' : 'bg-orange-50'}`} className={`text-xs ${totalMgDiff > 0 ? 'bg-blue-100 dark:bg-blue-900/40 dark:text-blue-200' : 'bg-orange-100 dark:bg-orange-900/40 dark:text-orange-200'}`}
> >
{totalMgDiff > 0 ? <TrendingUp className="h-3 w-3 inline mr-1" /> : <TrendingDown className="h-3 w-3 inline mr-1" />} {totalMgDiff > 0 ? <TrendingUp className="h-3 w-3 inline mr-1" /> : <TrendingDown className="h-3 w-3 inline mr-1" />}
{day.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0).toFixed(1)} mg {day.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0).toFixed(1)} mg

View File

@@ -13,6 +13,7 @@ import React, { useState } from 'react';
import { Button } from './ui/button'; import { Button } from './ui/button';
import { Card, CardContent, CardHeader, CardTitle } from './ui/card'; import { Card, CardContent, CardHeader, CardTitle } from './ui/card';
import LanguageSelector from './language-selector'; import LanguageSelector from './language-selector';
import ThemeSelector from './theme-selector';
import { PROJECT_REPOSITORY_URL } from '../constants/defaults'; import { PROJECT_REPOSITORY_URL } from '../constants/defaults';
interface DisclaimerModalProps { interface DisclaimerModalProps {
@@ -20,6 +21,8 @@ interface DisclaimerModalProps {
onAccept: () => void; onAccept: () => void;
currentLanguage: string; currentLanguage: string;
onLanguageChange: (lang: string) => void; onLanguageChange: (lang: string) => void;
currentTheme?: 'light' | 'dark' | 'system';
onThemeChange?: (theme: 'light' | 'dark' | 'system') => void;
t: (key: string) => string; t: (key: string) => string;
} }
@@ -28,6 +31,8 @@ const DisclaimerModal: React.FC<DisclaimerModalProps> = ({
onAccept, onAccept,
currentLanguage, currentLanguage,
onLanguageChange, onLanguageChange,
currentTheme = 'system',
onThemeChange,
t t
}) => { }) => {
const [sourcesExpanded, setSourcesExpanded] = useState(false); const [sourcesExpanded, setSourcesExpanded] = useState(false);
@@ -44,15 +49,24 @@ const DisclaimerModal: React.FC<DisclaimerModalProps> = ({
<CardTitle className="text-2xl font-bold"> <CardTitle className="text-2xl font-bold">
{t('disclaimerModalTitle')} {t('disclaimerModalTitle')}
</CardTitle> </CardTitle>
<p className="text-center text-muted-foreground mt-2"> <p className="text-left text-muted-foreground mt-2">
{t('disclaimerModalSubtitle')} {t('disclaimerModalSubtitle')}
</p> </p>
</div> </div>
<LanguageSelector <div className="flex flex-wrap-reverse gap-2 justify-end">
currentLanguage={currentLanguage} {onThemeChange && (
onLanguageChange={onLanguageChange} <ThemeSelector
t={t} currentTheme={currentTheme}
/> onThemeChange={onThemeChange}
t={t}
/>
)}
<LanguageSelector
currentLanguage={currentLanguage}
onLanguageChange={onLanguageChange}
t={t}
/>
</div>
</div> </div>
</CardHeader> </CardHeader>
<CardContent className="space-y-6 pt-6"> <CardContent className="space-y-6 pt-6">

View File

@@ -327,12 +327,12 @@ const chartDomain = React.useMemo(() => {
<UiTooltip> <UiTooltip>
<UiTooltipTrigger asChild> <UiTooltipTrigger asChild>
<span <span
className="px-1 py-0.5 rounded-sm bg-white text-black shadow-sm border border-muted truncate inline-block max-w-[100px]" className="px-1 py-0.5 rounded-sm bg-background text-foreground shadow-sm border border-border truncate inline-block max-w-[100px]"
> >
{labelInfo.display} {labelInfo.display}
</span> </span>
</UiTooltipTrigger> </UiTooltipTrigger>
<UiTooltipContent className="bg-white text-black shadow-md border max-w-xs"> <UiTooltipContent className="bg-background text-foreground shadow-md border border-border max-w-xs">
<span className="font-medium">{labelInfo.full}</span> <span className="font-medium">{labelInfo.full}</span>
</UiTooltipContent> </UiTooltipContent>
</UiTooltip> </UiTooltip>
@@ -481,9 +481,9 @@ const chartDomain = React.useMemo(() => {
} }
return ( return (
<div className="recharts-default-tooltip" style={{ margin: 0, padding: 10, backgroundColor: 'rgb(255, 255, 255)', border: '1px solid rgb(204, 204, 204)', whiteSpace: 'nowrap' }}> <div className="bg-background border border-border rounded shadow-lg" style={{ margin: 0, padding: 10, whiteSpace: 'nowrap' }}>
<p className="recharts-tooltip-label" style={{ margin: 0 }}>{t('time')}: {timeLabel}</p> <p className="text-foreground font-medium" style={{ margin: 0 }}>{t('time')}: {timeLabel}</p>
<ul className="recharts-tooltip-item-list" style={{ padding: 0, margin: 0 }}> <ul style={{ padding: 0, margin: 0 }}>
{payload.map((entry: any, index: number) => { {payload.map((entry: any, index: number) => {
const labelInfo = seriesLabels[entry.dataKey] || { display: entry.name, full: entry.name }; const labelInfo = seriesLabels[entry.dataKey] || { display: entry.name, full: entry.name };
const isTemplate = entry.dataKey?.toString().includes('template'); const isTemplate = entry.dataKey?.toString().includes('template');
@@ -493,12 +493,12 @@ const chartDomain = React.useMemo(() => {
return ( return (
<li <li
key={`item-${index}`} key={`item-${index}`}
className="recharts-tooltip-item" className="text-foreground"
style={{ display: 'block', paddingTop: 4, paddingBottom: 4, color: entry.color, opacity }} style={{ display: 'block', paddingTop: 4, paddingBottom: 4, color: entry.color, opacity }}
> >
<span className="recharts-tooltip-item-name" title={labelInfo.full}>{labelInfo.display}</span> <span title={labelInfo.full}>{labelInfo.display}</span>
<span className="recharts-tooltip-item-separator">: </span> <span>: </span>
<span className="recharts-tooltip-item-value">{value} {t('unitNgml')}</span> <span>{value} {t('unitNgml')}</span>
</li> </li>
); );
})} })}