fix(themes): style admin health alerts

Add custom-theme styles for the admin configuration alerts and bump built-in theme asset versions so existing installations refresh stale theme CSS.
This commit is contained in:
3252a8
2026-06-10 14:25:24 +03:00
parent 217bed3c5d
commit fd931581f5
8 changed files with 145 additions and 10 deletions
+57 -2
View File
@@ -168,6 +168,7 @@
.theme-key-ascii .admin-toolbar-card, .theme-key-ascii .admin-toolbar-card,
.theme-key-ascii .admin-table-card, .theme-key-ascii .admin-table-card,
.theme-key-ascii .admin-panel-dash-card, .theme-key-ascii .admin-panel-dash-card,
.theme-key-ascii .admin-config-alerts,
.theme-key-ascii .admin-select-trigger, .theme-key-ascii .admin-select-trigger,
.theme-key-ascii .admin-select-content, .theme-key-ascii .admin-select-content,
.theme-key-ascii .admin-cn-card[data-slot="card"], .theme-key-ascii .admin-cn-card[data-slot="card"],
@@ -199,7 +200,8 @@
.theme-key-ascii .admin-tabs-trigger, .theme-key-ascii .admin-tabs-trigger,
.theme-key-ascii .admin-revenue-period-btn, .theme-key-ascii .admin-revenue-period-btn,
.theme-key-ascii .admin-mobile-toggle, .theme-key-ascii .admin-mobile-toggle,
.theme-key-ascii .admin-nav-item { .theme-key-ascii .admin-nav-item,
.theme-key-ascii .admin-config-alert-link {
border: 1px solid #ffffff; border: 1px solid #ffffff;
border-radius: 0; border-radius: 0;
background: #000000; background: #000000;
@@ -216,7 +218,8 @@
.theme-key-ascii .admin-nav-item:hover, .theme-key-ascii .admin-nav-item:hover,
.theme-key-ascii .admin-tabs-trigger:hover, .theme-key-ascii .admin-tabs-trigger:hover,
.theme-key-ascii .admin-revenue-period-btn:hover, .theme-key-ascii .admin-revenue-period-btn:hover,
.theme-key-ascii .bottom-nav button:hover { .theme-key-ascii .bottom-nav button:hover,
.theme-key-ascii .admin-config-alert-link:hover {
background: #ffffff; background: #ffffff;
color: #000000; color: #000000;
} }
@@ -393,6 +396,58 @@
color: #000000; color: #000000;
} }
/* ---------- Admin health config alerts ---------- */
.theme-key-ascii .admin-config-alerts {
position: relative;
padding-left: 18px;
color: #ffffff;
}
.theme-key-ascii .admin-config-alerts::before {
content: "!";
position: absolute;
top: 11px;
left: 7px;
color: #ffffff;
font-family: var(--font-mono);
font-weight: 700;
}
.theme-key-ascii .admin-config-alerts-error {
border-color: #ff5555;
color: #ffaaaa;
}
.theme-key-ascii .admin-config-alerts-error::before {
color: #ff5555;
}
.theme-key-ascii .admin-config-alert-dot {
width: auto;
height: auto;
border-radius: 0;
background: transparent;
color: currentColor;
transform: none;
}
.theme-key-ascii .admin-config-alert-dot::before {
content: ">";
font-family: var(--font-mono);
}
.theme-key-ascii .admin-config-alert-error .admin-config-alert-dot {
background: transparent;
color: #ff5555;
}
.theme-key-ascii .admin-config-alert-link {
padding: 1px 7px;
font-family: var(--font-mono);
opacity: 1;
}
/* ---------- New webapp surfaces: support, purchase info, password login ---------- */ /* ---------- New webapp surfaces: support, purchase info, password login ---------- */
.theme-key-ascii .trial-offer-card, .theme-key-ascii .trial-offer-card,
+1 -1
View File
@@ -9,7 +9,7 @@
"use_primary_accent": false, "use_primary_accent": false,
"use_in_admin": true, "use_in_admin": true,
"css_file": "style.css", "css_file": "style.css",
"assets_version": 6, "assets_version": 7,
"tokens": { "tokens": {
"color_scheme": "dark", "color_scheme": "dark",
"style_preset": "ascii" "style_preset": "ascii"
@@ -252,6 +252,27 @@ body:has(.theme-key-light) .install-platform-item[data-selected] {
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
} }
/* Admin health config alerts */
.theme-key-light .admin-config-alerts {
border-color: color-mix(in srgb, var(--warning) 38%, var(--admin-border));
background: color-mix(in srgb, var(--warning) 9%, #ffffff);
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06);
}
.theme-key-light .admin-config-alerts-error {
border-color: color-mix(in srgb, var(--danger) 38%, var(--admin-border));
background: color-mix(in srgb, var(--danger) 8%, #ffffff);
}
.theme-key-light .admin-config-alert-link {
background: rgba(255, 255, 255, 0.58);
}
.theme-key-light .admin-config-alert-link:hover {
background: #ffffff;
}
/* Telegram notifications banner: keep the warm warning tint but swap the /* Telegram notifications banner: keep the warm warning tint but swap the
* dark-theme inset bevel for the soft drop shadow the other light cards use. */ * dark-theme inset bevel for the soft drop shadow the other light cards use. */
.theme-key-light .telegram-notifications-card { .theme-key-light .telegram-notifications-card {
+1 -1
View File
@@ -9,7 +9,7 @@
"use_primary_accent": true, "use_primary_accent": true,
"use_in_admin": true, "use_in_admin": true,
"css_file": "style.css", "css_file": "style.css",
"assets_version": 5, "assets_version": 6,
"tokens": { "tokens": {
"color_scheme": "light" "color_scheme": "light"
} }
@@ -1267,6 +1267,59 @@ body:has(.theme-key-windows95) .install-platform-item[data-selected] {
inset -1px -1px 0 #dfdfdf; inset -1px -1px 0 #dfdfdf;
} }
/* Admin health config alerts */
.theme-key-windows95 .admin-config-alerts {
border: 2px solid;
border-color: #ffffff #404040 #404040 #ffffff;
background: #ffffcc;
color: #000000;
box-shadow:
inset 1px 1px 0 #dfdfdf,
inset -1px -1px 0 #808080;
}
.theme-key-windows95 .admin-config-alerts-error {
border-color: #ffffff #404040 #404040 #ffffff;
background: #f7d6d6;
color: #000000;
}
.theme-key-windows95 .admin-config-alert-dot {
border-radius: 0;
background: #808000;
box-shadow:
1px 1px 0 #ffffff,
-1px -1px 0 #404040;
}
.theme-key-windows95 .admin-config-alert-error .admin-config-alert-dot {
background: #800000;
}
.theme-key-windows95 .admin-config-alert-link {
border: 2px solid;
border-color: #ffffff #404040 #404040 #ffffff;
border-radius: 0;
background: #c0c0c0;
color: #000000;
box-shadow:
inset 1px 1px 0 #dfdfdf,
inset -1px -1px 0 #808080;
opacity: 1;
}
.theme-key-windows95 .admin-config-alert-link:hover {
background: #dfdfdf;
}
.theme-key-windows95 .admin-config-alert-link:active {
border-color: #404040 #ffffff #ffffff #404040;
box-shadow:
inset 1px 1px 0 #808080,
inset -1px -1px 0 #dfdfdf;
}
.theme-key-windows95 input::placeholder, .theme-key-windows95 input::placeholder,
.theme-key-windows95 textarea::placeholder, .theme-key-windows95 textarea::placeholder,
.theme-key-windows95 .input::placeholder, .theme-key-windows95 .input::placeholder,
@@ -9,7 +9,7 @@
"use_primary_accent": false, "use_primary_accent": false,
"use_in_admin": true, "use_in_admin": true,
"css_file": "style.css", "css_file": "style.css",
"assets_version": 13, "assets_version": 14,
"tokens": { "tokens": {
"color_scheme": "light", "color_scheme": "light",
"style_preset": "win95" "style_preset": "win95"
+3
View File
@@ -372,6 +372,7 @@ def _builtin_theme_assets_need_refresh(key: str, target_dir: Path) -> bool:
or ".theme-key-light.app-shell" not in style or ".theme-key-light.app-shell" not in style
or "Install guide theme surfaces" not in style or "Install guide theme surfaces" not in style
or "Admin controls: range sliders and sortable rows" not in style or "Admin controls: range sliders and sortable rows" not in style
or "Admin health config alerts" not in style
) )
if key == "ascii": if key == "ascii":
return ( return (
@@ -383,6 +384,7 @@ def _builtin_theme_assets_need_refresh(key: str, target_dir: Path) -> bool:
or "New webapp surfaces: support, purchase info, password login" not in style or "New webapp surfaces: support, purchase info, password login" not in style
or "Install guide theme surfaces" not in style or "Install guide theme surfaces" not in style
or "Admin controls: range sliders and sortable rows" not in style or "Admin controls: range sliders and sortable rows" not in style
or "Admin health config alerts" not in style
) )
if key != "windows95": if key != "windows95":
return False return False
@@ -407,6 +409,7 @@ def _builtin_theme_assets_need_refresh(key: str, target_dir: Path) -> bool:
or "New webapp surfaces: support, purchase info, password login" not in style or "New webapp surfaces: support, purchase info, password login" not in style
or "Install guide theme surfaces" not in style or "Install guide theme surfaces" not in style
or "Admin controls: range sliders and sortable rows" not in style or "Admin controls: range sliders and sortable rows" not in style
or "Admin health config alerts" not in style
or any(not (target_dir / "icons" / icon).exists() for icon in required_icons) or any(not (target_dir / "icons" / icon).exists() for icon in required_icons)
) )
+8 -5
View File
@@ -34,14 +34,14 @@ class WebappThemesConfigTests(unittest.TestCase):
self.assertEqual(win95.tokens.style_preset, "win95") self.assertEqual(win95.tokens.style_preset, "win95")
self.assertFalse(win95.use_primary_accent) self.assertFalse(win95.use_primary_accent)
self.assertTrue(win95.use_in_admin) self.assertTrue(win95.use_in_admin)
self.assertEqual(win95.assets_version, 13) self.assertEqual(win95.assets_version, 14)
self.assertEqual(cfg.theme_by_key("light").assets_version, 5) self.assertEqual(cfg.theme_by_key("light").assets_version, 6)
ascii_theme = cfg.theme_by_key("ascii") ascii_theme = cfg.theme_by_key("ascii")
self.assertIsNotNone(ascii_theme) self.assertIsNotNone(ascii_theme)
self.assertEqual(ascii_theme.css_file, "style.css") self.assertEqual(ascii_theme.css_file, "style.css")
self.assertFalse(ascii_theme.use_primary_accent) self.assertFalse(ascii_theme.use_primary_accent)
self.assertTrue(ascii_theme.use_in_admin) self.assertTrue(ascii_theme.use_in_admin)
self.assertEqual(ascii_theme.assets_version, 6) self.assertEqual(ascii_theme.assets_version, 7)
def test_env_override_default_theme(self): def test_env_override_default_theme(self):
cfg = builtin_webapp_themes_config("#00fe7a") cfg = builtin_webapp_themes_config("#00fe7a")
@@ -430,7 +430,7 @@ class WebappThemesConfigTests(unittest.TestCase):
descriptor["assets_version"], descriptor["assets_version"],
cfg.theme_by_key("windows95").assets_version, cfg.theme_by_key("windows95").assets_version,
) )
self.assertEqual(descriptor["assets_version"], 13) self.assertEqual(descriptor["assets_version"], 14)
self.assertIn("lucide-house", css) self.assertIn("lucide-house", css)
self.assertIn("lucide-earth", css) self.assertIn("lucide-earth", css)
self.assertIn("lucide-circle-check", css) self.assertIn("lucide-circle-check", css)
@@ -444,6 +444,7 @@ class WebappThemesConfigTests(unittest.TestCase):
self.assertIn("New webapp surfaces: support, purchase info, password login", css) self.assertIn("New webapp surfaces: support, purchase info, password login", css)
self.assertIn("Install guide theme surfaces", css) self.assertIn("Install guide theme surfaces", css)
self.assertIn("Admin controls: range sliders and sortable rows", css) self.assertIn("Admin controls: range sliders and sortable rows", css)
self.assertIn("Admin health config alerts", css)
self.assertIn( self.assertIn(
( (
".theme-key-windows95 .support-list-card {\n" ".theme-key-windows95 .support-list-card {\n"
@@ -486,6 +487,7 @@ class WebappThemesConfigTests(unittest.TestCase):
self.assertIn(".theme-key-light.app-shell", css) self.assertIn(".theme-key-light.app-shell", css)
self.assertIn("Install guide theme surfaces", css) self.assertIn("Install guide theme surfaces", css)
self.assertIn("Admin controls: range sliders and sortable rows", css) self.assertIn("Admin controls: range sliders and sortable rows", css)
self.assertIn("Admin health config alerts", css)
def test_resolved_refreshes_stale_builtin_ascii_assets(self): def test_resolved_refreshes_stale_builtin_ascii_assets(self):
with tempfile.TemporaryDirectory() as tmp: with tempfile.TemporaryDirectory() as tmp:
@@ -518,7 +520,8 @@ class WebappThemesConfigTests(unittest.TestCase):
descriptor = json.loads((stale_theme_dir / "theme.json").read_text(encoding="utf-8")) descriptor = json.loads((stale_theme_dir / "theme.json").read_text(encoding="utf-8"))
css = (stale_theme_dir / "style.css").read_text(encoding="utf-8") css = (stale_theme_dir / "style.css").read_text(encoding="utf-8")
self.assertEqual(descriptor["assets_version"], cfg.theme_by_key("ascii").assets_version) self.assertEqual(descriptor["assets_version"], cfg.theme_by_key("ascii").assets_version)
self.assertEqual(descriptor["assets_version"], 6) self.assertEqual(descriptor["assets_version"], 7)
self.assertIn("Console-style tables", css) self.assertIn("Console-style tables", css)
self.assertIn("Install guide theme surfaces", css) self.assertIn("Install guide theme surfaces", css)
self.assertIn("Admin controls: range sliders and sortable rows", css) self.assertIn("Admin controls: range sliders and sortable rows", css)
self.assertIn("Admin health config alerts", css)