From 3e7281e4db9d1532fc9f566f18e89450992ee51c Mon Sep 17 00:00:00 2001 From: Andreas Weyer Date: Sat, 17 Jan 2026 13:06:56 +0000 Subject: [PATCH] Update consolidated and improved tooltips --- src/App.tsx | 39 +++-- src/components/day-schedule.tsx | 162 +++++++++--------- src/components/settings.tsx | 40 +---- src/components/simulation-chart.tsx | 57 +++--- src/components/ui/form-numeric-input.tsx | 10 +- .../ui/icon-button-with-tooltip.tsx | 49 ++++++ 6 files changed, 180 insertions(+), 177 deletions(-) create mode 100644 src/components/ui/icon-button-with-tooltip.tsx diff --git a/src/App.tsx b/src/App.tsx index 74b93be..624a7a8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,6 +19,8 @@ import Settings from './components/settings'; import LanguageSelector from './components/language-selector'; import DisclaimerModal from './components/disclaimer-modal'; import { Button } from './components/ui/button'; +import { TooltipProvider } from './components/ui/tooltip'; +import { IconButtonWithTooltip } from './components/ui/icon-button-with-tooltip'; import { PROJECT_REPOSITORY_URL, APP_VERSION } from './constants/defaults'; // Custom Hooks @@ -100,19 +102,20 @@ const MedPlanAssistant = () => { } = useSimulation(appState); return ( -
- {/* Disclaimer Modal */} - + +
+ {/* Disclaimer Modal */} + -
-
-
+
+
+

{t('appTitle')}

@@ -147,15 +150,14 @@ const MedPlanAssistant = () => { {t('both')}
- + />
{
+
- + ); }; diff --git a/src/components/day-schedule.tsx b/src/components/day-schedule.tsx index 5b94897..126cb81 100644 --- a/src/components/day-schedule.tsx +++ b/src/components/day-schedule.tsx @@ -14,7 +14,8 @@ import { Card, CardContent } from './ui/card'; import { Badge } from './ui/badge'; import { FormTimeInput } from './ui/form-time-input'; import { FormNumericInput } from './ui/form-numeric-input'; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/tooltip'; +import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip'; +import { IconButtonWithTooltip } from './ui/icon-button-with-tooltip'; import CollapsibleCardHeader from './ui/collapsible-card-header'; import { Plus, Copy, Trash2, ArrowDownAZ, TrendingUp, TrendingDown } from 'lucide-react'; import type { DayGroup } from '../constants/defaults'; @@ -116,25 +117,23 @@ const DaySchedule: React.FC = ({ rightSection={ <> {canAddDay && ( - + /> )} {!day.isTemplate && ( - + /> )} } @@ -143,58 +142,54 @@ const DaySchedule: React.FC = ({ {t('day')} {dayIndex + 1} {!day.isTemplate && doseCountDiff !== 0 ? ( - - - - - - -

- {doseCountDiff > 0 ? '+' : ''}{doseCountDiff} {Math.abs(doseCountDiff) === 1 ? t('dose') : t('doses')} {t('comparedToRegularPlan')} -

-
-
-
+ {doseCountDiff > 0 ? : } + {day.doses.length} {day.doses.length === 1 ? t('dose') : t('doses')} + + + + +

+ {doseCountDiff > 0 ? '+' : ''}{doseCountDiff} {Math.abs(doseCountDiff) === 1 ? t('dose') : t('doses')} {t('comparedToRegularPlan')} +

+
+ ) : ( {day.doses.length} {day.doses.length === 1 ? t('dose') : t('doses')} )} {!day.isTemplate && Math.abs(totalMgDiff) > 0.1 ? ( - - - - - - -

- {totalMgDiff > 0 ? '+' : ''}{totalMgDiff.toFixed(1)} mg {t('comparedToRegularPlan')} -

-
-
-
+ {totalMgDiff > 0 ? : } + {day.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0).toFixed(1)} mg + + + + +

+ {totalMgDiff > 0 ? '+' : ''}{totalMgDiff.toFixed(1)} mg {t('comparedToRegularPlan')} +

+
+ ) : ( {day.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0).toFixed(1)} mg @@ -207,31 +202,29 @@ const DaySchedule: React.FC = ({
{t('time')} - - - - - - -

- {isDaySorted(day) ? t('sortByTimeSorted') : t('sortByTimeNeeded')} -

-
-
-
+ + + + + +

+ {isDaySorted(day) ? t('sortByTimeSorted') : t('sortByTimeNeeded')} +

+
+
{t('ldx')} (mg)
@@ -267,16 +260,15 @@ const DaySchedule: React.FC = ({ errorMessage={t('errorNumberRequired')} warningMessage={t('warningZeroDose')} /> - + />
); })} diff --git a/src/components/settings.tsx b/src/components/settings.tsx index f8f9aec..198be09 100644 --- a/src/components/settings.tsx +++ b/src/components/settings.tsx @@ -15,7 +15,7 @@ import { Label } from './ui/label'; import { Switch } from './ui/switch'; import { Separator } from './ui/separator'; import { Button } from './ui/button'; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/tooltip'; +import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select'; import { FormNumericInput } from './ui/form-numeric-input'; import CollapsibleCardHeader from './ui/collapsible-card-header'; @@ -269,7 +269,6 @@ const Settings = ({ - setOpenTooltipId(open ? 'showTemplateDay' : null)}> {clearButton && allowEmpty && ( - + /> )} {unit && {unit}} diff --git a/src/components/ui/icon-button-with-tooltip.tsx b/src/components/ui/icon-button-with-tooltip.tsx new file mode 100644 index 0000000..8551a1e --- /dev/null +++ b/src/components/ui/icon-button-with-tooltip.tsx @@ -0,0 +1,49 @@ +/** + * IconButtonWithTooltip + * + * A reusable button component that combines an icon button with a tooltip. + * Provides consistent tooltip behavior across the app for icon-only action buttons. + * + * @author Andreas Weyer + * @license MIT + */ + +import React from 'react'; +import { Button, ButtonProps } from './button'; +import { Tooltip, TooltipContent, TooltipTrigger } from './tooltip'; + +interface IconButtonWithTooltipProps extends Omit { + /** The icon element to display in the button */ + icon: React.ReactNode; + /** The tooltip text to show on hover */ + tooltip: string; + /** Optional side for tooltip positioning */ + tooltipSide?: 'top' | 'right' | 'bottom' | 'left'; +} + +export const IconButtonWithTooltip: React.FC = ({ + icon, + tooltip, + tooltipSide = 'top', + disabled, + ...buttonProps +}) => { + return ( + + + + + {!disabled && ( + +

{tooltip}

+
+ )} +
+ ); +};