Update various color/style improvements, primarily for error/warn/info bubbles and boxes

This commit is contained in:
2026-02-07 20:06:56 +00:00
parent 651097b3fb
commit 7f8503387c
11 changed files with 247 additions and 29 deletions

View File

@@ -320,7 +320,7 @@ const MedPlanAssistant = () => {
</div>
<footer className="mt-8 p-4 bg-muted rounded-lg text-sm text-muted-foreground border">
<footer className="mt-8 p-4 bg-muted rounded-lg text-sm border">
<div className="space-y-3">
<div>
<h3 className="font-semibold mb-2 text-foreground">{t('importantNote')}</h3>

View File

@@ -843,7 +843,7 @@ const DataManagementModal: React.FC<DataManagementModalProps> = ({
className={`flex items-center gap-2 text-sm ${
jsonValidationMessage.type === 'success'
? 'text-green-600 dark:text-green-400'
: 'text-red-600 dark:text-red-400'
: 'error-text'
}`}
>
{jsonValidationMessage.type === 'success' ? (
@@ -858,7 +858,7 @@ const DataManagementModal: React.FC<DataManagementModalProps> = ({
{jsonValidationMessage.warnings.map((warning, index) => (
<div
key={index}
className="bg-yellow-500 text-white text-xs p-2 rounded-md"
className="warning-bubble text-xs p-2 rounded-md"
>
{warning}
</div>
@@ -909,7 +909,7 @@ const DataManagementModal: React.FC<DataManagementModalProps> = ({
<div className="flex items-center gap-2">
<Trash2 className="h-5 w-5 text-destructive" />
</div>
<h3 className="text-lg font-semibold text-destructive">{t('deleteSpecificData')}</h3>
<h3 className="text-lg font-semibold">{t('deleteSpecificData')}</h3>
<Tooltip>
<TooltipTrigger asChild>
<button
@@ -926,8 +926,8 @@ const DataManagementModal: React.FC<DataManagementModalProps> = ({
</div>
{/* Warning Message */}
<div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-md p-3 text-sm">
<p className="text-yellow-800 dark:text-yellow-200">{t('deleteDataWarning')}</p>
<div className="warning-bg-box rounded-md p-3 text-sm">
<p className="warning-text">{t('deleteDataWarning')}</p>
</div>
<div className="space-y-2">

View File

@@ -135,7 +135,7 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
tooltip={t('removeDay')}
size="sm"
variant="outline"
className="border-destructive text-destructive hover:bg-destructive hover:text-destructive-foreground"
className="text-destructive hover:bg-destructive hover:text-destructive-foreground"
/>
)}
</>
@@ -153,7 +153,7 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
>
<Badge
variant="outline"
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'}`}
className={`text-xs ${doseCountDiff > 0 ? 'bg-blue-100 dark:bg-blue-900/60 dark:text-blue-200' : 'bg-orange-100 dark:bg-orange-900/60 dark:text-orange-200'}`}
>
{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')}
@@ -180,7 +180,7 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
>
<Badge
variant="outline"
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'}`}
className={`text-xs ${totalMgDiff > 0 ? 'bg-blue-100 dark:bg-blue-900/60 dark:text-blue-200' : 'bg-orange-100 dark:bg-orange-900/60 dark:text-orange-200'}`}
>
{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
@@ -291,7 +291,7 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
size="sm"
variant="outline"
disabled={day.isTemplate && day.doses.length === 1}
className="h-9 w-9 p-0 border-destructive text-destructive hover:bg-destructive hover:text-destructive-foreground disabled:border-muted"
className="h-9 w-9 p-0 text-destructive hover:bg-destructive hover:text-destructive-foreground disabled:border-muted"
/>
</div>
</div>

View File

@@ -109,7 +109,7 @@ const DisclaimerModal: React.FC<DisclaimerModalProps> = ({
<span className="text-2xl"></span>
{t('disclaimerModalScheduleII')}
</h3>
<p className="text-sm text-red-800 dark:text-red-300">
<p className="text-sm error-text">
{t('disclaimerModalScheduleIIText')}
</p>
</div>

View File

@@ -772,8 +772,8 @@ const Settings = ({
/>
{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">
<p className="text-yellow-800 dark:text-yellow-200">{t('advancedSettingsWarning')}</p>
<div className="warning-bg-box rounded-md p-3 text-sm">
<p className="warning-text">{t('advancedSettingsWarning')}</p>
</div>
{/* Standard Volume of Distribution */}
@@ -816,7 +816,7 @@ const Settings = ({
</SelectContent>
</FormSelect>
{pkParams.advanced.standardVd?.preset === 'weight-based' && (
<div className="ml-0 mt-2 p-2 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded text-xs text-blue-800 dark:text-blue-200">
<div className="ml-0 mt-2 p-2 info-bg-box rounded text-xs info-text">
{t('weightBasedVdInfo')}
</div>
)}

View File

@@ -206,8 +206,8 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
size="icon"
className={cn(
"h-9 w-9 rounded-r-none border-r-0",
hasError && "border-destructive",
hasWarning && !hasError && "border-yellow-500"
hasError && "error-border",
hasWarning && !hasError && "warning-border"
)}
onClick={() => updateValue(-1)}
disabled={isAtMin}
@@ -227,8 +227,8 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
inputWidth, "h-9 z-10",
"rounded-none",
getAlignmentClass(),
hasError && "border-destructive focus-visible:ring-destructive",
hasWarning && !hasError && "border-yellow-500 focus-visible:ring-yellow-500"
hasError && "error-border focus-visible:ring-destructive",
hasWarning && !hasError && "warning-border focus-visible:ring-amber-500"
)}
{...props}
/>
@@ -239,8 +239,8 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
className={cn(
"h-9 w-9",
showResetButton ? "rounded-l-none rounded-r-none border-x-0" : "rounded-l-none border-l-0",
hasError && "border-destructive",
hasWarning && !hasError && "border-yellow-500"
hasError && "error-border",
hasWarning && !hasError && "warning-border"
)}
onClick={() => updateValue(1)}
disabled={isAtMax}
@@ -257,8 +257,8 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
size="icon"
className={cn(
"h-9 w-9 rounded-l-none",
hasError && "border-destructive",
hasWarning && !hasError && "border-yellow-500"
hasError && "error-border",
hasWarning && !hasError && "warning-border"
)}
onClick={() => onChange(String(defaultValue ?? ''))}
tabIndex={-1}
@@ -267,12 +267,12 @@ const FormNumericInput = React.forwardRef<HTMLInputElement, NumericInputProps>(
</div>
{unit && <span className="text-sm text-muted-foreground whitespace-nowrap">{unit}</span>}
{hasError && isFocused && errorMessage && (
<div className="absolute top-full left-0 mt-1 z-20 w-64 bg-destructive text-destructive-foreground text-xs p-2 rounded-md shadow-lg">
<div className="absolute top-full left-0 mt-1 z-20 w-80 error-bubble text-xs p-2 rounded-md shadow-lg">
{errorMessage}
</div>
)}
{hasWarning && isFocused && warningMessage && (
<div className="absolute top-full left-0 mt-1 z-20 w-48 bg-yellow-500 text-white text-xs p-2 rounded-md shadow-lg">
<div className="absolute top-full left-0 mt-1 z-20 w-80 warning-bubble text-xs p-2 rounded-md shadow-lg">
{warningMessage}
</div>
)}

View File

@@ -38,9 +38,10 @@ export const FormSelect: React.FC<FormSelectProps> = ({
return (
<div className="flex items-center gap-0">
<Select value={value} onValueChange={onValueChange}>
<Select value={value} onValueChange={onValueChange}>
<SelectTrigger className={cn(
showResetButton && "rounded-r-none border-r-0 z-10",
"bg-background",
triggerClassName
)}>
<SelectValue placeholder={placeholder} />

View File

@@ -199,8 +199,8 @@ const FormTimeInput = React.forwardRef<HTMLInputElement, TimeInputProps>(
"w-20 h-9 z-20",
"rounded-r-none",
getAlignmentClass(),
hasError && "border-destructive focus-visible:ring-destructive",
hasWarning && !hasError && "border-yellow-500 focus-visible:ring-yellow-500"
hasError && "error-border focus-visible:ring-destructive",
hasWarning && !hasError && "warning-border focus-visible:ring-amber-500"
)}
{...props}
/>
@@ -289,12 +289,12 @@ const FormTimeInput = React.forwardRef<HTMLInputElement, TimeInputProps>(
</div>
{unit && <span className="text-sm text-muted-foreground whitespace-nowrap">{unit}</span>}
{hasError && isFocused && errorMessage && (
<div className="absolute top-full left-0 mt-1 z-50 w-48 bg-destructive text-destructive-foreground text-xs p-2 rounded-md shadow-lg">
<div className="absolute top-full left-0 mt-1 z-50 w-80 error-bubble text-xs p-2 rounded-md shadow-lg">
{errorMessage}
</div>
)}
{hasWarning && isFocused && warningMessage && (
<div className="absolute top-full left-0 mt-1 z-50 w-48 bg-yellow-500 text-white text-xs p-2 rounded-md shadow-lg">
<div className="absolute top-full left-0 mt-1 z-50 w-80 warning-bubble text-xs p-2 rounded-md shadow-lg">
{warningMessage}
</div>
)}

View File

@@ -48,6 +48,10 @@
--accent-foreground: 0 0% 90%;
--destructive: 0 84% 60%;
--destructive-foreground: 0 0% 98%;
--bubble-error: 0 84% 60%;
--bubble-error-foreground: 0 0% 98%;
--bubble-warning: 42 100% 60%;
--bubble-warning-foreground: 0 0% 98%;
--border: 0 0% 25%;
--input: 0 0% 25%;
--ring: 0 0% 40%;
@@ -68,3 +72,55 @@
font-feature-settings: "rlig" 1, "calt" 1;
}
}
@layer components {
/* Error message bubble - validation popups */
.error-bubble {
@apply bg-[hsl(var(--background))] text-[hsl(var(--foreground))] border border-red-500 dark:border-red-500;
}
/* Warning message bubble - validation popups */
.warning-bubble {
@apply bg-[hsl(var(--background))] text-[hsl(var(--foreground))] border border-amber-500 dark:border-amber-500;
}
/* Error border - for input fields with errors */
.error-border {
@apply !border-red-500;
}
/* Warning border - for input fields with warnings */
.warning-border {
@apply !border-amber-500;
}
/* Error background box - for static error/warning sections */
.error-bg-box {
@apply bg-[hsl(var(--background))] border border-red-500 dark:border-red-500;
}
/* Warning background box - for static warning sections */
.warning-bg-box {
@apply bg-[hsl(var(--background))] border border-amber-500 dark:border-amber-500;
}
/* Info background box - for informational sections */
.info-bg-box {
@apply bg-[hsl(var(--background))] border border-blue-500 dark:border-blue-500;
}
/* Error text - for inline error text */
.error-text {
@apply text-[hsl(var(--foreground))];
}
/* Warning text - for inline warning text */
.warning-text {
@apply text-[hsl(var(--foreground))];
}
/* Info text - for inline info text */
.info-text {
@apply text-[hsl(var(--foreground))];
}
}