Consolidate omarchy-shell colors into a single shell.toml surface

Five plugins each owned their own colors.toml watcher with subtly
different parsers, plus two ad-hoc per-theme override files
(notifications.json, image-picker-colors.json). This collapses all of
that into one source of truth: Commons/Color.qml watches colors.toml +
shell.toml and exposes Color.bar.*, Color.popups.*, Color.notifications.*,
Color.menu.*, Color.imagePicker.* for every surface to bind to.

shell.toml is generated by the existing template pipeline from
default/themed/shell.toml.tpl. Themes can ship their own shell.toml to
override individual keys; everything missing falls back to the
foundational palette via root.pick(). Settings panel is intentionally
not themable beyond the foundational tokens.

last-horizon and solitude ship a minimal shell.toml to preserve their
historical 'notification border matches Hyprland active border'
behavior, which previously came from parsing the theme's hyprland.conf
(now removed).
This commit is contained in:
Ryan Hughes
2026-05-16 00:30:27 -04:00
parent 227d32544f
commit f404a81c6a
14 changed files with 199 additions and 298 deletions
@@ -9,6 +9,7 @@ import Quickshell.Wayland
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.Commons
import "common" as BarCommon
Item {
@@ -49,9 +50,11 @@ Item {
// "monospace" resolves through fontconfig at paint time, so changing the
// system font (via `omarchy-font-set`) updates the bar without a reload.
property string fontFamily: "monospace"
property color foreground: "#cacccc"
property color background: "#101315"
property color urgent: "#a55555"
// Bound to the central Color singleton so the bar tracks shell.toml's
// [bar] section. Property names kept for the rest of this file's bindings.
property color foreground: Color.bar.text
property color background: Color.bar.background
property color urgent: Color.bar.active
property string weatherText: ""
property string weatherClass: ""
property bool updateAvailable: false
@@ -438,18 +441,6 @@ Item {
}
}
function loadTheme(raw) {
var lines = String(raw || "").split("\n")
for (var i = 0; i < lines.length; i++) {
var match = lines[i].match(/^\s*([A-Za-z0-9_-]+)\s*=\s*["']?(#[0-9A-Fa-f]{6})/)
if (!match) continue
if (match[1] === "foreground") foreground = match[2]
else if (match[1] === "background") background = match[2]
else if (match[1] === "red") urgent = match[2]
}
}
function updateWeather(raw) {
var data = parseModuleJson(raw)
weatherText = data.text || ""
@@ -723,26 +714,6 @@ Item {
onTriggered: root.tooltipShown = true
}
// The host owns shell.json loading and injects `barConfig`. Bar still keeps
// its own theme FileView since theme colors are independent of shell.json.
// `omarchy-theme-set` recreates the entire theme/ directory via rm+mv, which
// invalidates the inotify watch on colors.toml. Use theme.name (overwritten
// in place) to force a fresh reload after each swap.
FileView {
id: themeColorsFile
path: root.home + "/.config/omarchy/current/theme/colors.toml"
watchChanges: true
printErrors: false
onLoaded: root.loadTheme(text())
onFileChanged: reload()
}
FileView {
path: root.home + "/.config/omarchy/current/theme.name"
watchChanges: true
printErrors: false
onFileChanged: themeColorsFile.reload()
}
// Presence of the `bar-off` flag = bar hidden. Watching the parent toggles
// directory because FileView can't observe a file that doesn't exist yet,
// and the flag is created/removed by `omarchy-toggle-bar`.
@@ -1,6 +1,7 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import qs.Commons
PopupWindow {
id: root
@@ -89,8 +90,8 @@ PopupWindow {
Rectangle {
id: card
anchors.fill: parent
color: root.bar ? root.bar.background : "#101315"
border.color: root.bar ? root.bar.foreground : "#cacccc"
color: Color.popups.background
border.color: Color.popups.border
border.width: 1
radius: 0
opacity: root.open ? 1.0 : 0