aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-15 11:16:09 +0200
committerDanilo M. <danix@danix.xyz>2026-09-15 11:16:09 +0200
commita9f3e65355b64577044467ca70ca16d00fba016b (patch)
treee23ba75ade9be67f194a6535d351f6a8fd9909ae
parentc90c72ed7d5bb5337319a053bf89d73fcb16c604 (diff)
downloadunified-desktop-theme-a9f3e65355b64577044467ca70ca16d00fba016b.tar.gz
unified-desktop-theme-a9f3e65355b64577044467ca70ca16d00fba016b.zip
feat(palette): add Sublime Text as a consumer
Two outputs, not one. The colour scheme themes the editor pane and tracks the wallpaper accent; the theme themes the UI chrome and sits on the scheme's fixed accent, because Sublime reads a theme once per window and a moving accent would leave open windows disagreeing with new ones. The colour scheme costs no new roles. Its scopes map onto the sixteen ANSI slots every scheme already declares, so all nine satisfy it and the identical-role-set selftest passes untouched. The theme is an override layered over Material Behave rather than a theme of its own: that theme hardcodes 419 rules of [r,g,b] literals with no variables, so the chrome surfaces are restated and its geometry, icons and animations are inherited. It installs under the name of the theme it overrides, because Sublime merges .sublime-theme files by filename with Packages/User last; under its own name it would never apply. It also has to follow Material Behave's material_theme_contrast_mode block and carry no settings gate, or contrast mode wins. The accent is replaced by matching the variable's current value rather than a placeholder: install.sh copies the file out of the repo, so after the first wallpaper change there is no placeholder left to substitute. udt-accent --selftest now covers that it stays idempotent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
-rw-r--r--.gitignore2
-rw-r--r--AGENTS.md41
-rwxr-xr-xbin/udt-accent38
-rwxr-xr-xbin/udt-palette52
-rwxr-xr-xinstall.sh27
-rw-r--r--templates/sublime/udt.sublime-color-scheme.in247
-rw-r--r--templates/sublime/udt.sublime-theme.in182
7 files changed, 583 insertions, 6 deletions
diff --git a/.gitignore b/.gitignore
index 8ab8278..6ffe055 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,5 @@ __pycache__/
/templates/obsidian/udt.css
/templates/typora/udt.css
/templates/homepage/custom.css
+/templates/sublime/udt.sublime-color-scheme
+/templates/sublime/udt.sublime-theme
diff --git a/AGENTS.md b/AGENTS.md
index d205bcd..0ecae09 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -6,7 +6,8 @@ Guidance for agents working in this repository.
One visual identity for a Hyprland desktop: Catppuccin Macchiato, Noto Sans for
UI text, Inconsolata Nerd Font Mono for monospace. It covers rofi, dunst,
-Hyprland window borders, conky, Qt5/Qt6, GTK3/GTK4, waybar, kitty and neovim.
+Hyprland window borders, conky, Qt5/Qt6, GTK3/GTK4, waybar, kitty, Sublime Text
+and neovim.
The repo holds the canonical copies. `./install.sh` symlinks them into place, so
the working config cannot drift from what is committed. Everything outside
@@ -40,7 +41,24 @@ switch into a diff. Editing one is pointless: the next install overwrites it.
The generated set is `rofi/udt/palette.rasi`, `templates/dunstrc`,
`templates/conky.conf`, `templates/waybar/theme.css`,
`templates/terminal/kitty-theme.conf`, `templates/homepage/custom.css`,
-`templates/kvantum/theme.{kvconfig,svg}` and `bin/udt_colors.py`.
+`templates/kvantum/theme.{kvconfig,svg}`,
+`templates/sublime/udt.sublime-color-scheme`,
+`templates/sublime/udt.sublime-theme` and `bin/udt_colors.py`.
+
+Sublime is two outputs, not one. The **colour scheme** is the editor pane and
+tracks the wallpaper accent. The **theme** is the UI chrome, and is an override
+layered over Material Behave: that theme hardcodes 419 rules of `[r,g,b]`
+literals with no variables, so the chrome surfaces are restated rather than
+remapped, and its geometry and icons are inherited untouched. Its accent is
+fixed, because Sublime reads a theme once per window.
+
+**The theme installs under the name of the theme it overrides**, `Material
+Behave.sublime-theme`, because Sublime merges `.sublime-theme` files by filename
+across packages with `Packages/User` last. Installed as `udt.sublime-theme` it
+would be an unselected theme that never applies. It also has to come after
+Material Behave's own `material_theme_contrast_mode` block, which re-tints the
+sidebar and status bar, and carry no settings gate of its own, or contrast mode
+wins. Removing the Materialize package leaves the override inert.
Qt and GTK apps reach the palette through Kvantum. Its theme is a `.kvconfig`
of colours plus a `.svg` of widget artwork with the colours baked into the
@@ -95,10 +113,19 @@ One colour moves: `@accent`. `bin/udt-accent` reads the current wallpaper,
extracts its signature colour, and snaps it to the nearest of ten Catppuccin
accents by perceptual hue in CIELAB. `wallp` calls it on every wallpaper change.
-It writes five things: `~/.cache/wal/udt-accent.rasi` (rofi),
+It writes six things: `~/.cache/wal/udt-accent.rasi` (rofi),
`~/.cache/wal/udt-border.lua` (Hyprland), the accent substitution in
`~/.cache/wal/dunstrc`, `~/.cache/wal/colors.json` (Firefox, via
-pywalfox), and `~/.cache/wal/udt-palette.qml` (quickshell).
+pywalfox), `~/.cache/wal/udt-palette.qml` (quickshell), and the accent
+substitution in Sublime's installed
+`Packages/User/udt.sublime-color-scheme`.
+
+**Sublime's accent is replaced, not substituted into a placeholder.** Its
+colour scheme cannot cascade, so the accent has to live in the one generated
+file rather than arriving as a second one, and `install.sh` copies that file
+out of the repo. `write_sublime` therefore rewrites the `"accent"` variable
+line by matching its current value, which makes it idempotent across
+wallpaper changes; a placeholder would survive only the first run.
The QML palette is the one output that is not only the accent: it carries
the whole structural palette too, parsed out of `rofi/udt/palette.rasi`
@@ -123,8 +150,9 @@ the terminal palette stays fixed no matter what the wallpaper looks like. The
write lands after `wallp` has already run `wal --theme`, so it wins; reorder
those two and pywal's wallpaper-derived colours come back.
-Not everything tracks the wallpaper. rofi, dunst, Hyprland borders and Firefox
-do; conky, Qt, GTK and waybar sit on fixed lavender, which is also the fallback
+Not everything tracks the wallpaper. rofi, dunst, Hyprland borders, Sublime's
+colour scheme and Firefox do; conky, Qt, GTK, waybar and Sublime's UI chrome sit
+on fixed lavender, which is also the fallback
when a wallpaper is too grey to snap. Qt and GTK apps only reread a theme on restart,
so a moving accent there would leave running apps disagreeing with new ones.
@@ -206,5 +234,6 @@ The table is what it does, and what to run if you change a config by hand.
| Hyprland | `hyprctl reload` |
| waybar | `killall -SIGUSR2 waybar` |
| kitty | `pkill -USR1 -x kitty` |
+| Sublime Text | nothing; it watches `Packages/User` and reloads both the scheme and the theme |
| conky | restart it; no hot-reload |
| Qt / GTK apps | restart the app |
diff --git a/bin/udt-accent b/bin/udt-accent
index 75058df..1a542a6 100755
--- a/bin/udt-accent
+++ b/bin/udt-accent
@@ -32,6 +32,8 @@ MIN_CHROMA = 10.0
OUTPUT = Path.home() / ".cache" / "wal" / "udt-accent.rasi"
BORDER_OUTPUT = Path.home() / ".cache" / "wal" / "udt-border.lua"
DUNSTRC = Path.home() / ".cache" / "wal" / "dunstrc"
+SUBLIME = (Path.home() / ".config" / "sublime-text" / "Packages" / "User"
+ / "udt.sublime-color-scheme")
QML_OUTPUT = Path.home() / ".cache" / "wal" / "udt-palette.qml"
# The installed rofi palette, itself generated by udt-palette. Read rather than
@@ -280,6 +282,29 @@ def write_dunst(name):
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+def write_sublime(name):
+ """Substitute the accent into the Sublime colour scheme install.sh copied.
+
+ In place, like dunst: Sublime colour schemes do not cascade, so the accent
+ cannot arrive as a second file. Sublime watches Packages/User and reloads a
+ scheme when its file changes, so no signal is needed. A missing file is not
+ an error, Sublime simply may not be installed here.
+
+ Unlike dunst, this reads the installed copy and has nowhere to recover
+ @ACCENT@ from once substituted, so the previous accent is replaced by
+ matching the variable line rather than a placeholder.
+ """
+ try:
+ text = SUBLIME.read_text()
+ except FileNotFoundError:
+ return
+
+ new, count = re.subn(r'("accent":\s*)"[^"]*"',
+ lambda m: f'{m.group(1)}"{ACCENTS[name]}"', text, count=1)
+ if count and new != text:
+ write_atomic(SUBLIME, new)
+
+
def main(image):
try:
name = snap(signature_color(image))
@@ -292,6 +317,7 @@ def main(image):
write_border(name)
write_qml(name)
write_dunst(name)
+ write_sublime(name)
write_colors_json(name, image)
# Hyprland only rereads its config on request, and may not be running.
@@ -316,6 +342,18 @@ def selftest():
delta = min(delta, 2 * math.pi - delta)
assert delta < 0.6, f"{probe} snapped to {got}, {delta:.2f} rad away"
+ # The Sublime accent is replaced by matching its current value, not a
+ # placeholder, so it has to survive being run twice: once over the freshly
+ # installed @ACCENT@, and again over the accent it wrote last time.
+ probe = '{\n "variables":\n {\n "accent": "@ACCENT@",\n'
+ first, n1 = re.subn(r'("accent":\s*)"[^"]*"', r'\1"#f5a97f"', probe, count=1)
+ second, n2 = re.subn(r'("accent":\s*)"[^"]*"', r'\1"#8bd5ca"', first, count=1)
+ third, n3 = re.subn(r'("accent":\s*)"[^"]*"', r'\1"#8bd5ca"', second, count=1)
+ assert (n1, n2, n3) == (1, 1, 1), (n1, n2, n3)
+ assert "@ACCENT@" not in first and '"#f5a97f"' in first
+ assert '"#f5a97f"' not in second and '"#8bd5ca"' in second
+ assert third == second, "accent substitution is not idempotent"
+
# A near-grey has an unstable hue angle and must take the fallback.
assert snap("#888888") == FALLBACK, snap("#888888")
assert FALLBACK in ACCENTS, FALLBACK
diff --git a/bin/udt-palette b/bin/udt-palette
index a746766..ceed64d 100755
--- a/bin/udt-palette
+++ b/bin/udt-palette
@@ -106,6 +106,12 @@ def hex8(c):
return f"#{r:02x}{g:02x}{b:02x}{round(a * 255 / 100):02x}"
+def rgb_array(c):
+ """[r, g, b], which is how a .sublime-theme writes a colour."""
+ r, g, b, _ = c
+ return f"[{r}, {g}, {b}]"
+
+
def rgba(c):
r, g, b, a = c
return f"rgb({r},{g},{b})" if a == 100 else f"rgba({r},{g},{b},{a / 100:.2f})"
@@ -422,6 +428,48 @@ def gen_dunst(res, scheme, palette, template):
return out
+def gen_sublime(res, scheme, palette, template):
+ """Sublime Text: substitute the palette into the colour scheme.
+
+ Scopes map onto the terminal roles rather than onto syntax roles of their
+ own. A scheme already declares all sixteen ANSI slots, so a syntax theme
+ costs no new roles and every shipped scheme satisfies it without touching
+ nine role maps.
+
+ @ACCENT@ is left alone for udt-accent, exactly as in the dunst template:
+ Sublime colour schemes do not cascade, so the accent cannot arrive as a
+ second file and has to be substituted into this one.
+ """
+ out = template.replace("@SCHEME@", scheme)
+ for role in ("bg", "bg_alt", "bg_deep", "surface", "surface_alt",
+ "fg", "fg_dim", "fg_faint",
+ "red", "green", "yellow", "blue", "magenta", "cyan",
+ "critical", "warning", "success", "info"):
+ out = out.replace(f"@{role.upper()}@", hex6(res[role]))
+ # The selection has to be translucent or it hides the text under it, and
+ # selection_bg resolves opaque because the terminal wants it that way.
+ out = out.replace("@SELECTION_BG@", hex8((*res["selection_bg"][:3], 35)))
+ return out
+
+
+def gen_sublime_theme(res, scheme, palette, template):
+ """Sublime Text: the UI chrome, as an override layered over Material Behave.
+
+ A .sublime-theme writes colours as [r, g, b] arrays rather than hex, so this
+ substitutes a different syntax from the colour scheme next door out of the
+ same roles.
+
+ The accent is the scheme's fixed one, not the wallpaper's: Sublime reads a
+ theme once per window, so a moving accent would leave open windows
+ disagreeing with new ones. Same reasoning as conky, Qt, GTK and waybar.
+ """
+ out = template.replace("@SCHEME@", scheme)
+ for role in ("bg", "bg_alt", "bg_deep", "fg", "fg_dim", "fg_faint",
+ "accent"):
+ out = out.replace(f"@{role.upper()}@", rgb_array(res[role]))
+ return out
+
+
def gen_conky(res, scheme, palette, template):
"""conky: substitute into the shipped template.
@@ -539,6 +587,10 @@ TARGETS = [
("templates/typora/udt.css", gen_typora, "templates/typora/udt.css.in"),
("templates/kvantum/theme.kvconfig", gen_kvantum, "templates/kvantum/theme.kvconfig.in"),
("templates/kvantum/theme.svg", gen_kvantum, "templates/kvantum/theme.svg.in"),
+ ("templates/sublime/udt.sublime-color-scheme", gen_sublime,
+ "templates/sublime/udt.sublime-color-scheme.in"),
+ ("templates/sublime/udt.sublime-theme", gen_sublime_theme,
+ "templates/sublime/udt.sublime-theme.in"),
]
diff --git a/install.sh b/install.sh
index 2083292..cdcdc99 100755
--- a/install.sh
+++ b/install.sh
@@ -61,6 +61,33 @@ fi
install -Dm644 "$repo/templates/terminal/kitty-theme.conf" \
"$HOME/.config/kitty/current-theme.conf"
+# Sublime Text. Copied into Packages/User, which Sublime watches, so writing it
+# reaches a running editor. The file still carries @ACCENT@, which udt-accent
+# substitutes below; selecting it is a separate step because color_scheme lives
+# in Preferences.sublime-settings alongside settings that are none of our
+# business, so only that one key is rewritten, and only if it is not ours yet.
+subl="$HOME/.config/sublime-text/Packages/User"
+if [ -d "$subl" ]; then
+ install -Dm644 "$repo/templates/sublime/udt.sublime-color-scheme" \
+ "$subl/udt.sublime-color-scheme"
+ # The UI chrome is an override, and Sublime merges .sublime-theme files by
+ # FILENAME across packages with User last. So it has to be installed under
+ # the name of the theme it layers over, not under a name of its own: called
+ # udt.sublime-theme it would be an unselected theme that never applies.
+ # Renaming it here rather than in the repo keeps the source name obvious.
+ behave="$subl/Material Behave.sublime-theme"
+ if [ -f "$behave" ] && ! grep -q 'Generated by udt-palette' "$behave"; then
+ cp "$behave" "$behave.pre-udt"
+ echo "sublime: kept your theme override as $(basename "$behave").pre-udt"
+ fi
+ install -Dm644 "$repo/templates/sublime/udt.sublime-theme" "$behave"
+ prefs="$subl/Preferences.sublime-settings"
+ if [ -f "$prefs" ] && ! grep -q '"color_scheme".*udt\.sublime-color-scheme' "$prefs"; then
+ sed -i 's|"color_scheme":[[:space:]]*"[^"]*"|"color_scheme": "Packages/User/udt.sublime-color-scheme"|' "$prefs"
+ echo "sublime: color_scheme switched to udt"
+ fi
+fi
+
# Kvantum wants a directory per theme, named after itself, and qt5ct/qt6ct
# reach Qt apps through it. The theme is installed under one fixed name rather
# than one per scheme: Kvantum caches by name, so reusing it means a switch
diff --git a/templates/sublime/udt.sublime-color-scheme.in b/templates/sublime/udt.sublime-color-scheme.in
new file mode 100644
index 0000000..30eed18
--- /dev/null
+++ b/templates/sublime/udt.sublime-color-scheme.in
@@ -0,0 +1,247 @@
+// Generated by udt-palette from palette/@SCHEME@.conf. Do not edit.
+//
+// A Sublime Text color scheme is JSON with comments. Colour scopes map onto the
+// terminal roles rather than onto syntax-specific roles of their own: a scheme
+// already declares all sixteen ANSI slots, so a syntax theme costs no new roles
+// and every shipped scheme satisfies it without editing nine role maps.
+//
+// @ACCENT@ is left for udt-accent, which substitutes it per wallpaper and
+// rewrites this file in place. Sublime watches Packages/User and reloads a
+// colour scheme when its file changes, so that reaches a running editor.
+{
+ "name": "UDT",
+ "author": "udt-palette (@SCHEME@)",
+ "variables":
+ {
+ "bg": "@BG@",
+ "bg_alt": "@BG_ALT@",
+ "bg_deep": "@BG_DEEP@",
+ "surface": "@SURFACE@",
+ "surface_alt": "@SURFACE_ALT@",
+
+ "fg": "@FG@",
+ "fg_dim": "@FG_DIM@",
+ "fg_faint": "@FG_FAINT@",
+
+ "accent": "@ACCENT@",
+
+ "red": "@RED@",
+ "green": "@GREEN@",
+ "yellow": "@YELLOW@",
+ "blue": "@BLUE@",
+ "magenta": "@MAGENTA@",
+ "cyan": "@CYAN@",
+
+ "critical": "@CRITICAL@",
+ "warning": "@WARNING@",
+ "success": "@SUCCESS@",
+ "info": "@INFO@"
+ },
+ "globals":
+ {
+ "background": "var(bg)",
+ "foreground": "var(fg)",
+ "caret": "var(accent)",
+ "block_caret": "var(accent)",
+ "invisibles": "var(fg_faint)",
+ "line_highlight": "var(surface)",
+ "selection": "@SELECTION_BG@",
+ "selection_border": "var(accent)",
+ "inactive_selection": "var(surface)",
+ "misspelling": "var(critical)",
+ "gutter": "var(bg)",
+ "gutter_foreground": "var(fg_faint)",
+ "guide": "var(surface)",
+ "active_guide": "var(accent)",
+ "stack_guide": "var(surface_alt)",
+ "find_highlight": "var(warning)",
+ "find_highlight_foreground": "var(bg)",
+ "shadow": "var(bg_deep)"
+ },
+ "rules":
+ [
+ {
+ "name": "Comment",
+ "scope": "comment, punctuation.definition.comment",
+ "foreground": "var(fg_faint)",
+ "font_style": "italic"
+ },
+ {
+ "name": "String",
+ "scope": "string, constant.other.symbol",
+ "foreground": "var(green)"
+ },
+ {
+ "name": "Escape sequence",
+ "scope": "constant.character.escape, constant.other.placeholder",
+ "foreground": "var(magenta)"
+ },
+ {
+ "name": "Number",
+ "scope": "constant.numeric",
+ "foreground": "var(yellow)"
+ },
+ {
+ "name": "Built-in constant",
+ "scope": "constant.language",
+ "foreground": "var(yellow)"
+ },
+ {
+ "name": "User-defined constant",
+ "scope": "constant.character, constant.other",
+ "foreground": "var(yellow)"
+ },
+ {
+ "name": "Variable",
+ "scope": "variable",
+ "foreground": "var(fg)"
+ },
+ {
+ "name": "Member",
+ "scope": "variable.other.member, meta.property variable",
+ "foreground": "var(cyan)"
+ },
+ {
+ "name": "Language variable",
+ "scope": "variable.language",
+ "foreground": "var(magenta)",
+ "font_style": "italic"
+ },
+ {
+ "name": "Keyword",
+ "scope": "keyword, keyword.operator.word",
+ "foreground": "var(magenta)"
+ },
+ {
+ "name": "Operator",
+ "scope": "keyword.operator",
+ "foreground": "var(cyan)"
+ },
+ {
+ "name": "Storage",
+ "scope": "storage, storage.modifier",
+ "foreground": "var(magenta)"
+ },
+ {
+ "name": "Storage type",
+ "scope": "storage.type",
+ "foreground": "var(blue)",
+ "font_style": "italic"
+ },
+ {
+ "name": "Class name",
+ "scope": "entity.name.class, entity.name.struct, entity.name.type",
+ "foreground": "var(yellow)",
+ "font_style": "italic"
+ },
+ {
+ "name": "Inherited class",
+ "scope": "entity.other.inherited-class",
+ "foreground": "var(yellow)",
+ "font_style": "italic"
+ },
+ {
+ "name": "Function name",
+ "scope": "entity.name.function, variable.function",
+ "foreground": "var(blue)"
+ },
+ {
+ "name": "Function argument",
+ "scope": "variable.parameter",
+ "foreground": "var(accent)",
+ "font_style": "italic"
+ },
+ {
+ "name": "Section or namespace",
+ "scope": "entity.name.namespace, entity.name.section",
+ "foreground": "var(accent)"
+ },
+ {
+ "name": "Tag name",
+ "scope": "entity.name.tag",
+ "foreground": "var(magenta)"
+ },
+ {
+ "name": "Tag attribute",
+ "scope": "entity.other.attribute-name",
+ "foreground": "var(yellow)",
+ "font_style": "italic"
+ },
+ {
+ "name": "Library function",
+ "scope": "support.function",
+ "foreground": "var(cyan)"
+ },
+ {
+ "name": "Library constant",
+ "scope": "support.constant",
+ "foreground": "var(yellow)"
+ },
+ {
+ "name": "Library class/type",
+ "scope": "support.class, support.type, support.other.namespace",
+ "foreground": "var(yellow)",
+ "font_style": "italic"
+ },
+ {
+ "name": "Punctuation",
+ "scope": "punctuation, meta.brace, meta.delimiter",
+ "foreground": "var(fg_dim)"
+ },
+ {
+ "name": "Invalid",
+ "scope": "invalid",
+ "foreground": "var(bg)",
+ "background": "var(critical)"
+ },
+ {
+ "name": "Invalid deprecated",
+ "scope": "invalid.deprecated",
+ "foreground": "var(bg)",
+ "background": "var(warning)"
+ },
+ {
+ "name": "Markup heading",
+ "scope": "markup.heading, entity.name.section",
+ "foreground": "var(accent)",
+ "font_style": "bold"
+ },
+ {
+ "name": "Markup link",
+ "scope": "markup.underline.link, string.other.link",
+ "foreground": "var(info)",
+ "font_style": "underline"
+ },
+ {
+ "name": "Markup bold",
+ "scope": "markup.bold",
+ "font_style": "bold"
+ },
+ {
+ "name": "Markup italic",
+ "scope": "markup.italic",
+ "font_style": "italic"
+ },
+ {
+ "name": "Markup raw",
+ "scope": "markup.raw, markup.inline.raw",
+ "foreground": "var(warning)",
+ "background": "var(bg_alt)"
+ },
+ {
+ "name": "Diff inserted",
+ "scope": "markup.inserted",
+ "foreground": "var(success)"
+ },
+ {
+ "name": "Diff deleted",
+ "scope": "markup.deleted",
+ "foreground": "var(critical)"
+ },
+ {
+ "name": "Diff changed",
+ "scope": "markup.changed",
+ "foreground": "var(warning)"
+ }
+ ]
+}
diff --git a/templates/sublime/udt.sublime-theme.in b/templates/sublime/udt.sublime-theme.in
new file mode 100644
index 0000000..17d1c1a
--- /dev/null
+++ b/templates/sublime/udt.sublime-theme.in
@@ -0,0 +1,182 @@
+// Generated by udt-palette from palette/@SCHEME@.conf. Do not edit.
+//
+// An override layered over Material Behave, not a theme of its own. Sublime
+// merges every .sublime-theme of the same name across packages, User last, so
+// this file re-colours that theme's chrome and inherits its geometry, icons and
+// animations untouched. Rename it and it stops applying.
+//
+// Material Behave hardcodes 419 rules of [r,g,b] literals with no variables to
+// override, so the surfaces are restated here rather than remapped. Only colour
+// is set: sizes, margins and opacities belong to the parent theme.
+//
+// Ordering matters. Material Behave ends with a contrast-mode block gated on
+// "material_theme_contrast_mode", which re-tints the sidebar, status bar and
+// panels a shade darker. Later rules win, so these come after it and carry no
+// settings gate of their own, which is what makes them apply either way.
+//
+// Colours are [r,g,b] arrays because that is what a .sublime-theme takes; the
+// colour scheme next door uses hex. Same palette, two syntaxes.
+//
+// The chrome does NOT track the wallpaper, unlike the colour scheme's accent.
+// Sublime reads a theme once per window, so a moving accent would leave open
+// windows disagreeing with new ones. The accent here is the scheme's fixed one,
+// which is what conky, Qt, GTK and waybar already sit on.
+[
+ // Editor ground, behind the tabs and in an empty window.
+ {
+ "class": "sheet_container_control",
+ "layer0.tint": @BG@
+ },
+
+ // Tab bar. The strip itself sits a shade off the editor so tabs read as
+ // raised; the selected tab matches the editor it belongs to.
+ {
+ "class": "tabset_control",
+ "layer0.tint": @BG_DEEP@
+ },
+ {
+ "class": "tab_control",
+ "layer0.tint": @BG_ALT@
+ },
+ {
+ "class": "tab_control",
+ "attributes": ["selected"],
+ "layer0.tint": @BG@
+ },
+ {
+ "class": "tab_label",
+ "fg": @FG_FAINT@
+ },
+ {
+ "class": "tab_label",
+ "parents": [{"class": "tab_control", "attributes": ["selected"]}],
+ "fg": @FG@
+ },
+
+ // Sidebar.
+ {
+ "class": "sidebar_container",
+ "layer0.tint": @BG_ALT@
+ },
+ {
+ "class": "sidebar_tree",
+ "layer0.tint": @BG_ALT@
+ },
+ {
+ "class": "sidebar_label",
+ "fg": @FG_DIM@
+ },
+ {
+ "class": "sidebar_label",
+ "parents": [{"class": "tree_row", "attributes": ["selected"]}],
+ "fg": @FG@
+ },
+ {
+ "class": "sidebar_heading",
+ "fg": @FG_FAINT@
+ },
+ // The hover and selection wash behind a row. Its opacity is the parent
+ // theme's; only the tint is ours.
+ {
+ "class": "tree_row",
+ "layer1.tint": @ACCENT@
+ },
+
+ // Status bar. Material Behave paints a hidden layer0 and a visible layer1,
+ // so both are set or the bar changes colour as it redraws.
+ {
+ "class": "status_bar",
+ "layer0.tint": @BG_ALT@,
+ "layer1.tint": @BG_ALT@
+ },
+ {
+ "class": "status_button",
+ "layer0.tint": @BG_ALT@
+ },
+ {
+ "class": "label_control",
+ "parents": [{"class": "status_bar"}],
+ "fg": @FG_DIM@
+ },
+
+ // Find, replace and the console.
+ {
+ "class": "panel_control",
+ "layer0.tint": @BG_ALT@,
+ "layer1.tint": @BG_ALT@
+ },
+ {
+ "class": "panel_button_control",
+ "layer0.tint": @BG_ALT@
+ },
+
+ // Command palette, goto-anything and autocomplete.
+ {
+ "class": "quick_panel",
+ "layer0.tint": @BG_ALT@
+ },
+ {
+ "class": "quick_panel_label",
+ "fg": @FG_DIM@
+ },
+ {
+ "class": "quick_panel_label",
+ "parents": [{"class": "quick_panel_row", "attributes": ["selected"]}],
+ "fg": @FG@
+ },
+ {
+ "class": "quick_panel_score_label",
+ "fg": @ACCENT@
+ },
+ {
+ "class": "quick_panel_path_label",
+ "fg": @FG_FAINT@
+ },
+ {
+ "class": "auto_complete",
+ "layer0.tint": @BG_ALT@
+ },
+ {
+ "class": "auto_complete_label",
+ "fg": @FG_DIM@
+ },
+ {
+ "class": "popup_control",
+ "layer0.tint": @BG_ALT@
+ },
+ {
+ "class": "dialog",
+ "layer0.tint": @BG_ALT@
+ },
+
+ // Tooltips, and the progress widgets that Material Behave tints per accent.
+ {
+ "class": "tool_tip_control",
+ "layer0.tint": @BG_DEEP@
+ },
+ {
+ "class": "tool_tip_label_control",
+ "fg": @FG_DIM@
+ },
+ {
+ "class": "progress_gauge_control",
+ "layer0.tint": @ACCENT@
+ },
+
+ // Scrollbars and the minimap viewport.
+ {
+ "class": "scroll_bar_control",
+ "layer0.tint": @BG_DEEP@
+ },
+ {
+ "class": "puck_control",
+ "layer0.tint": @FG_FAINT@
+ },
+
+ // Title bar, on the platforms and settings where Material Behave draws it.
+ {
+ "class": "title_bar",
+ "bg": @BG_DEEP@,
+ "fg": @FG_DIM@
+ }
+]