From 8b5615426a6aec55ea64463207f85594669f8fd7 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 22 Apr 2026 16:54:11 +0200 Subject: [PATCH] wire design palette through resolver with fallback chains Surface map now tries palette keys (bgSunken, surfaceHi, textHi, etc.) first, falling back to semantic refs for legacy themes. Sidebar/panel bg differentiates from workspace bg. Buttons use accent colour with onAccent text. Four-level text gradient flows to widgets. WCAG-AA contrast fixes: clide textDim lightened, midnight onAccent darkened, paper textDim darkened. Contrast test updated to cover all four themes. Resolver tests updated for the new palette shape. Goldens regenerated. Co-Authored-By: Claude --- app/lib/kernel/src/theme/resolver.dart | 162 ++++++++++-------- app/lib/kernel/src/theme/themes/clide.yaml | 2 +- app/lib/kernel/src/theme/themes/midnight.yaml | 1 + app/lib/kernel/src/theme/themes/paper.yaml | 2 +- app/test/a11y/contrast_test.dart | 5 +- app/test/goldens/goldens/ci/clide_button.png | Bin 2365 -> 2455 bytes app/test/goldens/goldens/ci/clide_tab_bar.png | Bin 804 -> 809 bytes .../goldens/goldens/linux/clide_button.png | Bin 16551 -> 16540 bytes .../goldens/goldens/linux/clide_tab_bar.png | Bin 7625 -> 7627 bytes app/test/kernel/src/theme/resolver_test.dart | 106 +++++++----- 10 files changed, 157 insertions(+), 121 deletions(-) diff --git a/app/lib/kernel/src/theme/resolver.dart b/app/lib/kernel/src/theme/resolver.dart index 854d0a39..c4b8e270 100644 --- a/app/lib/kernel/src/theme/resolver.dart +++ b/app/lib/kernel/src/theme/resolver.dart @@ -151,12 +151,13 @@ class ThemeResolver { final resolved = _resolveRef(override, palette, semantic); if (resolved != null) return resolved; } - final defaultRef = _defaultSurfaceMap[key]; - if (defaultRef != null) { - final resolved = _resolveRef(defaultRef, palette, semantic); - if (resolved != null) return resolved; + final candidates = _defaultSurfaceMap[key]; + if (candidates != null) { + for (final ref in candidates) { + final resolved = _resolveRef(ref, palette, semantic); + if (resolved != null) return resolved; + } } - // Last-ditch: something has to render. Fall back to semantic text. return semantic.lookup(SemanticKeys.text) ?? const Color(0xFFFFFFFF); } @@ -172,81 +173,94 @@ class ThemeResolver { /// Default palette names a semantic role will try, in order, when the /// theme doesn't override the role explicitly. const Map> _defaultSemanticFallbacks = { - SemanticKeys.mainchrome: ['panel', 'surface', 'background'], + SemanticKeys.mainchrome: ['bgSunken', 'panel', 'surface', 'background'], SemanticKeys.calltoaction: ['accent', 'primary'], - SemanticKeys.focus: ['primary', 'accent'], - SemanticKeys.background: ['background'], + SemanticKeys.focus: ['accent', 'primary'], + SemanticKeys.background: ['bg', 'background'], SemanticKeys.surface: ['surface', 'panel'], - SemanticKeys.text: ['foreground'], - SemanticKeys.textMuted: ['muted', 'secondary', 'foreground'], - SemanticKeys.success: ['success'], - SemanticKeys.warning: ['warning'], - SemanticKeys.error: ['error'], + SemanticKeys.text: ['textHi', 'foreground'], + SemanticKeys.textMuted: ['textDim', 'muted', 'secondary', 'foreground'], + SemanticKeys.success: ['ok', 'success'], + SemanticKeys.warning: ['warn', 'warning'], + SemanticKeys.error: ['err', 'error'], SemanticKeys.info: ['info', 'primary'], }; /// Default surface map. Every entry resolves through the semantic layer /// where it makes sense; raw palette refs are used only where the /// semantic layer doesn't have a role that fits. -const Map _defaultSurfaceMap = { - TokenKeys.globalForeground: 'semantic.text', - TokenKeys.globalBackground: 'semantic.background', - TokenKeys.globalBorder: 'semantic.surface', - TokenKeys.globalFocus: 'semantic.focus', - TokenKeys.globalTextMuted: 'semantic.text_muted', - TokenKeys.panelBackground: 'semantic.mainchrome', - TokenKeys.panelBorder: 'semantic.surface', - TokenKeys.panelActiveBorder: 'semantic.focus', - TokenKeys.panelHeader: 'semantic.mainchrome', - TokenKeys.panelHeaderForeground: 'semantic.text', - TokenKeys.sidebarBackground: 'semantic.mainchrome', - TokenKeys.sidebarForeground: 'semantic.text', - TokenKeys.sidebarItemHover: 'semantic.surface', - TokenKeys.sidebarItemSelected: 'semantic.focus', - TokenKeys.sidebarSectionHeader: 'semantic.text_muted', - TokenKeys.statusBarBackground: 'semantic.mainchrome', - TokenKeys.statusBarForeground: 'semantic.text', - TokenKeys.statusBarItemActiveBackground: 'semantic.focus', - TokenKeys.statusBarItemHoverBackground: 'semantic.surface', - TokenKeys.tabBarBackground: 'semantic.mainchrome', - TokenKeys.tabActive: 'semantic.background', - TokenKeys.tabInactive: 'semantic.mainchrome', - TokenKeys.tabActiveForeground: 'semantic.text', - TokenKeys.tabInactiveForeground: 'semantic.text_muted', - TokenKeys.tabActiveBorder: 'semantic.focus', - TokenKeys.tabCloseHover: 'semantic.error', - TokenKeys.buttonBackground: 'semantic.surface', - TokenKeys.buttonForeground: 'semantic.text', - TokenKeys.buttonHoverBackground: 'semantic.mainchrome', - TokenKeys.buttonActiveBackground: 'semantic.focus', - TokenKeys.buttonBorder: 'semantic.surface', - TokenKeys.listItemBackground: 'semantic.background', - TokenKeys.listItemForeground: 'semantic.text', - TokenKeys.listItemHoverBackground: 'semantic.surface', - TokenKeys.listItemSelectedBackground: 'semantic.focus', - TokenKeys.listItemSelectedForeground: 'semantic.background', - TokenKeys.scrollbarSlider: 'semantic.surface', - TokenKeys.scrollbarSliderHover: 'semantic.text_muted', - TokenKeys.scrollbarTrack: 'semantic.mainchrome', - TokenKeys.tooltipBackground: 'semantic.surface', - TokenKeys.tooltipForeground: 'semantic.text', - TokenKeys.tooltipBorder: 'semantic.mainchrome', - TokenKeys.dropdownBackground: 'semantic.surface', - TokenKeys.dropdownForeground: 'semantic.text', - TokenKeys.dropdownBorder: 'semantic.mainchrome', - TokenKeys.modalOverlayBackground: '#C0000000', - TokenKeys.modalSurfaceBackground: 'semantic.mainchrome', - TokenKeys.modalSurfaceBorder: 'semantic.focus', - TokenKeys.dividerColor: 'semantic.surface', - TokenKeys.statusSuccess: 'semantic.success', - TokenKeys.statusWarning: 'semantic.warning', - TokenKeys.statusError: 'semantic.error', - TokenKeys.statusInfo: 'semantic.info', - TokenKeys.syntaxKeyword: 'semantic.calltoaction', - TokenKeys.syntaxType: 'semantic.info', - TokenKeys.syntaxString: 'semantic.success', - TokenKeys.syntaxNumber: 'semantic.warning', - TokenKeys.syntaxComment: 'semantic.text_muted', - TokenKeys.syntaxMethod: 'semantic.focus', - TokenKeys.syntaxPunct: 'semantic.text_muted', +const Map> _defaultSurfaceMap = { + // global — try design keys first, then legacy semantic + TokenKeys.globalForeground: ['textHi', 'semantic.text'], + TokenKeys.globalBackground: ['bg', 'semantic.background'], + TokenKeys.globalBorder: ['border', 'semantic.surface'], + TokenKeys.globalFocus: ['accent', 'semantic.focus'], + TokenKeys.globalTextMuted: ['textDim', 'semantic.text_muted'], + // panel + TokenKeys.panelBackground: ['bgSunken', 'semantic.mainchrome'], + TokenKeys.panelBorder: ['border', 'semantic.surface'], + TokenKeys.panelActiveBorder: ['borderHi', 'semantic.focus'], + TokenKeys.panelHeader: ['surface', 'semantic.mainchrome'], + TokenKeys.panelHeaderForeground: ['text', 'semantic.text'], + // sidebar + TokenKeys.sidebarBackground: ['bgSunken', 'semantic.mainchrome'], + TokenKeys.sidebarForeground: ['text', 'semantic.text'], + TokenKeys.sidebarItemHover: ['surface', 'semantic.surface'], + TokenKeys.sidebarItemSelected: ['surfaceHi', 'semantic.focus'], + TokenKeys.sidebarSectionHeader: ['textMute', 'semantic.text_muted'], + // statusbar + TokenKeys.statusBarBackground: ['bgSunken', 'semantic.mainchrome'], + TokenKeys.statusBarForeground: ['text', 'semantic.text'], + TokenKeys.statusBarItemActiveBackground: ['accent', 'semantic.focus'], + TokenKeys.statusBarItemHoverBackground: ['surface', 'semantic.surface'], + // tabs + TokenKeys.tabBarBackground: ['bgSunken', 'semantic.mainchrome'], + TokenKeys.tabActive: ['bg', 'semantic.background'], + TokenKeys.tabInactive: ['bgSunken', 'semantic.mainchrome'], + TokenKeys.tabActiveForeground: ['textHi', 'semantic.text'], + TokenKeys.tabInactiveForeground: ['textDim', 'semantic.text_muted'], + TokenKeys.tabActiveBorder: ['accent', 'semantic.focus'], + TokenKeys.tabCloseHover: ['err', 'semantic.error'], + // buttons + TokenKeys.buttonBackground: ['accent', 'semantic.calltoaction'], + TokenKeys.buttonForeground: ['onAccent', 'semantic.background'], + TokenKeys.buttonHoverBackground: ['accentPress', 'semantic.focus'], + TokenKeys.buttonActiveBackground: ['accentPress', 'semantic.focus'], + TokenKeys.buttonBorder: ['border', 'semantic.surface'], + // list items + TokenKeys.listItemBackground: ['bg', 'semantic.background'], + TokenKeys.listItemForeground: ['text', 'semantic.text'], + TokenKeys.listItemHoverBackground: ['surface', 'semantic.surface'], + TokenKeys.listItemSelectedBackground: ['surfaceHi', 'semantic.focus'], + TokenKeys.listItemSelectedForeground: ['textHi', 'semantic.text'], + // scrollbar + TokenKeys.scrollbarSlider: ['border', 'semantic.surface'], + TokenKeys.scrollbarSliderHover: ['borderHi', 'semantic.text_muted'], + TokenKeys.scrollbarTrack: ['bgSunken', 'semantic.mainchrome'], + // tooltip + TokenKeys.tooltipBackground: ['surface', 'semantic.surface'], + TokenKeys.tooltipForeground: ['textHi', 'semantic.text'], + TokenKeys.tooltipBorder: ['borderHi', 'semantic.mainchrome'], + // dropdown + TokenKeys.dropdownBackground: ['surface', 'semantic.surface'], + TokenKeys.dropdownForeground: ['text', 'semantic.text'], + TokenKeys.dropdownBorder: ['border', 'semantic.mainchrome'], + // modal + TokenKeys.modalOverlayBackground: ['#C0000000'], + TokenKeys.modalSurfaceBackground: ['surface', 'semantic.mainchrome'], + TokenKeys.modalSurfaceBorder: ['accent', 'semantic.focus'], + // divider + TokenKeys.dividerColor: ['border', 'semantic.surface'], + // status + TokenKeys.statusSuccess: ['ok', 'semantic.success'], + TokenKeys.statusWarning: ['warn', 'semantic.warning'], + TokenKeys.statusError: ['err', 'semantic.error'], + TokenKeys.statusInfo: ['info', 'semantic.info'], + TokenKeys.syntaxKeyword: ['semantic.calltoaction'], + TokenKeys.syntaxType: ['semantic.info'], + TokenKeys.syntaxString: ['semantic.success'], + TokenKeys.syntaxNumber: ['semantic.warning'], + TokenKeys.syntaxComment: ['semantic.text_muted'], + TokenKeys.syntaxMethod: ['semantic.focus'], + TokenKeys.syntaxPunct: ['semantic.text_muted'], }; diff --git a/app/lib/kernel/src/theme/themes/clide.yaml b/app/lib/kernel/src/theme/themes/clide.yaml index f3b94fe3..6881b729 100644 --- a/app/lib/kernel/src/theme/themes/clide.yaml +++ b/app/lib/kernel/src/theme/themes/clide.yaml @@ -22,7 +22,7 @@ palette: surfaceHi: "#2C3046" border: "#343850" borderHi: "#3C445C" - textDim: "#78809C" + textDim: "#8890AC" textMute: "#545C84" accentSoft: "#2178A0F8" diff --git a/app/lib/kernel/src/theme/themes/midnight.yaml b/app/lib/kernel/src/theme/themes/midnight.yaml index e12fc89a..4894c807 100644 --- a/app/lib/kernel/src/theme/themes/midnight.yaml +++ b/app/lib/kernel/src/theme/themes/midnight.yaml @@ -18,6 +18,7 @@ palette: warning: "#D7BA7D" error: "#F48771" info: "#569CD6" + onAccent: "#0B1220" surfaceHi: "#2D2D2E" border: "#333333" borderHi: "#3F3F3F" diff --git a/app/lib/kernel/src/theme/themes/paper.yaml b/app/lib/kernel/src/theme/themes/paper.yaml index 6823ee79..84a7f669 100644 --- a/app/lib/kernel/src/theme/themes/paper.yaml +++ b/app/lib/kernel/src/theme/themes/paper.yaml @@ -21,7 +21,7 @@ palette: surfaceHi: "#ECE7DB" border: "#1A1A1A" borderHi: "#4A4A4A" - textDim: "#8A8A82" + textDim: "#5E5E56" textMute: "#A8A89E" accentSoft: "#21C14B2A" diff --git a/app/test/a11y/contrast_test.dart b/app/test/a11y/contrast_test.dart index 27215f66..1410c0d3 100644 --- a/app/test/a11y/contrast_test.dart +++ b/app/test/a11y/contrast_test.dart @@ -11,7 +11,10 @@ void main() { group('contrast — all bundled themes meet WCAG AA', () { const bundledPaths = [ - 'lib/kernel/src/theme/themes/summer-night.yaml', + 'lib/kernel/src/theme/themes/clide.yaml', + 'lib/kernel/src/theme/themes/midnight.yaml', + 'lib/kernel/src/theme/themes/paper.yaml', + 'lib/kernel/src/theme/themes/terminal.yaml', ]; for (final path in bundledPaths) { diff --git a/app/test/goldens/goldens/ci/clide_button.png b/app/test/goldens/goldens/ci/clide_button.png index 456cf3e15e591343ff6ab5af6d0c97b9ea07abc8..008f3e4e41220be5302c7855f1982ca389c27bbe 100644 GIT binary patch delta 1905 zcmY+Ec{tm79>=4KI)-(X)RCP|iyB8$>i$tPt`bSH)rzACYOzvB&^W@FDTyPxSy!v{ zp@f*Abp0(nZ0KpWiZn8SXhxnn;{S0;dB9HLX6rX2gg*<;7q$t!pF&ZQf&NHoskOy&9EC2=xcjMR=Jgw+SC#qVh^unN^BS(YtO= za*2I?Ra)6EY4A}xojI^1OQ>7xZ9p^jvV>!p3X(C~P7SxXc=pq~r=?8nRO0~IPUt_^ zus_g(MgY=noUJ?Alw>>Y`MEuWLF;VY+T~1dvuGx&L3Guqcn`j5`vfl^RktbM$Q(W@ zS8ACXkL^;U?gLQnVj;&Xa0-~`!i@KAb;3L9kz=IBeR<{{mmu=U=(IX*` z7ivEYq&6J6q$Gd1_lC@K10>q2HBnhH&$#a0nb7vRZB~*M0uWE|QD%>hP_^wPZEv!j z*HKBYt|^WuwQM*%#Gf(2c5FM|wQ>Q(+gNm|^v``n*gFpg2MYdlul!!OlaYfVsMCy6 zD|m-E*LPNAmRlYijv5C|b;m7*Y)J3EwG@%tmnPh>)#ZKShkb)&R^6cJTiNVvp@@F4 zY>n-Ch?i7&pOYiC)QTb)3gm)JBY`x7lOvEz z*V?PD79SO*m#!ke_=X$j6a-R0f1%I6ttIf<2^^s3A9@txHlR(zB;npFenT;2VQUd@ zy5a|xs&$4KX4>F9;H0=|^2iGcUNXw9!vmH(K6PvPpRb4-iHU@mY4Z4#@qkmR9_SJr zVUBUGXT1m3ANB|@V-o%rv6R<(ute6lh4F*AfZO+O2{s`Kf6vQ_iM-<4{Q!zfyZ22% zmxz5E3qzbJAUvMB6HQwz3`b1{&*pmV1W6V;s#Z;wt4~RNLps6-nT6C6x3}6cai3f` zRrO;CbAqQru#;-2`Gc*&V6-7uu;xCKAFQuk@>QIuhs8*{Kzlu+r^6rnQ8ppvwhssX z^Zo#nWp%|PWp&0l>6FBR(Y_II)*PE!fR`+NjMVigqH|1M`L(ua(t%-xW6QWmLY|9rGD!zxmc>K{iWR3cOrFHG6=;tH8_j=EqPeHzf24-Zv3aV?Nd}(7fs> z^OKQpuJ}c9vVxoL**pSQF270JU)b?D_^d*Iy~Xh=@t{n4$|XC0!6io|J9f@L=X}ix zC^ezxPF!kmbE3fswY26oCEcMB3!E^?pgp%{B8em(|apw`qTUq%LO` zY@z9V6>kRy4%&nm?nHQ=uvYYRrTjsE(8nFWoXOP{5Mke;5Ao{Gvs{jKNetL5m)g%U z2`s(}Ki63M_8dO9Mo;`>rhW`PjlZ&u$O+g%tH9lXEU2kr7ktB3wSRlOj@sLHtTC?3N582@+yIA%Tz5n| JG<+BM!ym`=yYB!1 delta 1810 zcmZvce>~Is9>>3hXyn&Mq;OToj~eDjj>D+#=0}plltO-<;xJk?KejYKimVBDM}Ci{ z`7xE_u!KgXrpq#JTT+{GJH%{uOXK0!+^usS=W+kIpU30<*XQwgf8LMR=lOh>gPHmz zM+q9Ad=bZjGioIK08$Nh-{5EI61$_rQ6Nbk?mv;(9usR3T(6twBzMgi&2y=*anes_ zUGLqg{_kh4UTyx)@Uqh*2l5eMa8k^B`cq`58v1ezZEKk$-pDl7!P(!vU@39vUuCq7 zV;#wy=r7_WijWP#uZR=3M}ZEz%Th$vJGYt&dqegmmv7edT5oeOv z(gdI@9b|ywJU&M*Q41lDs2MA2mpSh_%C2b=u%{6*MXJe`4>a2b9|?q{v~>y>1w0~= z$-k-{BAgCfp?0L$(2JG=oi@4nisSxcx2MI6bFa-vjpBP06|nOgyyeC5Nm5G2K^dem z_&k)wdZYrIb1%VxNHpgsdnB@cuS5)th%3QqqvD-9bO)9v-&Nob$RI|3ymPLr{q@+u zk88w6GajpZ4gp@!EC}M{6pA9;^u|a*96}VaY~ausbFIMWv>WxIq2kV;F)r8tWV)X4 zWa~dDn3zqY3_wENx6-aIrnhft=BOv2;oDA2)5=1+H zs*m@Ap`|C_Dn~*(sqt0s)|-R~UYI{K-~k}e77d5k z-lH6w72zNkCQiWf*r#u;QyE!8s3%7}B#cR#$urVsj&0|A*tnp9am$39pJBZi^NYK+ z`CpcT6Q!)7p_#d)`$_+_&Hj06yqG+yw);(2-|H7F9%&W14!vCxFo=Cs~@x7^gne)&KZ3hHp$XgYeA+#pUnD{M67 z?+b3}FDESf4IWG@c8~q#O}RaeNvWUdscI~YxCCF@j1E>A_i-2{SyUY(+z;=yi0{68 zt>3J5+}11cW4Mxw-}WXUE=@0T-6~QPy^yYA8f6>!?Th;UJ2+KiBdxd8=JWe2uOYcG zI@5P>Hh&-*(!f&^dCdwm72CZUtL2YCl;YF?eklT~V0=RVn{=%`mFii`-olBsgD3fw z<+o`H-5hH_)e-*Ix3ZzB6zkgMuReR>xC1h+3Xr;vhpFf4JO{;@GOYE$Iz(LktgcuS zmd|}lr?G@@>dw+)!}?XHj$ppdm41)=>Z5QgY?j+X{w!dbwb-3q$iIv`b56nO4mzFKI72YcwDRU< zwM$ED}K_6`Y_{rw?WjN5u@ZR&trZlb@uB`NvKR zVr7M}&*;Lu3O+otS8%&ql0F!p7N888?y`kopa0&txNoiFfA|xj#;OVKGDyYa$>-&< z_=Tc(u)pY=c6gu=G zyab`w&`VJ82D-aAbtn`a90ZNHxw(s4!NrP=qhkr=%L(~E&z$dkFCqMRA;alhySg?m z0CS)}+?(n9x-)$nz#I{g!7Gz&0T&6ZX4bbb0n7^iP4a?e7p9AP`KGZ~-2Zzycjv4(hT20E|U-f3QpV#SCL!c{&OoFHP`@wSON&d5! v_88TTODTiV%i3cQ$Oc$Zr`xGL0z~@3TG)}k7fm&{S09XO50R?hpRYXvM6&?` zu>=r^C4fMzcHB37`1q-tNoK&#&a3kM@LOl+uRnZT7O!3J?EH&#Fx>C-{LQWHPS2kP zU4Mqy0D)kU!7Gz&0SjAhg{#P|a8Q>G5Qrs!Kr8_SVm0Oc55ECcvbwiZE}b0L9s^>v z%U_1IXNYyR*Oq3^A0bdnbMNjW8z3-K=57p1@ABfguWOI~{+h@@0F!cMX{odeE9bt> zpCFU)0X_~(0D)NT!p3gx833xV0g^yq(VyR)o&R?4T^S74J3Id(J%9GJ)AJL)hX=#` z+9S+7800000NkvXXu0mjf_{{9H diff --git a/app/test/goldens/goldens/linux/clide_button.png b/app/test/goldens/goldens/linux/clide_button.png index 06dabb88c57b6e860dee778b52d83d47ce2f47b7..4dfd29c15604f633aa693dfdfb800685e495ec12 100644 GIT binary patch literal 16540 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 literal 16551 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 YnAB?)L|9=0H$jk>R*|asXd3)~0UJ}zMF0Q* diff --git a/app/test/goldens/goldens/linux/clide_tab_bar.png b/app/test/goldens/goldens/linux/clide_tab_bar.png index 6674a2a6b2b8a8f0ef3e67c0fa27a24b74f37cd9..2b03cb03fa1b59431b8391f3a28da1ca63cbc9b5 100644 GIT binary patch delta 7316 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 ZO^qPDw6=Q`4G@4Ib!Ba(Qbntf{{@hlt|$Ni delta 7302 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 G!v6<+e1#$a diff --git a/app/test/kernel/src/theme/resolver_test.dart b/app/test/kernel/src/theme/resolver_test.dart index 2f297d6d..d2a63940 100644 --- a/app/test/kernel/src/theme/resolver_test.dart +++ b/app/test/kernel/src/theme/resolver_test.dart @@ -9,7 +9,41 @@ void main() { Palette paletteOf(Map colors) => Palette(colors); group('ThemeResolver default fallbacks', () { - test('palette-only summer-night shape resolves every token', () { + test('design-shape palette resolves every token', () { + final tokens = resolver.resolve( + palette: paletteOf(const { + 'bg': Color(0xFF20202C), + 'bgSunken': Color(0xFF1A1A24), + 'surface': Color(0xFF242838), + 'surfaceHi': Color(0xFF2C3046), + 'border': Color(0xFF343850), + 'borderHi': Color(0xFF3C445C), + 'textHi': Color(0xFFE6E8F2), + 'text': Color(0xFFB1BBE3), + 'textDim': Color(0xFF78809C), + 'textMute': Color(0xFF545C84), + 'accent': Color(0xFF78A0F8), + 'accentPress': Color(0xFF6C90DC), + 'accentSoft': Color(0x2178A0F8), + 'onAccent': Color(0xFF0D1020), + 'ok': Color(0xFF7DD3A8), + 'warn': Color(0xFFE6C370), + 'err': Color(0xFFE87D7D), + 'info': Color(0xFF78A0F8), + }), + ); + expect(tokens.globalBackground, const Color(0xFF20202C)); + expect(tokens.globalForeground, const Color(0xFFE6E8F2)); + expect(tokens.panelBackground, const Color(0xFF1A1A24)); + expect(tokens.sidebarItemSelected, const Color(0xFF2C3046)); + expect(tokens.statusSuccess, const Color(0xFF7DD3A8)); + expect(tokens.statusError, const Color(0xFFE87D7D)); + expect(tokens.globalTextMuted, const Color(0xFF78809C)); + expect(tokens.buttonBackground, const Color(0xFF78A0F8)); + expect(tokens.buttonForeground, const Color(0xFF0D1020)); + }); + + test('legacy palette keys still resolve via fallback chains', () { final tokens = resolver.resolve( palette: paletteOf(const { 'primary': Color(0xFF00A3D2), @@ -28,27 +62,8 @@ void main() { expect(tokens.globalBackground, const Color(0xFF21262F)); expect(tokens.globalForeground, const Color(0xFFE2E8F5)); expect(tokens.panelBackground, const Color(0xFF292E38)); - expect(tokens.sidebarItemSelected, const Color(0xFF00A3D2)); expect(tokens.statusSuccess, const Color(0xFF00AB9A)); expect(tokens.statusError, const Color(0xFFF06C6F)); - expect(tokens.globalTextMuted, const Color(0xFF6A7280)); - }); - - test('missing "muted" falls back to foreground', () { - final tokens = resolver.resolve( - palette: paletteOf(const { - 'primary': Color(0xFF111111), - 'accent': Color(0xFF222222), - 'background': Color(0xFF333333), - 'surface': Color(0xFF444444), - 'panel': Color(0xFF555555), - 'foreground': Color(0xFFEEEEEE), - 'success': Color(0xFF008800), - 'warning': Color(0xFFFF8800), - 'error': Color(0xFFFF0000), - }), - ); - expect(tokens.globalTextMuted, const Color(0xFFEEEEEE)); }); }); @@ -56,15 +71,16 @@ void main() { test('surface override wins over default', () { final tokens = resolver.resolve( palette: paletteOf(const { - 'primary': Color(0xFF111111), - 'accent': Color(0xFF222222), - 'background': Color(0xFF333333), + 'bg': Color(0xFF333333), + 'bgSunken': Color(0xFF222222), 'surface': Color(0xFF444444), - 'panel': Color(0xFF555555), - 'foreground': Color(0xFFFFFFFF), - 'success': Color(0xFF008800), - 'warning': Color(0xFFFF8800), - 'error': Color(0xFFFF0000), + 'border': Color(0xFF555555), + 'textHi': Color(0xFFFFFFFF), + 'accent': Color(0xFF111111), + 'ok': Color(0xFF008800), + 'warn': Color(0xFFFF8800), + 'err': Color(0xFFFF0000), + 'info': Color(0xFF111111), }), surfaceOverride: const { 'panel.background': '#00FF00', @@ -73,36 +89,38 @@ void main() { expect(tokens.panelBackground, const Color(0xFF00FF00)); }); - test('semantic override propagates to surface tokens using it', () { + test('semantic override propagates when palette key is absent', () { final tokens = resolver.resolve( palette: paletteOf(const { - 'primary': Color(0xFF111111), - 'accent': Color(0xFF222222), - 'background': Color(0xFF333333), + 'bg': Color(0xFF333333), + 'bgSunken': Color(0xFF222222), 'surface': Color(0xFF444444), - 'panel': Color(0xFF555555), - 'foreground': Color(0xFFFFFFFF), - 'success': Color(0xFF008800), - 'warning': Color(0xFFFF8800), - 'error': Color(0xFFFF0000), - 'teal': Color(0xFF007777), + 'surfaceHi': Color(0xFF555555), + 'border': Color(0xFF666666), + 'textHi': Color(0xFFFFFFFF), + 'ok': Color(0xFF008800), + 'warn': Color(0xFFFF8800), + 'err': Color(0xFFFF0000), + 'info': Color(0xFF111111), }), semanticOverride: const SemanticRoles({ 'focus': Color(0xFF007777), }), ); - // sidebarItemSelected defaults to semantic.focus — expect override. - expect(tokens.sidebarItemSelected, const Color(0xFF007777)); + // No 'accent' in palette, so globalFocus falls through to + // semantic.focus which is overridden. + expect(tokens.globalFocus, const Color(0xFF007777)); }); test('extensionOverride populates extensionTokens map', () { final tokens = resolver.resolve( palette: paletteOf(const { - 'primary': Color(0xFF111111), - 'background': Color(0xFF333333), + 'bg': Color(0xFF333333), + 'bgSunken': Color(0xFF222222), 'surface': Color(0xFF444444), - 'panel': Color(0xFF555555), - 'foreground': Color(0xFFFFFFFF), + 'border': Color(0xFF555555), + 'textHi': Color(0xFFFFFFFF), + 'accent': Color(0xFF111111), }), extensionOverride: const { 'ext.sqlite.table.background': '#ABCDEF',