Bring on gradient borders
This commit is contained in:
+296
@@ -0,0 +1,296 @@
|
||||
# Omarchy theming
|
||||
|
||||
Omarchy themes live under `themes/<name>/` in the source tree, with optional
|
||||
user themes under `~/.config/omarchy/themes/<name>/`. A theme normally starts
|
||||
with a `colors.toml`; Omarchy generates the rest of the theme files from
|
||||
`default/themed/*.tpl` when `omarchy-theme-set <name>` runs.
|
||||
|
||||
## Theme activation flow
|
||||
|
||||
`omarchy-theme-set <name>` builds a clean staging directory at
|
||||
`~/.config/omarchy/current/next-theme`:
|
||||
|
||||
1. Copy the first-party theme from `themes/<name>/`.
|
||||
2. Overlay any user theme files from `~/.config/omarchy/themes/<name>/`.
|
||||
3. If needed, generate `colors.toml` from `alacritty.toml`.
|
||||
4. Run `omarchy-theme-set-templates` to render templates into the staging
|
||||
theme.
|
||||
5. Move the staging theme into `~/.config/omarchy/current/theme` and notify the
|
||||
running shell.
|
||||
|
||||
Template rendering only happens when the staged theme has `colors.toml`.
|
||||
Existing files are never overwritten by a template, so a hand-written
|
||||
`themes/<name>/shell.toml` or `hyprland.lua` wins over
|
||||
`default/themed/shell.toml.tpl` or `hyprland.lua.tpl`.
|
||||
|
||||
User templates in `~/.config/omarchy/themed/*.tpl` are processed before the
|
||||
built-in templates. If a user template has the same output filename as a
|
||||
built-in template, the built-in output is skipped.
|
||||
|
||||
## `colors.toml`
|
||||
|
||||
`colors.toml` provides the palette keys used by templates. Common keys are:
|
||||
|
||||
```toml
|
||||
foreground = "#a9b1d6"
|
||||
background = "#1a1b26"
|
||||
accent = "#7aa2f7"
|
||||
color1 = "#f7768e"
|
||||
color4 = "#7aa2f7"
|
||||
```
|
||||
|
||||
Any key can be referenced from a template with `{{ key }}`. The shell also
|
||||
uses a few semantic palette keys directly:
|
||||
|
||||
- `foreground`
|
||||
- `background`
|
||||
- `accent` — preferred when present; otherwise some places fall back to
|
||||
`color4`
|
||||
- `urgent` / `color1`
|
||||
|
||||
## Template placeholders
|
||||
|
||||
Templates are plain files ending in `.tpl`. `omarchy-theme-set-templates`
|
||||
replaces placeholders with values from `colors.toml`.
|
||||
|
||||
### Color placeholders
|
||||
|
||||
For a color key such as `accent = "#7aa2f7"`:
|
||||
|
||||
| Placeholder | Output |
|
||||
|-------------|--------|
|
||||
| `{{ accent }}` | `#7aa2f7` |
|
||||
| `{{ accent_strip }}` | `7aa2f7` |
|
||||
| `{{ accent_rgb }}` | `122,162,247` |
|
||||
|
||||
### Color mixing
|
||||
|
||||
`mix`, `mix_strip`, and `mix_rgb` blend two hex colors by a fraction or
|
||||
percentage:
|
||||
|
||||
```text
|
||||
{{ mix background foreground 15% }}
|
||||
{{ mix_strip background accent 0.35 }}
|
||||
{{ mix_rgb color0 color7 50 }}
|
||||
```
|
||||
|
||||
### Gradient helpers
|
||||
|
||||
Some theme keys can be either a solid color or a Hyprland-style gradient:
|
||||
|
||||
```toml
|
||||
hyprland_active_border = "rgba(33ccffee) rgba(00ff99ee) 45deg"
|
||||
```
|
||||
|
||||
Gradient helper placeholders understand those values:
|
||||
|
||||
| Helper | Use | Example output |
|
||||
|--------|-----|----------------|
|
||||
| `{{ hypr_gradient hyprland_active_border accent }}` | Hyprland Lua config | `{ colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }` |
|
||||
| `{{ shell_gradient hyprland_active_border accent }}` | shell border tokens | `rgba(33ccffee) rgba(00ff99ee) 45deg` |
|
||||
| `{{ gradient_start hyprland_active_border accent }}` | flat-color-only consumers | `#33ccff` |
|
||||
|
||||
The second argument is a fallback. For example,
|
||||
`{{ shell_gradient hyprland_active_border accent }}` means: use
|
||||
`hyprland_active_border` if the theme defines it; otherwise use `accent`.
|
||||
The helper does not choose the first color unless you use `gradient_start`.
|
||||
|
||||
## `shell.toml`
|
||||
|
||||
`shell.toml` contains shell surface roles, control states, spacing, typography,
|
||||
and bar sizing. The default generated file comes from
|
||||
`default/themed/shell.toml.tpl`.
|
||||
|
||||
The running shell reads `shell.toml` into two QML singletons:
|
||||
|
||||
- `Color` for palette and surface roles like `Color.menu.border`.
|
||||
- `Style` for controls, spacing, font scale, corner radius, and bar sizing.
|
||||
|
||||
### Borders
|
||||
|
||||
Shell border tokens accept either a solid color or a gradient in the same key:
|
||||
|
||||
```toml
|
||||
[notifications]
|
||||
border = "#7aa2f7"
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```toml
|
||||
[notifications]
|
||||
border = "rgba(33ccffee) rgba(00ff99ee) 45deg"
|
||||
```
|
||||
|
||||
Do not add a separate `border-gradient` key for new themes. The parser still
|
||||
accepts `border-gradient` and `*-border-gradient` for compatibility with older
|
||||
configs, but the canonical form is the border key itself.
|
||||
|
||||
Border alphas apply to solid borders and to every gradient stop:
|
||||
|
||||
```toml
|
||||
[notifications]
|
||||
border = "rgba(33ccffee) rgba(00ff99ee) 45deg"
|
||||
border-alpha = 0.8
|
||||
```
|
||||
|
||||
If a color stop already includes alpha, the stop alpha and `border-alpha` are
|
||||
combined.
|
||||
|
||||
### Border widths
|
||||
|
||||
Border widths accept CSS-style lists:
|
||||
|
||||
```toml
|
||||
border-width = 2 # all sides
|
||||
border-width = "2 4" # top/bottom, right/left
|
||||
border-width = "2 4 6" # top, right/left, bottom
|
||||
border-width = "2 4 6 8" # top, right, bottom, left
|
||||
```
|
||||
|
||||
Per-side keys override the list:
|
||||
|
||||
```toml
|
||||
[notifications]
|
||||
border-width = 2
|
||||
border-width-left = 6
|
||||
```
|
||||
|
||||
That gives notifications a 2px border on the top, right, and bottom, and a 6px
|
||||
left edge.
|
||||
|
||||
State-specific borders follow the same pattern. A selected menu row can use a
|
||||
different width from the card border:
|
||||
|
||||
```toml
|
||||
[menu]
|
||||
selected-border = "accent"
|
||||
selected-border-width = "1 1 1 4"
|
||||
```
|
||||
|
||||
For state-specific surfaces such as lock and polkit, the token name prefixes
|
||||
the width key:
|
||||
|
||||
```toml
|
||||
[lock]
|
||||
border-active = "rgba(33ccffee) rgba(00ff99ee) 45deg"
|
||||
border-active-width-left = 6
|
||||
```
|
||||
|
||||
### Control borders
|
||||
|
||||
`[controls]` governs shared controls such as buttons, dropdowns, text fields,
|
||||
toggles, and cursor rows. Each state has a fill color, optional border value,
|
||||
border width, and border alpha:
|
||||
|
||||
```toml
|
||||
[controls]
|
||||
normal-color = "#a9b1d6"
|
||||
normal-border = "#a9b1d6"
|
||||
normal-border-width = 1
|
||||
normal-border-alpha = 0.4
|
||||
|
||||
hover-cursor-color = "#a9b1d6"
|
||||
hover-cursor-border = "#a9b1d6"
|
||||
hover-cursor-border-width = 1
|
||||
hover-cursor-border-alpha = 0.25
|
||||
```
|
||||
|
||||
The `*-border` keys can also be gradients:
|
||||
|
||||
```toml
|
||||
[controls]
|
||||
focus-border = "rgba(33ccffee) rgba(00ff99ee) 45deg"
|
||||
focus-border-width = "2 2 2 4"
|
||||
```
|
||||
|
||||
Set a border width to `0` to keep the fill but remove that state border.
|
||||
|
||||
### Surface sections
|
||||
|
||||
Common shell sections include:
|
||||
|
||||
- `[bar]`
|
||||
- `[controls]`
|
||||
- `[popups]`
|
||||
- `[tooltip]`
|
||||
- `[notifications]`
|
||||
- `[launcher]`
|
||||
- `[menu]`
|
||||
- `[polkit]`
|
||||
- `[lock]`
|
||||
- `[image-picker]`
|
||||
- `[spacing]`
|
||||
- `[font]`
|
||||
|
||||
Clipboard and emojis inherit menu tokens. Popups are used by bar flyouts,
|
||||
dropdowns, OSD, and popup cards.
|
||||
|
||||
## QML border API
|
||||
|
||||
Plugin and shell QML should use `BorderSurface` for theme-aware borders:
|
||||
|
||||
```qml
|
||||
import qs.Commons
|
||||
import qs.Ui
|
||||
|
||||
BorderSurface {
|
||||
color: Color.popups.background
|
||||
borderSpec: Border.surfaceSpec("popups", "border", Color.popups.border, 2)
|
||||
padding: Style.spacing.popupPadding
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: parent.contentTopInset
|
||||
anchors.rightMargin: parent.contentRightInset
|
||||
anchors.bottomMargin: parent.contentBottomInset
|
||||
anchors.leftMargin: parent.contentLeftInset
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `Border.surfaceSpec(section, token, fallbackColor, fallbackWidth)` for
|
||||
shell theme tokens, `Border.controlSpec(state, foreground, accent)` for shared
|
||||
controls, and `Border.flat(color, width)` for a deliberate local border that
|
||||
should not be overridden by the active theme. `Color.<section>.border` is the
|
||||
flat first-stop color for consumers that cannot render full border specs.
|
||||
|
||||
## Hyprland templates
|
||||
|
||||
Hyprland theme output is generated from `default/themed/hyprland.lua.tpl`.
|
||||
Use `hypr_gradient` for border values because Hyprland's Lua config wants a
|
||||
Lua string for solid colors and a Lua table for gradients:
|
||||
|
||||
```lua
|
||||
local active_border_color = {{ hypr_gradient hyprland_active_border accent }}
|
||||
```
|
||||
|
||||
For a solid fallback this renders:
|
||||
|
||||
```lua
|
||||
local active_border_color = "#7aa2f7"
|
||||
```
|
||||
|
||||
For a gradient it renders:
|
||||
|
||||
```lua
|
||||
local active_border_color = { colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }
|
||||
```
|
||||
|
||||
## Adding or overriding theme files
|
||||
|
||||
- Add palette values to `themes/<name>/colors.toml`.
|
||||
- Prefer generated files when the theme can be expressed with templates.
|
||||
- Add a hand-written file in `themes/<name>/` only when that theme needs to
|
||||
override the generated output entirely.
|
||||
- Add a new built-in template under `default/themed/<file>.tpl` when every
|
||||
theme should generate that file.
|
||||
- Add a user-wide template under `~/.config/omarchy/themed/<file>.tpl` when a
|
||||
local customization should apply across themes.
|
||||
|
||||
When changing templates or theme helpers, run focused tests such as:
|
||||
|
||||
```bash
|
||||
./test/cli
|
||||
./test/shell
|
||||
```
|
||||
Reference in New Issue
Block a user