mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-08-26 04:56:36 +00:00
fix(ui): keep white on the destructive fill readable in both themes
Four states were under AA, not one: the dark badge and button at rest (3.71), the light badge on hover (4.34) and the dark button on hover (4.40), plus the dark destructive menu item (4.01). Badge and button had also drifted apart — one faded to 80% on hover, the other to 90% — so each failed in a different theme. The token itself cannot be retuned: sweeping its lightness finds no value that serves both roles, because the same red is a fill under white text and the text colour on the page. Darkening it for the fill would break the twenty-four text-destructive call sites. Tune the fill's opacity per theme instead, keeping white text and adding no tokens. A translucent red composites toward what is behind it, so the same fade darkens it on the dark ground and lightens it on the light one: full strength on light fading to 90% on hover, 80% on dark dropping to 70%. Hover now raises contrast in both themes. All four states land between 5.04 and 6.28, verified on a built bundle against every dark surface token (worst case 5.13 on secondary). The dark destructive menu item drops its focus wash from 20% to 10%, matching light and restoring the label to 4.52 at the cost of a fainter highlight. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
f88427c264
commit
9f40102d6a
@@ -18,7 +18,12 @@ const badgeVariants = cva(
|
||||
variant: {
|
||||
blue: 'border-blue-500/20 bg-blue-500/10 text-blue-700 hover:bg-blue-500/20 dark:text-blue-400',
|
||||
default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
|
||||
destructive: 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
|
||||
// The dark fill is translucent on purpose: composited over the dark
|
||||
// ground it darkens the red, which is what keeps the white foreground
|
||||
// above AA (opaque it measures 3.71). Alphas differ per theme because
|
||||
// the same fade lightens the red over a white ground.
|
||||
destructive:
|
||||
'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/90 dark:bg-destructive/80 dark:hover:bg-destructive/70',
|
||||
green: 'border-green-500/20 bg-green-500/10 text-green-800 hover:bg-green-500/20 dark:text-green-400',
|
||||
orange: 'border-orange-500/20 bg-orange-500/10 text-orange-700 hover:bg-orange-500/20 dark:text-orange-400',
|
||||
outline: 'text-foreground',
|
||||
|
||||
@@ -24,7 +24,11 @@ const buttonVariants = cva(
|
||||
},
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground shadow-sm hover:bg-primary/90',
|
||||
destructive: 'bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90',
|
||||
// Translucent dark fill on purpose — over the dark ground it darkens
|
||||
// the red, keeping the white foreground above AA (opaque it is 3.71).
|
||||
// Mirrors the destructive Badge; keep the two in step.
|
||||
destructive:
|
||||
'bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90 dark:bg-destructive/80 dark:hover:bg-destructive/70',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
outline: 'border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground',
|
||||
|
||||
@@ -75,7 +75,7 @@ function ContextMenuItem({
|
||||
return (
|
||||
<ContextMenuPrimitive.Item
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/10 relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
|
||||
@@ -81,7 +81,7 @@ function DropdownMenuItem({
|
||||
return (
|
||||
<DropdownMenuPrimitive.Item
|
||||
className={cn(
|
||||
'focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
'focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/10 relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0',
|
||||
inset && 'pl-8',
|
||||
className,
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user