Merge pull request #3773 from bluewave-labs/fix/status-page-brand-color-not-applied
fix(status page): apply brand color via a dedicated brand token
This commit is contained in:
4 files changed
+54
-9
No files matched your search
@@ -142,6 +142,7 @@ const StatusPageView = () => {
|
||||
theme={statusPage.theme}
|
||||
themeMode={statusPage.themeMode}
|
||||
timezone={statusPage.timezone}
|
||||
brandColor={statusPage.color}
|
||||
paintBody
|
||||
>
|
||||
{customCss && <style>{customCss}</style>}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
useState,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import { alpha, darken } from "@mui/material/styles";
|
||||
import {
|
||||
DEFAULT_STATUS_PAGE_THEME,
|
||||
resolveStatusPageTheme,
|
||||
@@ -36,6 +37,15 @@ interface Props {
|
||||
theme?: StatusPageTheme;
|
||||
themeMode?: StatusPageThemeMode;
|
||||
timezone?: string;
|
||||
/**
|
||||
* Brand color picked in the status-page appearance settings. When
|
||||
* provided, it feeds `tokens.brand` / `brandStrong` / `brandSoft`,
|
||||
* which theme styles use for accent surfaces (hero, active tabs,
|
||||
* links). It does NOT recolor the semantic `up`/OK status color, so
|
||||
* a red or orange brand cannot make the "all operational" indicator
|
||||
* signal downtime.
|
||||
*/
|
||||
brandColor?: string;
|
||||
/**
|
||||
* When true, paint the document body with the theme background so it
|
||||
* covers beyond the provider's wrapper (useful on the public route
|
||||
@@ -54,10 +64,32 @@ interface Props {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const HEX_COLOR = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
|
||||
|
||||
// Resolve the brand triple that theme styles read from. A customer's
|
||||
// picked color (when valid) overrides the theme's default; otherwise
|
||||
// the theme's own `brand*` values win, and finally we fall back to the
|
||||
// `up*` triple so unmigrated theme styles have something to consume.
|
||||
const resolveBrandTokens = (
|
||||
tokens: StatusPageThemeTokens,
|
||||
brandColor: string | undefined
|
||||
): StatusPageThemeTokens => {
|
||||
const validOverride = brandColor && HEX_COLOR.test(brandColor) ? brandColor : undefined;
|
||||
const brand = validOverride ?? tokens.brand ?? tokens.up;
|
||||
const brandStrong = validOverride
|
||||
? darken(validOverride, 0.2)
|
||||
: (tokens.brandStrong ?? tokens.upStrong);
|
||||
const brandSoft = validOverride
|
||||
? alpha(validOverride, 0.15)
|
||||
: (tokens.brandSoft ?? tokens.upSoft);
|
||||
return { ...tokens, brand, brandStrong, brandSoft };
|
||||
};
|
||||
|
||||
export const StatusPageThemeProvider = ({
|
||||
theme,
|
||||
themeMode,
|
||||
timezone,
|
||||
brandColor,
|
||||
paintBody = false,
|
||||
transparent = false,
|
||||
children,
|
||||
@@ -109,7 +141,11 @@ export const StatusPageThemeProvider = ({
|
||||
|
||||
const resolvedMode: ResolvedMode =
|
||||
resolvedThemeMode === "auto" ? systemMode : resolvedThemeMode;
|
||||
const tokens = themeTokens[resolvedTheme][resolvedMode];
|
||||
const baseTokens = themeTokens[resolvedTheme][resolvedMode];
|
||||
const tokens = useMemo(
|
||||
() => resolveBrandTokens(baseTokens, brandColor),
|
||||
[baseTokens, brandColor]
|
||||
);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
|
||||
@@ -119,7 +119,7 @@ export const refinedStyles = (
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: "8px",
|
||||
background: tokens.up,
|
||||
background: tokens.brand,
|
||||
display: "grid",
|
||||
placeItems: "center",
|
||||
color: "#fff",
|
||||
@@ -191,16 +191,16 @@ export const refinedStyles = (
|
||||
whiteSpace: "nowrap",
|
||||
textAlign: "center",
|
||||
border: 0,
|
||||
background: active ? tokens.upSoft : "transparent",
|
||||
background: active ? tokens.brandSoft : "transparent",
|
||||
fontFamily: "inherit",
|
||||
fontSize: 11,
|
||||
padding: { xs: "5px 6px", md: "5px 14px" },
|
||||
cursor: "pointer",
|
||||
color: active ? tokens.up : tokens.textMuted,
|
||||
color: active ? tokens.brand : tokens.textMuted,
|
||||
borderRadius: "5px",
|
||||
transition: "background 0.15s ease, color 0.15s ease",
|
||||
fontWeight: active ? 600 : 500,
|
||||
"&:hover": { color: active ? tokens.up : tokens.text },
|
||||
"&:hover": { color: active ? tokens.brand : tokens.text },
|
||||
}),
|
||||
|
||||
monitorList: {
|
||||
@@ -259,9 +259,9 @@ export const refinedStyles = (
|
||||
},
|
||||
pillHardware: {
|
||||
...pillBase,
|
||||
color: tokens.up,
|
||||
color: tokens.brand,
|
||||
border: `1px solid ${tokens.border}`,
|
||||
background: tokens.upSoft,
|
||||
background: tokens.brandSoft,
|
||||
},
|
||||
monitorUrl: {
|
||||
fontSize: 12,
|
||||
@@ -382,11 +382,11 @@ export const refinedStyles = (
|
||||
fontSize: 12,
|
||||
mt: "40px",
|
||||
"& a": {
|
||||
color: tokens.up,
|
||||
color: tokens.brand,
|
||||
textDecoration: "underline",
|
||||
textUnderlineOffset: "3px",
|
||||
fontWeight: 600,
|
||||
"&:hover": { color: tokens.upStrong || tokens.up },
|
||||
"&:hover": { color: tokens.brandStrong },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -9,6 +9,14 @@ export interface StatusPageThemeTokens {
|
||||
up: string;
|
||||
upStrong: string;
|
||||
upSoft: string;
|
||||
// Accent used for brand-tinted surfaces (hero background, active tab
|
||||
// underline, "view all" links). Distinct from `up` so a red/orange
|
||||
// brand color cannot recolor the semantic OK/up status indicators.
|
||||
// Themes leave these undefined by default; the provider falls back
|
||||
// to `up`/`upStrong`/`upSoft` so styles have a value to consume.
|
||||
brand?: string;
|
||||
brandStrong?: string;
|
||||
brandSoft?: string;
|
||||
degraded: string;
|
||||
degradedSoft: string;
|
||||
down: string;
|
||||
|
||||
Reference in new issue
Block a user