diff --git a/backend/bot/app/web/themes/ascii/style.css b/backend/bot/app/web/themes/ascii/style.css index beae129..c944651 100644 --- a/backend/bot/app/web/themes/ascii/style.css +++ b/backend/bot/app/web/themes/ascii/style.css @@ -149,6 +149,12 @@ .theme-key-ascii .ticket-message-avatar, .theme-key-ascii .ticket-message-bubble, .theme-key-ascii .ticket-composer, +.theme-key-ascii .install-platform-trigger, +.theme-key-ascii .install-app-button, +.theme-key-ascii .install-step, +.theme-key-ascii .install-subscription-card, +.theme-key-ascii .install-qr-wrap, +.theme-key-ascii .install-loading, .theme-key-ascii .admin-sidebar, .theme-key-ascii .admin-header, .theme-key-ascii .admin-card, @@ -183,6 +189,8 @@ .theme-key-ascii .support-new-ticket-button, .theme-key-ascii .support-select-trigger, .theme-key-ascii .support-status-tabs-trigger, +.theme-key-ascii .install-platform-trigger, +.theme-key-ascii .install-app-button, .theme-key-ascii .admin-btn, .theme-key-ascii .admin-chip, .theme-key-ascii .admin-tabs-trigger, @@ -230,6 +238,7 @@ .theme-key-ascii .support-status-tabs-trigger[data-state="active"], .theme-key-ascii .support-select-item[data-highlighted], .theme-key-ascii .support-select-item[data-selected], +.theme-key-ascii .install-app-button.active, .theme-key-ascii .admin-nav-item.active, .theme-key-ascii .admin-tabs-trigger[data-state="active"], .theme-key-ascii .admin-revenue-period-btn.is-active { @@ -259,6 +268,9 @@ .theme-key-ascii .admin-revenue-period-btn:focus-visible, .theme-key-ascii .admin-mobile-toggle:focus-visible, .theme-key-ascii .language-select-trigger:focus-visible, +.theme-key-ascii .install-platform-trigger:focus-visible, +.theme-key-ascii .install-platform-trigger[data-state="open"], +.theme-key-ascii .install-app-button:focus-visible, .theme-key-ascii .bottom-nav button:focus-visible { outline: 2px solid #ffffff; outline-offset: 1px; @@ -412,6 +424,7 @@ } body:has(.theme-key-ascii) .support-select-content, +body:has(.theme-key-ascii) .install-platform-content, body:has(.theme-key-ascii) .field-error-tooltip { border: 1px solid #ffffff; border-radius: 0; @@ -420,19 +433,24 @@ body:has(.theme-key-ascii) .field-error-tooltip { box-shadow: 0 0 0 1px #ffffff; } -body:has(.theme-key-ascii) .support-select-item { +body:has(.theme-key-ascii) .support-select-item, +body:has(.theme-key-ascii) .install-platform-item { border-radius: 0; color: #ffffff; } body:has(.theme-key-ascii) .support-select-item[data-highlighted], -body:has(.theme-key-ascii) .support-select-item[data-selected] { +body:has(.theme-key-ascii) .support-select-item[data-selected], +body:has(.theme-key-ascii) .install-platform-item[data-highlighted], +body:has(.theme-key-ascii) .install-platform-item[data-selected] { background: #ffffff; color: #000000 !important; } body:has(.theme-key-ascii) .support-select-item[data-highlighted] svg, -body:has(.theme-key-ascii) .support-select-item[data-selected] svg { +body:has(.theme-key-ascii) .support-select-item[data-selected] svg, +body:has(.theme-key-ascii) .install-platform-item[data-highlighted] svg, +body:has(.theme-key-ascii) .install-platform-item[data-selected] svg { color: #000000 !important; stroke: #000000 !important; } @@ -695,7 +713,8 @@ body:has(.theme-key-ascii) .support-select-item[data-selected] svg { .theme-key-ascii .admin-btn-primary svg.lucide, .theme-key-ascii .admin-nav-item.active svg.lucide, .theme-key-ascii .admin-tabs-trigger[data-state="active"] svg.lucide, -.theme-key-ascii .admin-revenue-period-btn.is-active svg.lucide { +.theme-key-ascii .admin-revenue-period-btn.is-active svg.lucide, +.theme-key-ascii .install-app-button.active svg.lucide { color: #000000 !important; stroke: #000000 !important; } @@ -1050,6 +1069,9 @@ body:has(.theme-key-ascii) .support-select-item[data-selected] svg { .language-select-content, .language-select-item, .language-select-trigger, .bottom-nav, .bottom-nav button, .link-button, + .install-platform-trigger, .install-platform-content, .install-platform-item, + .install-app-button, .install-step, .install-subscription-card, + .install-qr-wrap, .install-subscription-header-icon, .install-loading, .support-overview-card, .support-list-card, .support-ticket-card, .support-conversation-card, .support-new-ticket-button, .support-create-panel, .support-select-trigger, .support-select-content, @@ -1083,6 +1105,9 @@ body:has(.theme-key-ascii) .support-select-item[data-selected] svg { .admin-tariff-card, .admin-toolbar-card, .admin-table-card, .admin-panel-dash-card, .admin-select-trigger, .admin-select-content, + .install-platform-trigger, .install-platform-content, + .install-app-button, .install-step, .install-subscription-card, + .install-qr-wrap, .install-loading, .admin-cn-card, .admin-input, .admin-textarea, .admin-btn, .admin-nav-item, .admin-tabs-trigger @@ -1096,6 +1121,71 @@ body:has(.theme-key-ascii) .support-select-item[data-selected] svg { border-radius: 0 !important; } +/* ---------- Install guide theme surfaces ---------- */ + +.theme-key-ascii .install-platform-trigger, +.theme-key-ascii .install-app-button, +.theme-key-ascii .install-step, +.theme-key-ascii .install-subscription-card, +.theme-key-ascii .install-qr-wrap, +.theme-key-ascii .install-loading, +body:has(.theme-key-ascii) .install-platform-content { + border: 1px solid #ffffff !important; + border-radius: 0 !important; + background: #000000 !important; + box-shadow: none !important; +} + +.theme-key-ascii .install-platform-trigger:hover, +.theme-key-ascii .install-app-button:hover:not(:disabled) { + background: #ffffff !important; + color: #000000 !important; + transform: none !important; +} + +.theme-key-ascii .install-app-button.active, +.theme-key-ascii .install-app-button.active:hover:not(:disabled), +body:has(.theme-key-ascii) .install-platform-item[data-highlighted], +body:has(.theme-key-ascii) .install-platform-item[data-selected] { + background: #ffffff !important; + color: #000000 !important; + border-color: #ffffff !important; +} + +.theme-key-ascii .install-app-button.active svg, +body:has(.theme-key-ascii) .install-platform-item[data-highlighted] svg, +body:has(.theme-key-ascii) .install-platform-item[data-selected] svg { + color: #000000 !important; + stroke: #000000 !important; +} + +.theme-key-ascii .install-step:hover, +.theme-key-ascii .install-subscription-card:hover { + transform: none !important; + box-shadow: none !important; +} + +.theme-key-ascii .install-step-icon, +.theme-key-ascii .install-subscription-header-icon { + border: 1px solid currentColor !important; + background: #000000 !important; + color: #ffffff !important; +} + +.theme-key-ascii .install-qr-divider { + color: #ffffff !important; + opacity: 0.72; +} + +.theme-key-ascii .install-feature-star.attention-dot { + background: #ffffff !important; + animation: ascii-caret 1s steps(1) infinite !important; +} + +.theme-key-ascii .install-loading .ui-spinner { + color: #ffffff; +} + /* ============================================================ * Console-style tables: cell borders, header underline, * row separator using dashed line. diff --git a/backend/bot/app/web/themes/ascii/theme.json b/backend/bot/app/web/themes/ascii/theme.json index 268715e..6880a94 100644 --- a/backend/bot/app/web/themes/ascii/theme.json +++ b/backend/bot/app/web/themes/ascii/theme.json @@ -9,7 +9,7 @@ "use_primary_accent": false, "use_in_admin": true, "css_file": "style.css", - "assets_version": 3, + "assets_version": 4, "tokens": { "color_scheme": "dark", "style_preset": "ascii" diff --git a/backend/bot/app/web/themes/light/style.css b/backend/bot/app/web/themes/light/style.css index 25f6148..80461d2 100644 --- a/backend/bot/app/web/themes/light/style.css +++ b/backend/bot/app/web/themes/light/style.css @@ -129,3 +129,57 @@ .theme-key-light .bonus-card-head > svg { color: color-mix(in srgb, var(--accent) 50%, #000000); } + +/* Install guide theme surfaces */ + +.theme-key-light .install-platform-trigger, +.theme-key-light .install-app-button, +.theme-key-light .install-step, +.theme-key-light .install-subscription-card, +.theme-key-light .install-qr-wrap { + background: #ffffff; + border-color: rgba(15, 23, 42, 0.12); + box-shadow: 0 8px 20px rgba(15, 23, 42, 0.055); +} + +.theme-key-light .install-app-button.active { + border-color: color-mix(in srgb, var(--accent) 42%, var(--border)); + background: color-mix(in srgb, var(--accent) 8%, #ffffff); + box-shadow: 0 10px 24px rgba(15, 23, 42, 0.08); +} + +.theme-key-light .install-platform-trigger:focus-visible, +.theme-key-light .install-platform-trigger[data-state="open"], +.theme-key-light .install-app-button:focus-visible { + border-color: color-mix(in srgb, var(--accent) 48%, var(--border)); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent); +} + +body:has(.theme-key-light) .install-platform-content { + background: #ffffff; + border-color: rgba(15, 23, 42, 0.14); + box-shadow: 0 14px 28px rgba(15, 23, 42, 0.12); +} + +body:has(.theme-key-light) .install-platform-item[data-highlighted], +body:has(.theme-key-light) .install-platform-item[data-selected] { + background: color-mix(in srgb, var(--accent) 9%, #ffffff); +} + +.theme-key-light .install-step-icon, +.theme-key-light .install-subscription-header-icon { + background: color-mix(in srgb, var(--accent) 8%, #ffffff); + color: color-mix(in srgb, var(--accent) 55%, #000000); +} + +.theme-key-light .install-qr-divider { + color: rgba(15, 23, 42, 0.24); +} + +.theme-key-light .install-feature-star.attention-dot { + background: #f59e0b; +} + +.theme-key-light .install-loading .ui-spinner { + color: color-mix(in srgb, var(--accent) 55%, #000000); +} diff --git a/backend/bot/app/web/themes/light/theme.json b/backend/bot/app/web/themes/light/theme.json index 9713516..175060f 100644 --- a/backend/bot/app/web/themes/light/theme.json +++ b/backend/bot/app/web/themes/light/theme.json @@ -9,7 +9,7 @@ "use_primary_accent": true, "use_in_admin": true, "css_file": "style.css", - "assets_version": 2, + "assets_version": 3, "tokens": { "color_scheme": "light" } diff --git a/backend/bot/app/web/themes/windows95/style.css b/backend/bot/app/web/themes/windows95/style.css index f15f934..974d571 100644 --- a/backend/bot/app/web/themes/windows95/style.css +++ b/backend/bot/app/web/themes/windows95/style.css @@ -138,12 +138,15 @@ .theme-key-windows95 svg.lucide-megaphone, .theme-key-windows95 svg.lucide-message-square, .theme-key-windows95 svg.lucide-message-square-plus, +.theme-key-windows95 svg.lucide-monitor, .theme-key-windows95 svg.lucide-paintbrush, .theme-key-windows95 svg.lucide-plus, +.theme-key-windows95 svg.lucide-qr-code, .theme-key-windows95 svg.lucide-refresh-cw, .theme-key-windows95 svg.lucide-save, .theme-key-windows95 svg.lucide-search, .theme-key-windows95 svg.lucide-send, +.theme-key-windows95 svg.lucide-share-2, .theme-key-windows95 svg.lucide-settings, .theme-key-windows95 svg.lucide-shield, .theme-key-windows95 svg.lucide-sliders, @@ -273,6 +276,10 @@ --win95-button-icon: var(--win95-icon-send); } +.theme-key-windows95 svg.lucide-monitor { + --win95-button-icon: var(--win95-icon-dashboard); +} + .theme-key-windows95 svg.lucide-paintbrush { --win95-button-icon: var(--win95-icon-paintbrush); } @@ -281,6 +288,10 @@ --win95-button-icon: var(--win95-icon-folder); } +.theme-key-windows95 svg.lucide-qr-code { + --win95-button-icon: var(--win95-icon-key); +} + .theme-key-windows95 svg.lucide-refresh-cw { --win95-button-icon: var(--win95-icon-refresh); } @@ -293,6 +304,10 @@ --win95-button-icon: var(--win95-icon-search); } +.theme-key-windows95 svg.lucide-share-2 { + --win95-button-icon: var(--win95-icon-send); +} + .theme-key-windows95 svg.lucide-settings { --win95-button-icon: var(--win95-icon-settings); } @@ -371,12 +386,15 @@ svg.lucide-megaphone, svg.lucide-message-square, svg.lucide-message-square-plus, + svg.lucide-monitor, svg.lucide-paintbrush, svg.lucide-plus, + svg.lucide-qr-code, svg.lucide-refresh-cw, svg.lucide-save, svg.lucide-search, svg.lucide-send, + svg.lucide-share-2, svg.lucide-settings, svg.lucide-shield, svg.lucide-sliders, @@ -425,12 +443,15 @@ svg.lucide-megaphone, svg.lucide-message-square, svg.lucide-message-square-plus, + svg.lucide-monitor, svg.lucide-paintbrush, svg.lucide-plus, + svg.lucide-qr-code, svg.lucide-refresh-cw, svg.lucide-save, svg.lucide-search, svg.lucide-send, + svg.lucide-share-2, svg.lucide-settings, svg.lucide-shield, svg.lucide-sliders, @@ -488,7 +509,13 @@ .theme-key-windows95 .support-message-scroll, .theme-key-windows95 .ticket-message-avatar, .theme-key-windows95 .ticket-message-bubble, -.theme-key-windows95 .ticket-composer { +.theme-key-windows95 .ticket-composer, +.theme-key-windows95 .install-platform-trigger, +.theme-key-windows95 .install-app-button, +.theme-key-windows95 .install-step, +.theme-key-windows95 .install-subscription-card, +.theme-key-windows95 .install-qr-wrap, +.theme-key-windows95 .install-loading { border-width: 2px; border-style: solid; border-color: #ffffff #404040 #404040 #ffffff; @@ -510,6 +537,7 @@ body:has(.theme-key-windows95) .language-select-content, body:has(.theme-key-windows95) .support-select-content, +body:has(.theme-key-windows95) .install-platform-content, body:has(.theme-key-windows95) .field-error-tooltip, body:has(.theme-key-windows95) .admin-select-content { border-width: 2px; @@ -525,18 +553,23 @@ body:has(.theme-key-windows95) .admin-select-content { body:has(.theme-key-windows95) .language-select-item, body:has(.theme-key-windows95) .support-select-item, +body:has(.theme-key-windows95) .install-platform-item, body:has(.theme-key-windows95) .admin-select-item { border-radius: 0 !important; } body:has(.theme-key-windows95) .support-select-item[data-highlighted], -body:has(.theme-key-windows95) .support-select-item[data-selected] { +body:has(.theme-key-windows95) .support-select-item[data-selected], +body:has(.theme-key-windows95) .install-platform-item[data-highlighted], +body:has(.theme-key-windows95) .install-platform-item[data-selected] { background: #000080; color: #ffffff !important; } body:has(.theme-key-windows95) .support-select-item[data-highlighted] svg, -body:has(.theme-key-windows95) .support-select-item[data-selected] svg { +body:has(.theme-key-windows95) .support-select-item[data-selected] svg, +body:has(.theme-key-windows95) .install-platform-item[data-highlighted] svg, +body:has(.theme-key-windows95) .install-platform-item[data-selected] svg { filter: brightness(0) invert(1); } @@ -560,7 +593,9 @@ body:has(.theme-key-windows95) .support-select-item[data-selected] svg { .theme-key-windows95 .link-button, .theme-key-windows95 .support-new-ticket-button, .theme-key-windows95 .support-select-trigger, -.theme-key-windows95 .support-status-tabs-trigger { +.theme-key-windows95 .support-status-tabs-trigger, +.theme-key-windows95 .install-platform-trigger, +.theme-key-windows95 .install-app-button { min-height: 34px; border: 2px solid; border-color: #ffffff #404040 #404040 #ffffff; @@ -625,7 +660,8 @@ body:has(.theme-key-windows95) .support-select-item[data-selected] svg { .theme-key-windows95 .support-new-ticket-button.active, .theme-key-windows95 .support-status-tabs-trigger[data-state="active"], .theme-key-windows95 .support-select-item[data-highlighted], -.theme-key-windows95 .support-select-item[data-selected] { +.theme-key-windows95 .support-select-item[data-selected], +.theme-key-windows95 .install-app-button.active { background: var(--accent); color: #ffffff; } @@ -718,6 +754,9 @@ body:has(.theme-key-windows95) .support-select-item[data-selected] svg { .theme-key-windows95 .ticket-composer:focus-within, .theme-key-windows95 .support-select-trigger:focus-visible, +.theme-key-windows95 .install-platform-trigger:focus-visible, +.theme-key-windows95 .install-platform-trigger[data-state="open"], +.theme-key-windows95 .install-app-button:focus-visible, .theme-key-windows95 .ticket-card:focus-visible, .theme-key-windows95 .support-status-tabs-trigger:focus-visible { outline: 1px dotted #000000; @@ -731,6 +770,85 @@ body:has(.theme-key-windows95) .support-select-item[data-selected] svg { transition: none; } +/* ---------- Install guide theme surfaces ---------- */ + +.theme-key-windows95 .install-platform-trigger, +.theme-key-windows95 .install-app-button { + background: #c0c0c0; + color: #000000; + transition: none; + transform: none; +} + +.theme-key-windows95 .install-platform-trigger:hover, +.theme-key-windows95 .install-app-button:hover:not(:disabled):not(.active) { + background: #dfdfdf; + transform: none; +} + +.theme-key-windows95 .install-app-button.active, +.theme-key-windows95 .install-app-button.active:hover:not(:disabled) { + background: var(--accent); + color: #ffffff; + border-color: #404040 #ffffff #ffffff #404040; + box-shadow: + inset 1px 1px 0 #000000, + inset -1px -1px 0 #dfdfdf; + transform: none; +} + +.theme-key-windows95 .install-step, +.theme-key-windows95 .install-subscription-card, +.theme-key-windows95 .install-qr-wrap, +.theme-key-windows95 .install-loading { + background: #c0c0c0; + transition: none; +} + +.theme-key-windows95 .install-step:hover, +.theme-key-windows95 .install-subscription-card:hover { + transform: none; + box-shadow: + inset 1px 1px 0 #dfdfdf, + inset -1px -1px 0 #808080; +} + +.theme-key-windows95 .install-step-icon, +.theme-key-windows95 .install-subscription-header-icon { + border: 2px solid; + border-color: #ffffff #404040 #404040 #ffffff; + background: #dfdfdf; + color: var(--accent); + box-shadow: + inset 1px 1px 0 #ffffff, + inset -1px -1px 0 #808080; +} + +body:has(.theme-key-windows95) .install-platform-content { + background: #c0c0c0; +} + +body:has(.theme-key-windows95) .install-platform-item[data-highlighted], +body:has(.theme-key-windows95) .install-platform-item[data-selected] { + background: var(--accent); + color: #ffffff !important; +} + +.theme-key-windows95 .install-qr-divider { + color: #404040; + opacity: 1; +} + +.theme-key-windows95 .install-feature-star.attention-dot { + background: #ffff00 !important; + border: 1px solid #000000; + box-shadow: 1px 1px 0 #000000; +} + +.theme-key-windows95 .install-loading .ui-spinner { + color: var(--accent); +} + .theme-key-windows95 .card-heading-accent, .theme-key-windows95 .brand-row strong, .theme-key-windows95 .login-brand h1, @@ -1059,6 +1177,9 @@ body:has(.theme-key-windows95) .support-select-item[data-selected] svg { .theme-key-windows95 .admin-revenue-period-btn:focus-visible, .theme-key-windows95 .admin-mobile-toggle:focus-visible, .theme-key-windows95 .language-select-trigger:focus-visible, +.theme-key-windows95 .install-platform-trigger:focus-visible, +.theme-key-windows95 .install-platform-trigger[data-state="open"], +.theme-key-windows95 .install-app-button:focus-visible, .theme-key-windows95 .bottom-nav button:focus-visible { outline: 1px dotted #000000; outline-offset: -4px; @@ -1116,6 +1237,7 @@ body:has(.theme-key-windows95) .support-select-item[data-selected] svg { .theme-key-windows95 .admin-nav-item.active svg.lucide, .theme-key-windows95 .admin-tabs-trigger[data-state="active"] svg.lucide, .theme-key-windows95 .admin-revenue-period-btn.is-active svg.lucide, +.theme-key-windows95 .install-app-button.active svg.lucide, .theme-key-windows95 .admin-header svg.lucide { filter: brightness(0) invert(1); } @@ -1133,7 +1255,6 @@ body:has(.theme-key-windows95) .support-select-item[data-selected] svg { .theme-key-windows95 svg.lucide-map, .theme-key-windows95 svg.lucide-menu, .theme-key-windows95 svg.lucide-mouse-pointer-click, -.theme-key-windows95 svg.lucide-qr-code, .theme-key-windows95 svg.lucide-radio, .theme-key-windows95 svg.lucide-repeat-2, .theme-key-windows95 svg.lucide-server, diff --git a/backend/bot/app/web/themes/windows95/theme.json b/backend/bot/app/web/themes/windows95/theme.json index 2ada36a..ab765c2 100644 --- a/backend/bot/app/web/themes/windows95/theme.json +++ b/backend/bot/app/web/themes/windows95/theme.json @@ -9,7 +9,7 @@ "use_primary_accent": false, "use_in_admin": true, "css_file": "style.css", - "assets_version": 9, + "assets_version": 11, "tokens": { "color_scheme": "light", "style_preset": "win95" diff --git a/backend/config/webapp_themes_config.py b/backend/config/webapp_themes_config.py index ee5acb5..243697b 100644 --- a/backend/config/webapp_themes_config.py +++ b/backend/config/webapp_themes_config.py @@ -365,7 +365,11 @@ def _builtin_theme_assets_need_refresh(key: str, target_dir: Path) -> bool: except OSError: return True if key == "light": - return "--success-text" not in style or ".theme-key-light.app-shell" not in style + return ( + "--success-text" not in style + or ".theme-key-light.app-shell" not in style + or "Install guide theme surfaces" not in style + ) if key == "ascii": return ( ".theme-key-ascii" not in style @@ -374,6 +378,7 @@ def _builtin_theme_assets_need_refresh(key: str, target_dir: Path) -> bool: or "ascii-boot-type" not in style or "Console-style tables" not in style or "New webapp surfaces: support, purchase info, password login" not in style + or "Install guide theme surfaces" not in style ) if key != "windows95": return False @@ -394,7 +399,9 @@ def _builtin_theme_assets_need_refresh(key: str, target_dir: Path) -> bool: or "::-webkit-slider-thumb" not in style or "?v=9" not in style or "lucide-life-buoy" not in style + or "lucide-qr-code" not in style or "New webapp surfaces: support, purchase info, password login" not in style + or "Install guide theme surfaces" not in style or any(not (target_dir / "icons" / icon).exists() for icon in required_icons) ) diff --git a/tests/test_webapp_themes_config.py b/tests/test_webapp_themes_config.py index c89e449..df33e84 100644 --- a/tests/test_webapp_themes_config.py +++ b/tests/test_webapp_themes_config.py @@ -33,13 +33,14 @@ class WebappThemesConfigTests(unittest.TestCase): self.assertEqual(win95.tokens.style_preset, "win95") self.assertFalse(win95.use_primary_accent) self.assertTrue(win95.use_in_admin) - self.assertEqual(win95.assets_version, 9) + self.assertEqual(win95.assets_version, 11) + self.assertEqual(cfg.theme_by_key("light").assets_version, 3) ascii_theme = cfg.theme_by_key("ascii") self.assertIsNotNone(ascii_theme) self.assertEqual(ascii_theme.css_file, "style.css") self.assertFalse(ascii_theme.use_primary_accent) self.assertTrue(ascii_theme.use_in_admin) - self.assertEqual(ascii_theme.assets_version, 3) + self.assertEqual(ascii_theme.assets_version, 4) def test_env_override_default_theme(self): cfg = builtin_webapp_themes_config("#00fe7a") @@ -381,7 +382,7 @@ class WebappThemesConfigTests(unittest.TestCase): descriptor["assets_version"], cfg.theme_by_key("windows95").assets_version, ) - self.assertEqual(descriptor["assets_version"], 9) + self.assertEqual(descriptor["assets_version"], 11) self.assertIn("lucide-house", css) self.assertIn("lucide-earth", css) self.assertIn("lucide-circle-check", css) @@ -391,7 +392,9 @@ class WebappThemesConfigTests(unittest.TestCase): self.assertIn("::-webkit-slider-thumb", css) self.assertIn("?v=9", css) self.assertIn("lucide-life-buoy", css) + self.assertIn("lucide-qr-code", css) self.assertIn("New webapp surfaces: support, purchase info, password login", css) + self.assertIn("Install guide theme surfaces", css) self.assertIn( ".theme-key-windows95 .support-list-card {\n grid-template-rows: auto auto minmax(0, 1fr);", css, @@ -429,3 +432,39 @@ class WebappThemesConfigTests(unittest.TestCase): css = (stale_theme_dir / "style.css").read_text(encoding="utf-8") self.assertIn(".theme-key-light.app-shell", css) + self.assertIn("Install guide theme surfaces", css) + + def test_resolved_refreshes_stale_builtin_ascii_assets(self): + with tempfile.TemporaryDirectory() as tmp: + themes_dir = Path(tmp) / "themes" + stale_theme_dir = themes_dir / "ascii" + stale_theme_dir.mkdir(parents=True) + (stale_theme_dir / "theme.json").write_text( + json.dumps( + { + "key": "ascii", + "names": {"en": "ASCII"}, + "enabled": True, + "default": False, + "use_primary_accent": False, + "css_file": "style.css", + "assets_version": 1, + "tokens": {"color_scheme": "dark", "style_preset": "ascii"}, + } + ), + encoding="utf-8", + ) + (stale_theme_dir / "style.css").write_text("/* stale */", encoding="utf-8") + + cfg = resolved_webapp_themes_catalog( + theme_dir=themes_dir, + primary_accent="#00fe7a", + env_default_theme=None, + ) + + descriptor = json.loads((stale_theme_dir / "theme.json").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"], 4) + self.assertIn("Console-style tables", css) + self.assertIn("Install guide theme surfaces", css)