diff --git a/CHANGELOG.md b/CHANGELOG.md index b45d50ba..52f0fa2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ ## [Unreleased] +## [v0.51.250] — 2026-06-03 — Release HR (stage-q22 — Zeus appearance skin) + +### Added +- New **Zeus** appearance skin (Settings → Appearance, or `/theme skin zeus`) — OLED-near-black dark surfaces that keep the default gold accent, for a high-contrast "gold on black" look that no existing skin offered. All visual changes are scoped to `data-skin="zeus"`; it's dark-focused and falls back to the default light palette in light mode. (#3328, @heagandev) + ## [v0.51.249] — 2026-06-03 — Release HQ (stage-q21 — auto-expand terminal on output toggle) ### Added diff --git a/THEMES.md b/THEMES.md index abb93270..e759359d 100644 --- a/THEMES.md +++ b/THEMES.md @@ -21,7 +21,7 @@ Preview is instant — the UI updates as you click. **Slash command:** Type `/theme ` in the composer. The command accepts both theme names (`system`, `dark`, `light`) and skin names (`default`, `ares`, `mono`, `slate`, `poseidon`, `sisyphus`, `charizard`, `sienna`, -`catppuccin`, `nous`, `geist-contrast`). It updates the matching axis and leaves the other one +`catppuccin`, `nous`, `geist-contrast`, `zeus`). It updates the matching axis and leaves the other one alone. **Persistence:** Both choices are stored in `localStorage` for flicker-free @@ -58,6 +58,7 @@ absent for light. System mode tracks the OS preference at runtime. | **Catppuccin** | Catppuccin Latte/Mocha palette with Mauve accent. | | **Nous** | Steel-blue accent with dashed technical surfaces. | | **Geist Contrast** (`geist-contrast`) | Geist-inspired monochrome surfaces with a restrained dark-mode `#FFF175` accent. | +| **Zeus** | OLED-near-black dark surfaces that keep the default gold accent. Dark-focused; falls back to the default light palette in light mode. | Each skin defines paired light + dark variants so it reads cleanly on either theme. The skin is applied as `data-skin=""` on `` (the default diff --git a/api/config.py b/api/config.py index 61aee973..fe890612 100644 --- a/api/config.py +++ b/api/config.py @@ -5073,6 +5073,7 @@ _SETTINGS_SKIN_VALUES = { "catppuccin", "nous", "geist-contrast", + "zeus", } _SETTINGS_LEGACY_THEME_MAP = { # Legacy full themes now map onto the closest supported theme + accent skin pair. diff --git a/static/boot.js b/static/boot.js index 052bee17..b9c38919 100644 --- a/static/boot.js +++ b/static/boot.js @@ -1470,6 +1470,7 @@ const _SKINS=[ {name:'Nous', colors:['#4682B4','#3A6E9A','#2C5F88']}, {name:'Neon', colors:['#B347FF','#C76BFF','#00DDFF']}, {name:'Geist Contrast', value:'geist-contrast', colors:['#000000','#ffffff','#FFF175']}, + {name:'Zeus', colors:['#FFD700','#FFBF00','#1A1A00']}, ]; const _VALID_THEMES=new Set((_THEMES||[]).map(t=>t.value)); const _VALID_SKINS=new Set((_SKINS||[]).map(s=>(s.value||s.name).toLowerCase())); diff --git a/static/i18n.js b/static/i18n.js index 8223545c..b840b4d2 100644 --- a/static/i18n.js +++ b/static/i18n.js @@ -202,7 +202,7 @@ const LOCALES = { cmd_terminal: 'Open the workspace terminal', cmd_new: 'Start a new chat session', cmd_usage: 'Toggle token usage display on/off', - cmd_theme: 'Switch appearance (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: 'Switch appearance (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: 'Switch agent personality', cmd_skills: 'List available Hermes skills', available_commands: 'Available commands:', @@ -1538,7 +1538,7 @@ const LOCALES = { cmd_terminal: 'Apri il terminale del workspace', cmd_new: 'Avvia una nuova sessione di chat', cmd_usage: 'Attiva/disattiva visualizzazione uso token', - cmd_theme: 'Cambia aspetto (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: 'Cambia aspetto (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: "Cambia personalità dell'agente", cmd_skills: 'Elenca le skill Hermes disponibili', available_commands: 'Comandi disponibili:', @@ -2866,7 +2866,7 @@ const LOCALES = { cmd_terminal: 'ワークスペースのターミナルを開く', cmd_new: '新しいチャットセッションを開始', cmd_usage: 'トークン使用量表示の ON/OFF を切り替え', - cmd_theme: '外観を切り替え (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: '外観を切り替え (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: 'エージェントのパーソナリティを切り替え', cmd_skills: '利用可能な Hermes スキルを一覧表示', available_commands: '利用可能なコマンド:', @@ -4156,7 +4156,7 @@ const LOCALES = { cmd_terminal: 'Открыть терминал рабочей области', cmd_new: 'Начать новую сессию чата', cmd_usage: 'Показать или скрыть использование токенов', - cmd_theme: 'Переключить внешний вид (тема: system/dark/light, скин: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: 'Переключить внешний вид (тема: system/dark/light, скин: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: 'Переключить личность агента', cmd_skills: 'Показать доступные навыки Hermes', available_commands: 'Доступные команды:', @@ -5455,7 +5455,7 @@ const LOCALES = { cmd_terminal: 'Abrir terminal del espacio de trabajo', cmd_new: 'Iniciar una nueva sesión de chat', cmd_usage: 'Activar o desactivar el uso de tokens', - cmd_theme: 'Cambiar apariencia (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: 'Cambiar apariencia (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: 'Cambiar la personalidad del agente', cmd_skills: 'Listar las skills de Hermes disponibles', available_commands: 'Comandos disponibles:', @@ -6695,7 +6695,7 @@ const LOCALES = { cmd_terminal: 'Workspace-Terminal öffnen', cmd_new: 'Neue Chat-Sitzung starten', cmd_usage: 'Token-Verbrauchsanzeige umschalten', - cmd_theme: 'Darstellung wechseln (Theme: system/dark/light, Skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: 'Darstellung wechseln (Theme: system/dark/light, Skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: 'Agenten-Persönlichkeit wechseln', cmd_skills: 'Verfügbare Hermes-Skills auflisten', available_commands: 'Verfügbare Befehle:', @@ -7986,7 +7986,7 @@ const LOCALES = { cmd_terminal: '打开工作区 Terminal', cmd_new: '新建聊天会话', cmd_usage: '切换 token 用量显示', - cmd_theme: '切换外观(主题:system/dark/light,皮肤:default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: '切换外观(主题:system/dark/light,皮肤:default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: '切换 Agent 人设', cmd_skills: '列出可用的 Hermes 技能', available_commands: '可用命令:', @@ -9263,7 +9263,7 @@ const LOCALES = { cmd_terminal: '開啟工作區 Terminal', cmd_new: '開始新的聊天對話', cmd_usage: '開啟或關閉 token 用量顯示', - cmd_theme: '切換外觀(主題:system/dark/light,skin:default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: '切換外觀(主題:system/dark/light,skin:default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: '切換 Agent 角色', cmd_skills: '列出可用的 Hermes 技能', available_commands: '可用命令:', @@ -10510,7 +10510,7 @@ const LOCALES = { cmd_workspace: 'Trocar workspace por nome', cmd_new: 'Iniciar nova sessão de chat', cmd_usage: 'Alternar exibição de uso de tokens', - cmd_theme: 'Trocar aparência (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: 'Trocar aparência (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: 'Trocar personalidade do agente', cmd_skills: 'Listar skills disponíveis do Hermes', available_commands: 'Comandos disponíveis:', @@ -11723,7 +11723,7 @@ const LOCALES = { cmd_terminal: '워크스페이스 터미널 열기', cmd_new: '새 채팅 세션 시작', cmd_usage: '토큰 사용량 표시 켜기/끄기', - cmd_theme: 'Switch appearance (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: 'Switch appearance (theme: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: 'Switch agent personality', cmd_skills: 'List available Hermes skills', available_commands: '사용 가능한 명령:', @@ -13044,7 +13044,7 @@ const LOCALES = { cmd_terminal: 'Ouvrez le terminal de l\'espace de travail', cmd_new: 'Démarrer une nouvelle session de discussion', cmd_usage: 'Activer/désactiver l\'affichage de l\'utilisation du jeton', - cmd_theme: 'Changer d\'apparence (thème : system/dark/light, skin : default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: 'Changer d\'apparence (thème : system/dark/light, skin : default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: 'Personnalité de l\'agent de commutation', cmd_skills: 'Lister les compétences Hermès disponibles', available_commands: 'Commandes disponibles :', @@ -14318,7 +14318,7 @@ const LOCALES = { cmd_terminal: 'Çalışma alanı terminalini açın', cmd_new: 'Yeni bir sohbet oturumu başlatın', cmd_usage: 'Token kullanımı ekranını aç/kapat', - cmd_theme: 'Görünümü değiştir (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_theme: 'Görünümü değiştir (tema: system/dark/light, skin: default/ares/mono/graphite/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast/zeus)', cmd_personality: 'Temsilci kişiliğini değiştir', cmd_skills: 'Mevcut Hermes becerilerini listele', available_commands: 'Mevcut komutlar:', diff --git a/static/index.html b/static/index.html index 710d24ea..57000e62 100644 --- a/static/index.html +++ b/static/index.html @@ -17,7 +17,7 @@ - + diff --git a/static/style.css b/static/style.css index fa64ac90..882d2988 100644 --- a/static/style.css +++ b/static/style.css @@ -728,6 +728,33 @@ :root[data-skin="geist-contrast"] textarea#msg{scrollbar-width:none;overflow-y:auto;} :root[data-skin="geist-contrast"] textarea#msg::-webkit-scrollbar{display:none;} + /* ── Skin: Zeus ── + OLED-near-black skin: replaces the default dark-blue/navy surfaces with warm + near-blacks while keeping the gold accent unchanged. Borders are gold-tinted + for warmth so the accent feels connected to the chrome. + Dark-only — no light-mode variant. */ + :root.dark[data-skin="zeus"]{ + --bg:#0F0F0F;--sidebar:#111111;--surface:#181818;--code-bg:#181818; + --topbar-bg:rgba(15,15,15,.98);--main-bg:rgba(15,15,15,0.6); + --border:#2A2A1E;--border2:rgba(255,215,0,0.18); + --input-bg:rgba(255,255,255,.04);--hover-bg:rgba(255,215,0,.06); + --surface-subtle:rgba(255,255,255,.03);--surface-subtle-hover:rgba(255,255,255,.05); + --border-subtle:rgba(255,215,0,.08);--border-muted:rgba(255,215,0,.14); + --focus-ring:rgba(255,215,0,.4);--focus-glow:rgba(255,215,0,.1); + } + :root.dark[data-skin="zeus"] .topbar{background:#0F0F0F;border-bottom:1px solid rgba(255,215,0,0.15);} + :root.dark[data-skin="zeus"] .sidebar{background:#111111;border-right:1px solid rgba(255,215,0,0.12);} + :root.dark[data-skin="zeus"] .session-item.active{background:rgba(255,215,0,0.1);border-left:2px solid #FFD700;color:#FFD700;} + :root.dark[data-skin="zeus"] .session-item:hover:not(.active){background:rgba(255,215,0,0.05);} + :root.dark[data-skin="zeus"] .composer-box{background:#141414;border-color:rgba(255,215,0,0.2);} + :root.dark[data-skin="zeus"] .msg-row[data-role="assistant"] .msg-body{background:#181818;border-color:rgba(255,215,0,0.1);} + :root.dark[data-skin="zeus"] .msg-row[data-role="user"] .msg-body{background:#1C1600;border-color:rgba(255,215,0,0.25);} + :root.dark[data-skin="zeus"] .app-dialog{background:linear-gradient(180deg,rgba(24,24,24,.99),rgba(15,15,15,.99));border-color:rgba(255,215,0,0.2);} + :root.dark[data-skin="zeus"] .app-dialog-overlay{background:rgba(0,0,0,.72);} + :root.dark[data-skin="zeus"] .kanban-modal{background:linear-gradient(180deg,rgba(24,24,24,.99),rgba(15,15,15,.99));border-color:rgba(255,215,0,0.2);} + :root.dark[data-skin="zeus"] .kanban-modal-overlay{background:rgba(0,0,0,.72);} + :root.dark[data-skin="zeus"] .kanban-board-switcher-menu{background:linear-gradient(180deg,rgba(24,24,24,.99),rgba(15,15,15,.99));border-color:rgba(255,215,0,0.15);} + /* #594: app-dialog light mode overrides — base styles use hardcoded dark gradients */ :root:not(.dark) .app-dialog{ background:linear-gradient(180deg,rgba(240,237,232,.99),rgba(228,224,216,.99)); diff --git a/tests/test_zeus_skin.py b/tests/test_zeus_skin.py new file mode 100644 index 00000000..7d064457 --- /dev/null +++ b/tests/test_zeus_skin.py @@ -0,0 +1,49 @@ +"""Zeus skin registration and dark-surface affordances.""" + +from pathlib import Path + +REPO = Path(__file__).parent.parent +CSS = (REPO / "static" / "style.css").read_text(encoding="utf-8") +BOOT_JS = (REPO / "static" / "boot.js").read_text(encoding="utf-8") +CONFIG_PY = (REPO / "api" / "config.py").read_text(encoding="utf-8") +INDEX_HTML = (REPO / "static" / "index.html").read_text(encoding="utf-8") +I18N_JS = (REPO / "static" / "i18n.js").read_text(encoding="utf-8") + + +def test_zeus_skin_is_registered_in_all_files(): + assert "{name:'Zeus'" in BOOT_JS + assert "zeus:1" in INDEX_HTML + assert '"zeus"' in CONFIG_PY + + +def test_zeus_dark_surfaces_are_near_black(): + assert ':root.dark[data-skin="zeus"]' in CSS + assert "--bg:#0F0F0F" in CSS + assert "--sidebar:#111111" in CSS + assert "--surface:#181818" in CSS + + +def test_zeus_preserves_default_gold_accent(): + # Zeus does NOT redefine --accent; it stays with the default gold. + # Verify gold-tinted border/focus vars are present instead. + assert "--border2:rgba(255,215,0,0.18)" in CSS + assert "--focus-ring:rgba(255,215,0,.4)" in CSS + assert "--hover-bg:rgba(255,215,0,.06)" in CSS + + +def test_zeus_active_session_uses_gold_highlight(): + assert ':root.dark[data-skin="zeus"] .session-item.active' in CSS + assert "border-left:2px solid #FFD700" in CSS + + +def test_zeus_modals_are_not_navy(): + # Modals/dialogs default to a hardcoded navy gradient — Zeus must override + assert ':root.dark[data-skin="zeus"] .app-dialog' in CSS + assert ':root.dark[data-skin="zeus"] .kanban-modal' in CSS + assert "rgba(24,24,24,.99)" in CSS + + +def test_zeus_i18n_lists_skin_in_all_locales(): + # Zeus is the last skin in each locale's cmd_theme string, so it appears + # as `…/zeus)` rather than `/zeus/`. There are 10 locales. + assert I18N_JS.count("zeus)") == 10