From b45795127d43e7938f292eb0bbfd6359e0ee5270 Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Tue, 19 May 2026 16:06:48 -0400 Subject: [PATCH] Rearrange common tokens --- default/themed/shell.toml.tpl | 30 ++++++++++++++------------- docs/omarchy-shell.md | 36 +++++++++++++++++++-------------- shell/Commons/Color.qml | 1 + shell/Commons/Style.qml | 11 ++++++---- shell/Ui/Button.qml | 2 +- shell/Ui/Dropdown.qml | 2 +- shell/Ui/SearchableDropdown.qml | 2 +- shell/plugins/osd/Osd.qml | 6 +++--- 8 files changed, 51 insertions(+), 39 deletions(-) diff --git a/default/themed/shell.toml.tpl b/default/themed/shell.toml.tpl index f1335a1e..5d8e58ba 100644 --- a/default/themed/shell.toml.tpl +++ b/default/themed/shell.toml.tpl @@ -14,34 +14,36 @@ active = "{{ color1 }}" size-horizontal = 26 size-vertical = 28 -[style] -# Shared control state tokens. See docs/omarchy-shell.md#interactive-states. -# Colors accept palette roles (foreground/accent/urgent/background) or hex. +[controls] +# Shared state tokens for interactive control chrome (buttons, dropdowns, +# tab strips, etc). # Normal: idle control chrome. -normal-color = "foreground" +normal-color = "{{ foreground }}" normal-fill-alpha = 0.04 normal-border-width = 1 normal-border-alpha = 0.4 # Hover-cursor: mouse hover and the panel keyboard cursor. -hover-cursor-color = "foreground" +hover-cursor-color = "{{ foreground }}" hover-cursor-fill-alpha = 0.08 hover-cursor-border-width = 1 hover-cursor-border-alpha = 0.25 +# Focus: Qt activeFocus. Mirror the hover-cursor values by default so +# mouse hover, keyboard cursor, and tab focus all read as the same state +# — themes that want focus to stand out override these four lines. +focus-color = "{{ foreground }}" +focus-fill-alpha = 0.08 +focus-border-width = 1 +focus-border-alpha = 0.25 + # Selected: persistent chosen/current state. -selected-color = "foreground" +selected-color = "{{ foreground }}" selected-fill-alpha = 0.18 selected-border-width = 0 selected-border-alpha = 1.0 -# Focus: Qt activeFocus; inherit hover-cursor unless intentionally different. -focus-color = "hover-cursor" -focus-fill-alpha = "hover-cursor" -focus-border-width = "hover-cursor" -focus-border-alpha = "hover-cursor" - # Momentary fills. pressed-fill-alpha = 0.22 selection-fill-alpha = 0.35 @@ -72,10 +74,10 @@ base-size = 12 # icon-large = 18 [popups] -# Shared by every bar flyout. Body text inside flyouts is not separately -# themable — it follows [bar].text. +# Shared by every bar flyout (dropdowns, OSD, popup cards). background = "{{ background }}" background-alpha = 1.0 +text = "{{ foreground }}" border = "{{ accent }}" border-alpha = 1.0 diff --git a/docs/omarchy-shell.md b/docs/omarchy-shell.md index d052d92f..27d62a8e 100644 --- a/docs/omarchy-shell.md +++ b/docs/omarchy-shell.md @@ -124,35 +124,37 @@ The shell exposes these tokens to QML via two singletons in ### Interactive states -`[style]` standardizes reusable control chrome around four states: -`normal`, `hover-cursor`, `selected`, and `focus`. State colors can be -palette roles (`foreground`, `accent`, `urgent`, `background`) or hex -strings. Fill/border alphas are applied to that state's color. +`[controls]` standardizes reusable control chrome (buttons, dropdowns, +tab strips, etc.) around four states: `normal`, `hover-cursor`, `focus`, +and `selected`. State colors accept palette roles (`foreground`, +`accent`, `urgent`, `background`) or hex strings; the default template +ships hex values. Fill/border alphas are applied to that state's color. -Focus inherits `hover-cursor` by default so mouse hover, the panel -keyboard cursor, and Qt activeFocus read as the same state. Use the -literal value `"hover-cursor"` on `focus-*` tokens to keep that -inheritance; set an explicit color/number only when a theme intentionally -wants focus to differ. +Surfaces like `[menu]`, `[app-launcher]`, and `[image-picker]` define +their own `selected-*` tokens and do **not** inherit from `[controls]`. +`[controls]` only governs the shared button/dropdown chrome. | State | Color token | Fill alpha | Border width | Border alpha | |-------|-------------|------------|--------------|--------------| | Normal idle chrome | `normal-color` | `normal-fill-alpha` | `normal-border-width` | `normal-border-alpha` | | Hover / keyboard cursor | `hover-cursor-color` | `hover-cursor-fill-alpha` | `hover-cursor-border-width` | `hover-cursor-border-alpha` | -| Persistent selected/current | `selected-color` | `selected-fill-alpha` | `selected-border-width` | `selected-border-alpha` | | Qt activeFocus | `focus-color` | `focus-fill-alpha` | `focus-border-width` | `focus-border-alpha` | +| Persistent selected/current | `selected-color` | `selected-fill-alpha` | `selected-border-width` | `selected-border-alpha` | + +The template ships `focus-*` adjacent to `hover-cursor-*` with the same +values so mouse hover, keyboard cursor, and tab focus read identically. +Themes that want focus to stand out override the four `focus-*` keys. Border widths are the theme-level on/off switches for state borders; set a width to `0` to keep the fill while removing that state border. The -default theme keeps selected borders off globally (`selected-border-width -= 0`); explicitly bordered controls can still keep their normal border -when selected. +default keeps selected borders off globally (`selected-border-width = +0`); explicitly bordered controls keep their normal border when selected. ```toml -[style] +[controls] # Accent-tinted cursor/focus, foreground-tinted selected state. hover-cursor-color = "accent" -focus-color = "hover-cursor" +focus-color = "accent" selected-color = "foreground" # Keep selected fills but remove selected-state borders. @@ -164,6 +166,10 @@ Momentary fills use `pressed-fill-alpha` for button press feedback and `pressed-color` or `selection-color`; they fall back to hover-cursor and foreground respectively. +The section was previously named `[style]`. Hand-written theme +`shell.toml` files using the old name still apply — the parser accepts +both `[controls]` and `[style]`. + ### Spacing `[spacing] scale` multiplies the shell's shared margins, gaps, and diff --git a/shell/Commons/Color.qml b/shell/Commons/Color.qml index 11de502a..fb02ecfc 100644 --- a/shell/Commons/Color.qml +++ b/shell/Commons/Color.qml @@ -65,6 +65,7 @@ QtObject { } readonly property QtObject popups: QtObject { property color background: root.composed("popups.background", "popups.background-alpha", root.background, 1.0) + property color text: root.pick("popups.text", root.foreground) property color border: root.composed("popups.border", "popups.border-alpha", root.pick("notifications.border", root.accent), 1.0) } readonly property QtObject tooltip: QtObject { diff --git a/shell/Commons/Style.qml b/shell/Commons/Style.qml index c5b180c6..2d37a8db 100644 --- a/shell/Commons/Style.qml +++ b/shell/Commons/Style.qml @@ -372,10 +372,10 @@ QtObject { } // Parse [font] base-size + per-token overrides, [bar] size-* keys, - // [style] state colors / alphas / border widths, and [spacing] scale + + // [controls] state colors / alphas / border widths, and [spacing] scale + // token overrides out of shell.toml. Color.qml owns the quoted-string // side of the surface color sections; Style owns quoted strings only - // inside [style]. + // inside [controls]. function loadShell(raw) { var fontOut = {} var barOut = {} @@ -393,7 +393,7 @@ QtObject { var sectionMatch = line.match(/^\[([A-Za-z0-9_-]+)\]\s*(#.*)?$/) if (sectionMatch) { section = sectionMatch[1]; continue } // Accept ints/floats for numeric tokens and quoted/bare words for - // [style] color roles / inheritance sentinels (e.g. "foreground", + // [controls] color roles / inheritance sentinels (e.g. "foreground", // "accent", "hover-cursor", "#c0caf5"). var numKv = line.match(/^([A-Za-z0-9_-]+)\s*=\s*(-?\d+(?:\.\d+)?)\s*(#.*)?$/) var stringKv = line.match(/^([A-Za-z0-9_-]+)\s*=\s*["']([^"']+)["']\s*(#.*)?$/) @@ -412,7 +412,10 @@ QtObject { var fval = parseFloat(rawValue) if (key === "scale") nextSpacingScale = fval else spacingOut[key] = fval - } else if (section === "style") { + } else if (section === "controls" || section === "style") { + // `[controls]` is the canonical section name; `[style]` is kept + // as a legacy alias so hand-written theme shell.toml files that + // predate the rename still apply. styleOut[key] = numKv ? parseFloat(rawValue) : rawValue } } diff --git a/shell/Ui/Button.qml b/shell/Ui/Button.qml index 1ad6df84..e870791b 100644 --- a/shell/Ui/Button.qml +++ b/shell/Ui/Button.qml @@ -13,7 +13,7 @@ import qs.Commons // idle transparent or normal border if `bordered` // // All fills/borders come from `qs.Commons.Style` tokens, so themes -// control the look via [style] in shell.toml. +// control the look via [controls] in shell.toml. // // Emits `hovered(bool)` so panels with their own keyboard cursor model // can update state on mouse enter/leave. diff --git a/shell/Ui/Dropdown.qml b/shell/Ui/Dropdown.qml index 820fe545..193543fb 100644 --- a/shell/Ui/Dropdown.qml +++ b/shell/Ui/Dropdown.qml @@ -22,7 +22,7 @@ Item { property string value: "" property var options: [] - property color foreground: Color.foreground + property color foreground: Color.popups.text property color background: Color.popups.background property color popupBorder: Color.popups.border property color accent: Color.accent diff --git a/shell/Ui/SearchableDropdown.qml b/shell/Ui/SearchableDropdown.qml index a230c4cd..3a1d5227 100644 --- a/shell/Ui/SearchableDropdown.qml +++ b/shell/Ui/SearchableDropdown.qml @@ -25,7 +25,7 @@ Item { property string emptyText: "No matches" property string triggerLabel: "" - property color foreground: Color.foreground + property color foreground: Color.popups.text property color background: Color.popups.background property color popupBorder: Color.popups.border property color accent: Color.accent diff --git a/shell/plugins/osd/Osd.qml b/shell/plugins/osd/Osd.qml index 40c38453..bf4d2e5c 100644 --- a/shell/plugins/osd/Osd.qml +++ b/shell/plugins/osd/Osd.qml @@ -107,14 +107,14 @@ Item { text: root.icon font.family: Style.font.family font.pixelSize: Style.font.displayLarge - color: Color.foreground + color: Color.popups.text } Rectangle { visible: root.hasProgress width: visible ? Style.space(142) : 0 height: Math.max(Style.space(6), Style.spacing.sm) anchors.verticalCenter: parent.verticalCenter - color: Color.alpha(Color.foreground, 0.45) + color: Color.alpha(Color.popups.text, 0.45) Rectangle { height: parent.height width: parent.width * (root.hasProgress ? root.value / root.maxValue : 0) @@ -128,7 +128,7 @@ Item { font.family: Style.font.family font.bold: true font.pixelSize: Style.font.title - color: Color.foreground + color: Color.popups.text elide: Text.ElideRight maximumLineCount: 1 clip: true