From 5b5e9220697a3d80cadde04df5e4ec4e5fac79cf Mon Sep 17 00:00:00 2001 From: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com> Date: Thu, 27 Aug 2026 15:57:15 +0000 Subject: [PATCH] Make the upgrade banner neutral instead of gradient purple (#7696) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What The `promo` banner tone was a full-bleed `indigo-500 → purple-500` gradient with white text and a black drop-shadow on the CTA. It was the only saturated fill in the app, and against the warm neutral palette it read as a foreign object above the workbench. The bar is now app chrome: | | Before | After | |---|---|---| | Background | 135° indigo→purple gradient | `--c-bg-raised` | | Border | `transparent` | `--c-border-subtle` hairline | | Icon | white glyph, no container | neutral glyph in a `--c-surface-sunken` chip | | Text | forced white | `--c-text` / `--c-text-muted` | | CTA | `premium` accent (violet gradient) | `default` accent (same primary button as the rest of the app) | Before Screenshot 2026-08-27 at 4 49 00 PM After Screenshot 2026-08-27 at 4 48 30 PM Only caller is the friendly variant of `UpgradeBanner` (self-hosted, under the free-tier user limit). ## Notes - **No new theme tokens.** Every value is an existing `--c-*` semantic token, so light and dark both follow automatically with no per-theme overrides. - The `premium` accent itself is untouched, so the upgrade CTAs in `OfflineActivationCard` and `PairingPanel` are unaffected. - `--c-hue-indigo` / `--c-hue-purple` are still used by `SaaSOnboardingSlides`, `PaygFree` and `UpgradeModal`, so no tokens are orphaned. - Deleted comments describe rules that no longer exist (the gradient, the white-on-gradient text overrides, the CTA shadow). No new comments added. ## Verification - `task frontend:check:all` passes (typecheck, oxlint, all four theme linters, stylelint, format, tests, build, storybook build). - `task frontend:storybook:a11y:changed` passes light and dark: 7 AppBanner stories, 0 violations. Both a11y baselines are empty, so this is zero known violations rather than a baselined pass. - Checked in Storybook under **Shared / AppBanner → All Top Bars**, which renders every top bar the app can show side by side, in both themes. --- .../src/core/components/shared/AppBanner.css | 31 ++++++++----------- .../src/core/components/shared/AppBanner.tsx | 2 +- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/frontend/editor/src/core/components/shared/AppBanner.css b/frontend/editor/src/core/components/shared/AppBanner.css index b3f3f9343a..8151fe916a 100644 --- a/frontend/editor/src/core/components/shared/AppBanner.css +++ b/frontend/editor/src/core/components/shared/AppBanner.css @@ -24,17 +24,10 @@ --app-banner-icon: var(--c-accent-fg, var(--c-primary)); } -/* The one bar meant to pop, so it takes the feature gradient rather than a tint. - Fixed hues by design — it doesn't follow the chosen accent. */ .app-banner--promo { - --app-banner-bg: linear-gradient( - 135deg, - var(--c-hue-indigo) 0%, - var(--c-hue-purple) 100% - ); - --app-banner-border: transparent; - --app-banner-icon: var(--color-text-on-accent); - color: var(--color-text-on-accent); + --app-banner-bg: var(--c-bg-raised); + --app-banner-border: var(--c-border-subtle); + --app-banner-icon: var(--c-text-muted); } .app-banner--warning { @@ -86,16 +79,18 @@ font-size: 0.75rem; } -/* On the gradient everything is white; muted grey would disappear. */ -.app-banner--promo .app-banner__message, -.app-banner--promo .app-banner__actions .sui-btn--tertiary, -.app-banner--promo .app-banner__actions .sui-ai { - color: var(--color-text-on-accent); +.app-banner--promo .app-banner__icon { + width: 1.75rem; + height: 1.75rem; + justify-content: center; + border-radius: var(--radius-md); + background: var(--c-surface-sunken); + box-shadow: inset 0 0 0 1px var(--c-border-subtle); } -/* Lifts the premium CTA off the gradient it sits on. */ -.app-banner--promo .app-banner__actions .sui-btn--primary { - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); +.app-banner--promo.app-banner--compact .app-banner__icon { + width: 1.5rem; + height: 1.5rem; } .app-banner__actions { diff --git a/frontend/editor/src/core/components/shared/AppBanner.tsx b/frontend/editor/src/core/components/shared/AppBanner.tsx index ee0ba03741..79ff268dd2 100644 --- a/frontend/editor/src/core/components/shared/AppBanner.tsx +++ b/frontend/editor/src/core/components/shared/AppBanner.tsx @@ -11,7 +11,7 @@ export type AppBannerTone = "info" | "promo" | "warning" | "danger"; /** Tone decides the button too, so the CTA can't drift from the bar it sits on. */ const TONE_BUTTON = { info: { variant: "secondary", accent: "default" }, - promo: { variant: "primary", accent: "premium" }, + promo: { variant: "primary", accent: "default" }, warning: { variant: "primary", accent: "warning" }, danger: { variant: "primary", accent: "danger" }, } as const;