From 168bb87bd3426bdd507414afb44e58d531ff8704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=85=E5=87=A4?= Date: Thu, 30 Jul 2026 19:59:30 +0800 Subject: [PATCH 1/2] fix(callout-banner): preserve tone on clickable hover Replace hover:bg-accent with tone-aware color-mix rules so destructive and warning banners stay in their soft fill family on hover. --- src/components/callout-banner/index.vue | 11 +++++++---- src/style.css | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/components/callout-banner/index.vue b/src/components/callout-banner/index.vue index e23abd6..9952d9e 100644 --- a/src/components/callout-banner/index.vue +++ b/src/components/callout-banner/index.vue @@ -10,6 +10,9 @@ @@ -79,8 +82,8 @@ const iconClass = computed(() => props.tone === 'destructive' ? 'text-destructive' : 'text-warning-foreground', ) -// When the whole banner is the affordance, it gets the neutral overlay hover the -// rest of the app's clickable surfaces use — the tile's own chrome, not a page -// injection. -const interactiveClass = 'w-full transition-colors hover:bg-accent' /* ui-allow-style */ +// When the whole banner is the affordance, hover stays in the same tone family +// (see [data-slot="callout-banner"] rules in style.css) — not hover:bg-accent, +// which replaced destructive/warning fills with neutral gray. +const interactiveClass = 'w-full cursor-pointer' diff --git a/src/style.css b/src/style.css index 4c4137a..0c233f5 100644 --- a/src/style.css +++ b/src/style.css @@ -594,6 +594,21 @@ :is(button, a)[data-slot="action-card"]:active::before { background-color: var(--action-card-active); } + + /* ── CalloutBanner — clickable hover must stay in the banner's tone ───────── + hover:bg-accent replaced destructive/warning soft fills with neutral gray. + Intensify the same soft/border pair instead. */ + :is(button)[data-slot="callout-banner"][data-clickable] { + transition: background-color 15ms ease, border-color 15ms ease; + } + :is(button)[data-slot="callout-banner"][data-clickable][data-tone="destructive"]:hover { + background-color: color-mix(in oklab, var(--destructive) 8%, transparent); + border-color: color-mix(in oklab, var(--destructive) 36%, transparent); + } + :is(button)[data-slot="callout-banner"][data-clickable][data-tone="warning"]:hover { + background-color: color-mix(in oklab, var(--warning-foreground) 10%, var(--warning-soft)); + border-color: color-mix(in oklab, var(--warning-foreground) 22%, var(--warning-border)); + } } @keyframes button-spin { From e95223273e2d502e92b694efc88392ad04d8940f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=85=E5=87=A4?= Date: Thu, 30 Jul 2026 20:05:06 +0800 Subject: [PATCH 2/2] fix(callout-banner): visible tone-preserving hover via soft-hover tokens @Component-layer :hover lost to Tailwind bg utilities. Register *-soft-hover tokens and apply hover:bg-*-soft-hover on clickable banners. --- src/components/callout-banner/index.vue | 20 ++++++++++++++------ src/style.css | 23 ++++++++--------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/components/callout-banner/index.vue b/src/components/callout-banner/index.vue index 9952d9e..042c26b 100644 --- a/src/components/callout-banner/index.vue +++ b/src/components/callout-banner/index.vue @@ -71,12 +71,20 @@ const props = withDefaults(defineProps<{ }) // Full literal class strings per tone — Tailwind scans source text, so a runtime -// concat would never be generated. Both tones now use a soft-token triplet. -const toneClass = computed(() => - props.tone === 'destructive' - ? 'border-destructive-border bg-destructive-soft' - : 'border-warning-border bg-warning-soft', -) +// concat would never be generated. Clickable hover uses the *-soft-hover tokens +// (utilities layer) so the wash is visible and stays in the same tone family. +const toneClass = computed(() => { + if (props.tone === 'destructive') { + const rest = 'border-destructive-border bg-destructive-soft' + return props.clickable + ? `${rest} transition-colors hover:bg-destructive-soft-hover hover:border-destructive-border-hover` + : rest + } + const rest = 'border-warning-border bg-warning-soft' + return props.clickable + ? `${rest} transition-colors hover:bg-warning-soft-hover hover:border-warning-border-hover` + : rest +}) const iconClass = computed(() => props.tone === 'destructive' ? 'text-destructive' : 'text-warning-foreground', diff --git a/src/style.css b/src/style.css index 0c233f5..d6d0011 100644 --- a/src/style.css +++ b/src/style.css @@ -594,21 +594,6 @@ :is(button, a)[data-slot="action-card"]:active::before { background-color: var(--action-card-active); } - - /* ── CalloutBanner — clickable hover must stay in the banner's tone ───────── - hover:bg-accent replaced destructive/warning soft fills with neutral gray. - Intensify the same soft/border pair instead. */ - :is(button)[data-slot="callout-banner"][data-clickable] { - transition: background-color 15ms ease, border-color 15ms ease; - } - :is(button)[data-slot="callout-banner"][data-clickable][data-tone="destructive"]:hover { - background-color: color-mix(in oklab, var(--destructive) 8%, transparent); - border-color: color-mix(in oklab, var(--destructive) 36%, transparent); - } - :is(button)[data-slot="callout-banner"][data-clickable][data-tone="warning"]:hover { - background-color: color-mix(in oklab, var(--warning-foreground) 10%, var(--warning-soft)); - border-color: color-mix(in oklab, var(--warning-foreground) 22%, var(--warning-border)); - } } @keyframes button-spin { @@ -1104,6 +1089,8 @@ call sites (see --muted-soft above for why color-mix, not a literal). */ --destructive-soft: color-mix(in oklab, var(--destructive) 5%, transparent); --destructive-border: color-mix(in oklab, var(--destructive) 30%, transparent); + --destructive-soft-hover: color-mix(in oklab, var(--destructive) 14%, transparent); + --destructive-border-hover: color-mix(in oklab, var(--destructive) 45%, transparent); --border: oklch(0.915 0.0045 72); /* Alpha policy: the soft/faint divider and card-edge rung — same color-mix reasoning as --muted-soft/--destructive-soft, reproducing `border-border/60` @@ -1402,6 +1389,8 @@ --warning-solid-foreground: oklch(0.18 0.02 75); --warning-soft: oklch(0.97 0.045 80); --warning-border: oklch(0.86 0.10 80); + --warning-soft-hover: color-mix(in oklab, var(--warning-foreground) 16%, var(--warning-soft)); + --warning-border-hover: color-mix(in oklab, var(--warning-foreground) 30%, var(--warning-border)); --info: oklch(0.62 0.15 235); --info-foreground: oklch(0.36 0.12 235); --info-soft: oklch(0.96 0.035 235); @@ -1969,6 +1958,8 @@ --color-destructive-foreground: var(--destructive-foreground); --color-destructive-soft: var(--destructive-soft); --color-destructive-border: var(--destructive-border); + --color-destructive-soft-hover: var(--destructive-soft-hover); + --color-destructive-border-hover: var(--destructive-border-hover); --color-border: var(--border); --color-border-soft: var(--border-soft); --color-input: var(--input); @@ -2051,6 +2042,8 @@ --color-warning-solid-foreground: var(--warning-solid-foreground); --color-warning-soft: var(--warning-soft); --color-warning-border: var(--warning-border); + --color-warning-soft-hover: var(--warning-soft-hover); + --color-warning-border-hover: var(--warning-border-hover); --color-info: var(--info); --color-info-foreground: var(--info-foreground); --color-info-soft: var(--info-soft);