mirror of
https://github.com/boolean-maybe/tiki
synced 2026-04-21 13:37:20 +00:00
theme-aware auto-generated caption colors
This commit is contained in:
parent
335743b874
commit
404b4be3be
12 changed files with 223 additions and 57 deletions
|
|
@ -61,7 +61,7 @@ Search order: user config dir (base) → `.doc/workflow.yaml` (project) → cwd
|
|||
**Statuses** — last file with a `statuses:` section wins (complete replacement). A project that defines its own statuses fully replaces the user-level defaults.
|
||||
|
||||
**Views (plugins)** — merged by name across files. The user config is the base; project and cwd files override individual fields:
|
||||
- Non-empty fields in the override replace the base (description, key, colors, view mode)
|
||||
- Non-empty fields in the override replace the base (description, key, view mode)
|
||||
- Non-empty arrays in the override replace the entire base array (lanes, actions)
|
||||
- Empty/zero fields in the override are ignored — the base value is kept
|
||||
- Views that only exist in the override are appended
|
||||
|
|
@ -149,8 +149,6 @@ statuses:
|
|||
views:
|
||||
- name: Kanban
|
||||
description: "Move tiki to new status, search, create or delete"
|
||||
foreground: "#87ceeb"
|
||||
background: "#25496a"
|
||||
key: "F1"
|
||||
lanes:
|
||||
- name: Ready
|
||||
|
|
@ -167,8 +165,6 @@ views:
|
|||
action: update where id = id() set status="done"
|
||||
- name: Backlog
|
||||
description: "Tasks waiting to be picked up, sorted by priority"
|
||||
foreground: "#5fff87"
|
||||
background: "#0b3d2e"
|
||||
key: "F3"
|
||||
lanes:
|
||||
- name: Backlog
|
||||
|
|
@ -180,8 +176,6 @@ views:
|
|||
action: update where id = id() set status="ready"
|
||||
- name: Recent
|
||||
description: "Tasks changed in the last 24 hours, most recent first"
|
||||
foreground: "#f4d6a6"
|
||||
background: "#5a3d1b"
|
||||
key: Ctrl-R
|
||||
lanes:
|
||||
- name: Recent
|
||||
|
|
@ -189,8 +183,6 @@ views:
|
|||
filter: select where now() - updatedAt < 24hour order by updatedAt desc
|
||||
- name: Roadmap
|
||||
description: "Epics organized by Now, Next, and Later horizons"
|
||||
foreground: "#e2e8f0"
|
||||
background: "#2a5f5a"
|
||||
key: "F4"
|
||||
lanes:
|
||||
- name: Now
|
||||
|
|
@ -214,15 +206,11 @@ views:
|
|||
type: doki
|
||||
fetcher: internal
|
||||
text: "Help"
|
||||
foreground: "#bcbcbc"
|
||||
background: "#003399"
|
||||
key: "?"
|
||||
- name: Docs
|
||||
description: "Project notes and documentation files"
|
||||
type: doki
|
||||
fetcher: file
|
||||
url: "index.md"
|
||||
foreground: "#ff9966"
|
||||
background: "#2b3a42"
|
||||
key: "F2"
|
||||
```
|
||||
|
|
@ -71,8 +71,6 @@ how Backlog is defined:
|
|||
views:
|
||||
- name: Backlog
|
||||
description: "Tasks waiting to be picked up, sorted by priority"
|
||||
foreground: "#5fff87"
|
||||
background: "#0b3d2e"
|
||||
key: "F3"
|
||||
lanes:
|
||||
- name: Backlog
|
||||
|
|
@ -86,7 +84,7 @@ views:
|
|||
|
||||
that translates to - show all tikis in the status `backlog`, sort by priority and then by ID arranged visually in 4 columns in a single lane.
|
||||
The `actions` section defines a keyboard shortcut `b` that moves the selected tiki to the board by setting its status to `ready`
|
||||
You define the name, description, caption colors, hotkey, and `ruki` expressions for filtering and actions. The `description` is displayed in the header when the view is active. Save this into a `workflow.yaml` file in the config directory
|
||||
You define the name, description, hotkey, and `ruki` expressions for filtering and actions. The `description` is displayed in the header when the view is active. Save this into a `workflow.yaml` file in the config directory
|
||||
|
||||
Likewise the documentation is just a plugin:
|
||||
|
||||
|
|
@ -97,8 +95,6 @@ views:
|
|||
type: doki
|
||||
fetcher: file
|
||||
url: "index.md"
|
||||
foreground: "#ff9966"
|
||||
background: "#2b3a42"
|
||||
key: "F2"
|
||||
```
|
||||
|
||||
|
|
@ -115,8 +111,6 @@ definition that roughly mimics the board:
|
|||
|
||||
```yaml
|
||||
name: Custom
|
||||
foreground: "#5fff87"
|
||||
background: "#005f00"
|
||||
key: "F4"
|
||||
lanes:
|
||||
- name: Ready
|
||||
|
|
|
|||
|
|
@ -46,8 +46,6 @@ Just configuring multiple plugins. Create a file like `brainstorm.yaml`:
|
|||
```text
|
||||
name: Brainstorm
|
||||
type: doki
|
||||
foreground: "##ffff99"
|
||||
background: "#996600"
|
||||
key: "F6"
|
||||
url: new-doc-root.md
|
||||
```
|
||||
|
|
|
|||
48
config/caption_colors_test.go
Normal file
48
config/caption_colors_test.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package config
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCaptionColorForIndex_Valid(t *testing.T) {
|
||||
cc := ColorsFromPalette(DarkPalette())
|
||||
for i := 0; i < 6; i++ {
|
||||
pair := cc.CaptionColorForIndex(i)
|
||||
if pair.Foreground.IsDefault() {
|
||||
t.Errorf("index %d: foreground is default", i)
|
||||
}
|
||||
if pair.Background.IsDefault() {
|
||||
t.Errorf("index %d: background is default", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCaptionColorForIndex_Wraps(t *testing.T) {
|
||||
cc := ColorsFromPalette(DarkPalette())
|
||||
first := cc.CaptionColorForIndex(0)
|
||||
wrapped := cc.CaptionColorForIndex(6)
|
||||
if first.Foreground.Hex() != wrapped.Foreground.Hex() {
|
||||
t.Errorf("expected index 6 to wrap to index 0: got fg %s vs %s", wrapped.Foreground.Hex(), first.Foreground.Hex())
|
||||
}
|
||||
if first.Background.Hex() != wrapped.Background.Hex() {
|
||||
t.Errorf("expected index 6 to wrap to index 0: got bg %s vs %s", wrapped.Background.Hex(), first.Background.Hex())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCaptionColorForIndex_Negative(t *testing.T) {
|
||||
cc := ColorsFromPalette(DarkPalette())
|
||||
pair := cc.CaptionColorForIndex(-1)
|
||||
if !pair.Foreground.IsDefault() {
|
||||
t.Errorf("expected default foreground for negative index, got %s", pair.Foreground.Hex())
|
||||
}
|
||||
if !pair.Background.IsDefault() {
|
||||
t.Errorf("expected default background for negative index, got %s", pair.Background.Hex())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllThemesHaveCaptionColors(t *testing.T) {
|
||||
for name, info := range themeRegistry {
|
||||
p := info.Palette()
|
||||
if len(p.CaptionColors) < 6 {
|
||||
t.Errorf("theme %q: has %d caption colors, want at least 6", name, len(p.CaptionColors))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,12 @@ type Gradient struct {
|
|||
End [3]int // R, G, B (0-255)
|
||||
}
|
||||
|
||||
// CaptionColorPair holds the foreground and background colors for a plugin caption row.
|
||||
type CaptionColorPair struct {
|
||||
Foreground Color
|
||||
Background Color
|
||||
}
|
||||
|
||||
// ColorConfig holds all color and style definitions per view
|
||||
type ColorConfig struct {
|
||||
// Caption colors
|
||||
|
|
@ -87,6 +93,9 @@ type ColorConfig struct {
|
|||
HeaderActionViewKeyColor Color
|
||||
HeaderActionViewLabelColor Color
|
||||
|
||||
// Plugin caption colors (auto-generated per theme)
|
||||
CaptionColors []CaptionColorPair
|
||||
|
||||
// Plugin-specific colors
|
||||
DepsEditorBackground Color // muted slate for dependency editor caption
|
||||
|
||||
|
|
@ -152,6 +161,9 @@ type Palette struct {
|
|||
StatuslineText Color // statusline primary text
|
||||
StatuslineAccent Color // statusline accent background
|
||||
StatuslineOk Color // statusline info/success foreground
|
||||
|
||||
// Plugin caption colors (6 curated fg/bg pairs per theme)
|
||||
CaptionColors []CaptionColorPair
|
||||
}
|
||||
|
||||
// darkenRGB returns a darkened version of an RGB triple. ratio 0 = no change, 1 = black.
|
||||
|
|
@ -277,9 +289,21 @@ func ColorsFromPalette(p Palette) *ColorConfig {
|
|||
StatuslineErrorFg: p.HighlightColor,
|
||||
StatuslineErrorBg: p.StatuslineMidBg,
|
||||
StatuslineFillBg: p.StatuslineMidBg,
|
||||
|
||||
// Plugin caption colors
|
||||
CaptionColors: p.CaptionColors,
|
||||
}
|
||||
}
|
||||
|
||||
// CaptionColorForIndex returns the caption color pair for a plugin at the given config index.
|
||||
// Wraps modulo slice length. Returns zero-value for negative index or empty slice.
|
||||
func (cc *ColorConfig) CaptionColorForIndex(index int) CaptionColorPair {
|
||||
if index < 0 || len(cc.CaptionColors) == 0 {
|
||||
return CaptionColorPair{}
|
||||
}
|
||||
return cc.CaptionColors[index%len(cc.CaptionColors)]
|
||||
}
|
||||
|
||||
// Global color config instance
|
||||
var globalColors *ColorConfig
|
||||
var colorsInitialized bool
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ views:
|
|||
- name: Kanban
|
||||
description: "Move tiki to new status, search, create or delete"
|
||||
default: true
|
||||
foreground: "#87ceeb"
|
||||
background: "#25496a"
|
||||
key: "F1"
|
||||
lanes:
|
||||
- name: Ready
|
||||
|
|
@ -42,8 +40,6 @@ views:
|
|||
action: update where id = id() set status="done"
|
||||
- name: Backlog
|
||||
description: "Tasks waiting to be picked up, sorted by priority"
|
||||
foreground: "#5fff87"
|
||||
background: "#0b3d2e"
|
||||
key: "F3"
|
||||
lanes:
|
||||
- name: Backlog
|
||||
|
|
@ -55,8 +51,6 @@ views:
|
|||
action: update where id = id() set status="ready"
|
||||
- name: Recent
|
||||
description: "Tasks changed in the last 24 hours, most recent first"
|
||||
foreground: "#f4d6a6"
|
||||
background: "#5a3d1b"
|
||||
key: Ctrl-R
|
||||
lanes:
|
||||
- name: Recent
|
||||
|
|
@ -64,8 +58,6 @@ views:
|
|||
filter: select where now() - updatedAt < 24hour order by updatedAt desc
|
||||
- name: Roadmap
|
||||
description: "Epics organized by Now, Next, and Later horizons"
|
||||
foreground: "#e2e8f0"
|
||||
background: "#2a5f5a"
|
||||
key: "F4"
|
||||
lanes:
|
||||
- name: Now
|
||||
|
|
@ -89,16 +81,12 @@ views:
|
|||
type: doki
|
||||
fetcher: internal
|
||||
text: "Help"
|
||||
foreground: "#bcbcbc"
|
||||
background: "#003399"
|
||||
key: "?"
|
||||
- name: Docs
|
||||
description: "Project notes and documentation files"
|
||||
type: doki
|
||||
fetcher: file
|
||||
url: "index.md"
|
||||
foreground: "#ff9966"
|
||||
background: "#2b3a42"
|
||||
key: "F2"
|
||||
|
||||
triggers:
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ Just configuring multiple plugins. Create a file like `brainstorm.yaml`:
|
|||
```text
|
||||
name: Brainstorm
|
||||
type: doki
|
||||
foreground: "##ffff99"
|
||||
background: "#996600"
|
||||
key: "F6"
|
||||
url: new-doc-root.md
|
||||
```
|
||||
|
|
|
|||
|
|
@ -44,6 +44,15 @@ func DarkPalette() Palette {
|
|||
StatuslineText: NewColorHex("#d8dee9"),
|
||||
StatuslineAccent: NewColorHex("#5e81ac"),
|
||||
StatuslineOk: NewColorHex("#a3be8c"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#87ceeb"), Background: NewColorHex("#25496a")}, // steel-blue (Kanban signature)
|
||||
{Foreground: NewColorHex("#8cd98c"), Background: NewColorHex("#003300")}, // green
|
||||
{Foreground: NewColorHex("#ffd78c"), Background: NewColorHex("#4d3200")}, // orange
|
||||
{Foreground: NewColorHex("#a9f1ea"), Background: NewColorHex("#13433e")}, // teal
|
||||
{Foreground: NewColorHex("#b7bcc7"), Background: NewColorHex("#1d2027")}, // blue-gray
|
||||
{Foreground: NewColorHex("#b0c4d4"), Background: NewColorHex("#1e2d3a")}, // slate blue
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +93,15 @@ func LightPalette() Palette {
|
|||
StatuslineText: NewColorHex("#2e3440"),
|
||||
StatuslineAccent: NewColorHex("#5e81ac"),
|
||||
StatuslineOk: NewColorHex("#4c7a5a"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#e0f0ff"), Background: NewColorHex("#3a6a90")}, // steel-blue (Kanban signature)
|
||||
{Foreground: NewColorHex("#d2ded6"), Background: NewColorHex("#467153")}, // green (StatuslineOk)
|
||||
{Foreground: NewColorHex("#edd6bf"), Background: NewColorHex("#a45200")}, // orange (InfoLabelColor)
|
||||
{Foreground: NewColorHex("#d2d3da"), Background: NewColorHex("#5a5e80")}, // indigo (ValueColor)
|
||||
{Foreground: NewColorHex("#c7e7e3"), Background: NewColorHex("#1a8174")}, // teal (LogoDotColor)
|
||||
{Foreground: NewColorHex("#dfdfdf"), Background: NewColorHex("#616161")}, // gray (MutedColor)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,6 +143,15 @@ func DraculaPalette() Palette {
|
|||
StatuslineText: NewColorHex("#f8f8f2"),
|
||||
StatuslineAccent: NewColorHex("#bd93f9"),
|
||||
StatuslineOk: NewColorHex("#50fa7b"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#cbf5fe"), Background: NewColorHex("#2a464c")}, // cyan
|
||||
{Foreground: NewColorHex("#b0fdc4"), Background: NewColorHex("#184b25")}, // green
|
||||
{Foreground: NewColorHex("#ffdfbd"), Background: NewColorHex("#4d3720")}, // orange
|
||||
{Foreground: NewColorHex("#f9fdcb"), Background: NewColorHex("#484b2a")}, // yellow
|
||||
{Foreground: NewColorHex("#b8c0d6"), Background: NewColorHex("#1d2231")}, // comment
|
||||
{Foreground: NewColorHex("#ffc3e5"), Background: NewColorHex("#4d243b")}, // pink
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +193,15 @@ func TokyoNightPalette() Palette {
|
|||
StatuslineText: NewColorHex("#c0caf5"),
|
||||
StatuslineAccent: NewColorHex("#7aa2f7"),
|
||||
StatuslineOk: NewColorHex("#9ece6a"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#c5e9ff"), Background: NewColorHex("#263e4d")}, // sky-blue
|
||||
{Foreground: NewColorHex("#d3e9bc"), Background: NewColorHex("#2f3e20")}, // green
|
||||
{Foreground: NewColorHex("#ffd3b9"), Background: NewColorHex("#4d2f1e")}, // orange
|
||||
{Foreground: NewColorHex("#efdbba"), Background: NewColorHex("#44341f")}, // yellow
|
||||
{Foreground: NewColorHex("#b3b7ca"), Background: NewColorHex("#1a1d29")}, // comment
|
||||
{Foreground: NewColorHex("#fbc2cc"), Background: NewColorHex("#4a232a")}, // red
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -207,6 +243,15 @@ func GruvboxDarkPalette() Palette {
|
|||
StatuslineText: NewColorHex("#ebdbb2"),
|
||||
StatuslineAccent: NewColorHex("#689d6a"), // dark aqua
|
||||
StatuslineOk: NewColorHex("#b8bb26"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#c7d7d1"), Background: NewColorHex("#27322e")}, // aqua-blue
|
||||
{Foreground: NewColorHex("#dfe09d"), Background: NewColorHex("#37380b")}, // green
|
||||
{Foreground: NewColorHex("#ffc698"), Background: NewColorHex("#4c2608")}, // orange
|
||||
{Foreground: NewColorHex("#fcdfaa"), Background: NewColorHex("#4b390e")}, // yellow
|
||||
{Foreground: NewColorHex("#bab6b2"), Background: NewColorHex("#1f1c19")}, // gray
|
||||
{Foreground: NewColorHex("#fd9a90"), Background: NewColorHex("#4b1610")}, // red
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -248,6 +293,15 @@ func CatppuccinMochaPalette() Palette {
|
|||
StatuslineText: NewColorHex("#cdd6f4"),
|
||||
StatuslineAccent: NewColorHex("#89b4fa"),
|
||||
StatuslineOk: NewColorHex("#a6e3a1"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#c9dcfd"), Background: NewColorHex("#293648")}, // blue
|
||||
{Foreground: NewColorHex("#d7f2d5"), Background: NewColorHex("#324430")}, // green
|
||||
{Foreground: NewColorHex("#fdddc9"), Background: NewColorHex("#4b3629")}, // peach
|
||||
{Foreground: NewColorHex("#fcf0d9"), Background: NewColorHex("#4b4435")}, // yellow
|
||||
{Foreground: NewColorHex("#f9eaea"), Background: NewColorHex("#483d3d")}, // flamingo
|
||||
{Foreground: NewColorHex("#cff2ec"), Background: NewColorHex("#2c4440")}, // teal
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,6 +343,15 @@ func SolarizedDarkPalette() Palette {
|
|||
StatuslineText: NewColorHex("#839496"),
|
||||
StatuslineAccent: NewColorHex("#268bd2"),
|
||||
StatuslineOk: NewColorHex("#859900"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#9dcbeb"), Background: NewColorHex("#0b2a3f")}, // blue
|
||||
{Foreground: NewColorHex("#c8d18c"), Background: NewColorHex("#282e00")}, // green
|
||||
{Foreground: NewColorHex("#e8ae96"), Background: NewColorHex("#3d1707")}, // orange
|
||||
{Foreground: NewColorHex("#9fd5d1"), Background: NewColorHex("#0d302e")}, // cyan
|
||||
{Foreground: NewColorHex("#b4bec1"), Background: NewColorHex("#1a2123")}, // base01
|
||||
{Foreground: NewColorHex("#ec908f"), Background: NewColorHex("#420f0e")}, // red
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,6 +393,15 @@ func NordPalette() Palette {
|
|||
StatuslineText: NewColorHex("#d8dee9"), // nord4
|
||||
StatuslineAccent: NewColorHex("#5e81ac"), // nord10
|
||||
StatuslineOk: NewColorHex("#a3be8c"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#c9e3ea"), Background: NewColorHex("#293a3e")}, // frost-cyan
|
||||
{Foreground: NewColorHex("#d6e2cb"), Background: NewColorHex("#31392a")}, // green
|
||||
{Foreground: NewColorHex("#eac9bf"), Background: NewColorHex("#3e2922")}, // orange
|
||||
{Foreground: NewColorHex("#f4e3c3"), Background: NewColorHex("#473d2a")}, // yellow
|
||||
{Foreground: NewColorHex("#aeb3bc"), Background: NewColorHex("#171a20")}, // nord3
|
||||
{Foreground: NewColorHex("#dca8ac"), Background: NewColorHex("#391d20")}, // red
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -371,6 +443,15 @@ func MonokaiPalette() Palette {
|
|||
StatuslineText: NewColorHex("#f8f8f2"),
|
||||
StatuslineAccent: NewColorHex("#66d9ef"),
|
||||
StatuslineOk: NewColorHex("#a6e22e"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#baeef8"), Background: NewColorHex("#1f4148")}, // cyan
|
||||
{Foreground: NewColorHex("#d7f2a1"), Background: NewColorHex("#32440e")}, // green
|
||||
{Foreground: NewColorHex("#fed09a"), Background: NewColorHex("#4c2d09")}, // orange
|
||||
{Foreground: NewColorHex("#f2eebc"), Background: NewColorHex("#454223")}, // yellow
|
||||
{Foreground: NewColorHex("#c1bfb7"), Background: NewColorHex("#23221c")}, // comment
|
||||
{Foreground: NewColorHex("#e08ea5"), Background: NewColorHex("#4b0c22")}, // pink-red
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -412,6 +493,15 @@ func OneDarkPalette() Palette {
|
|||
StatuslineText: NewColorHex("#abb2bf"),
|
||||
StatuslineAccent: NewColorHex("#61afef"),
|
||||
StatuslineOk: NewColorHex("#98c379"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#b8dbf8"), Background: NewColorHex("#1d3548")}, // blue
|
||||
{Foreground: NewColorHex("#d1e4c3"), Background: NewColorHex("#2e3b24")}, // green
|
||||
{Foreground: NewColorHex("#ead2ba"), Background: NewColorHex("#3f2e1f")}, // orange
|
||||
{Foreground: NewColorHex("#f1deba"), Background: NewColorHex("#453a25")}, // yellow
|
||||
{Foreground: NewColorHex("#b6b9bf"), Background: NewColorHex("#1c1e22")}, // comment
|
||||
{Foreground: NewColorHex("#eeb2b6"), Background: NewColorHex("#432123")}, // red
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -455,6 +545,15 @@ func CatppuccinLattePalette() Palette {
|
|||
StatuslineText: NewColorHex("#4c4f69"),
|
||||
StatuslineAccent: NewColorHex("#1e66f5"),
|
||||
StatuslineOk: NewColorHex("#40a02b"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#c7d9fd"), Background: NewColorHex("#1e66f5")}, // blue (ValueColor)
|
||||
{Foreground: NewColorHex("#f7e3c7"), Background: NewColorHex("#8d5a12")}, // yellow (HighlightColor)
|
||||
{Foreground: NewColorHex("#ffd8c2"), Background: NewColorHex("#b54708")}, // peach (InfoLabelColor)
|
||||
{Foreground: NewColorHex("#dedfe4"), Background: NewColorHex("#5e606f")}, // overlay0 (MutedColor)
|
||||
{Foreground: NewColorHex("#c5e4e6"), Background: NewColorHex("#148187")}, // teal (LogoDotColor)
|
||||
{Foreground: NewColorHex("#c0e9f9"), Background: NewColorHex("#0381b3")}, // sky (DeepSkyBlue)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -496,6 +595,15 @@ func SolarizedLightPalette() Palette {
|
|||
StatuslineText: NewColorHex("#657b83"),
|
||||
StatuslineAccent: NewColorHex("#268bd2"),
|
||||
StatuslineOk: NewColorHex("#859900"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#c9e2f4"), Background: NewColorHex("#2073ae")}, // blue (ValueColor)
|
||||
{Foreground: NewColorHex("#ede2bf"), Background: NewColorHex("#826300")}, // yellow (HighlightColor)
|
||||
{Foreground: NewColorHex("#f2d2c5"), Background: NewColorHex("#b74414")}, // orange (InfoLabelColor)
|
||||
{Foreground: NewColorHex("#d5dbdd"), Background: NewColorHex("#52666d")}, // base01 (SoftTextColor)
|
||||
{Foreground: NewColorHex("#cae8e5"), Background: NewColorHex("#217d76")}, // cyan (LogoDotColor)
|
||||
{Foreground: NewColorHex("#e1e6bf"), Background: NewColorHex("#637200")}, // green (AccentColor)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -537,6 +645,15 @@ func GruvboxLightPalette() Palette {
|
|||
StatuslineText: NewColorHex("#3c3836"),
|
||||
StatuslineAccent: NewColorHex("#427b58"),
|
||||
StatuslineOk: NewColorHex("#79740e"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#e2d6c3"), Background: NewColorHex("#8b5b0f")}, // amber/ochre
|
||||
{Foreground: NewColorHex("#dedcc3"), Background: NewColorHex("#6f6a0d")}, // green
|
||||
{Foreground: NewColorHex("#ebcec0"), Background: NewColorHex("#c44103")}, // orange
|
||||
{Foreground: NewColorHex("#d0ded5"), Background: NewColorHex("#3f7554")}, // aqua
|
||||
{Foreground: NewColorHex("#dedbd8"), Background: NewColorHex("#6a5f55")}, // gray
|
||||
{Foreground: NewColorHex("#e2d7d2"), Background: NewColorHex("#8b5e4b")}, // warm brown
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -578,5 +695,14 @@ func GithubLightPalette() Palette {
|
|||
StatuslineText: NewColorHex("#1f2328"),
|
||||
StatuslineAccent: NewColorHex("#0969da"),
|
||||
StatuslineOk: NewColorHex("#116329"),
|
||||
|
||||
CaptionColors: []CaptionColorPair{
|
||||
{Foreground: NewColorHex("#c2daf6"), Background: NewColorHex("#0a72ed")}, // blue
|
||||
{Foreground: NewColorHex("#c4d8ca"), Background: NewColorHex("#188d3b")}, // green
|
||||
{Foreground: NewColorHex("#e5cdbf"), Background: NewColorHex("#ba4600")}, // orange
|
||||
{Foreground: NewColorHex("#e6d9bf"), Background: NewColorHex("#9a6700")}, // amber
|
||||
{Foreground: NewColorHex("#d9dbdd"), Background: NewColorHex("#5b626a")}, // muted
|
||||
{Foreground: NewColorHex("#e6d2d2"), Background: NewColorHex("#9b4a4a")}, // muted red
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import (
|
|||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/boolean-maybe/tiki/config"
|
||||
|
|
@ -20,9 +19,9 @@ func parsePluginConfig(cfg pluginFileConfig, source string, schema ruki.Schema)
|
|||
}
|
||||
|
||||
// Common fields
|
||||
// Use ColorDefault as sentinel so views can detect "not specified" and use theme-appropriate colors
|
||||
fg := config.NewColor(parseColor(cfg.Foreground, tcell.ColorDefault))
|
||||
bg := config.NewColor(parseColor(cfg.Background, tcell.ColorDefault))
|
||||
// caption colors are now auto-generated per theme; YAML fg/bg fields are silently ignored
|
||||
fg := config.DefaultColor()
|
||||
bg := config.DefaultColor()
|
||||
|
||||
key, r, mod, err := parseKey(cfg.Key)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -56,12 +56,16 @@ func NewDokiView(
|
|||
}
|
||||
|
||||
func (dv *DokiView) build() {
|
||||
// title bar with gradient background using plugin color
|
||||
textColor := config.DefaultColor()
|
||||
if !dv.pluginDef.Foreground.IsDefault() {
|
||||
textColor = dv.pluginDef.Foreground
|
||||
// title bar with gradient background using theme-derived caption colors
|
||||
colors := config.GetColors()
|
||||
pair := colors.CaptionColorForIndex(dv.pluginDef.ConfigIndex)
|
||||
bgColor := pair.Background
|
||||
textColor := pair.Foreground
|
||||
if dv.pluginDef.ConfigIndex < 0 {
|
||||
bgColor = dv.pluginDef.Background
|
||||
textColor = config.DefaultColor()
|
||||
}
|
||||
dv.titleBar = NewGradientCaptionRow([]string{dv.pluginDef.Name}, nil, dv.pluginDef.Background, textColor)
|
||||
dv.titleBar = NewGradientCaptionRow([]string{dv.pluginDef.Name}, nil, bgColor, textColor)
|
||||
|
||||
// Fetch initial content and create NavigableMarkdown with appropriate provider
|
||||
var content string
|
||||
|
|
|
|||
|
|
@ -51,8 +51,6 @@ how Backlog is defined:
|
|||
```yaml
|
||||
views:
|
||||
- name: Backlog
|
||||
foreground: "#5fff87"
|
||||
background: "#0b3d2e"
|
||||
key: "F3"
|
||||
lanes:
|
||||
- name: Backlog
|
||||
|
|
@ -66,7 +64,7 @@ views:
|
|||
|
||||
that translates to - show all tikis in the status `backlog`, sort by priority and then by ID arranged visually in 4 columns in a single lane.
|
||||
The `actions` section defines a keyboard shortcut `b` that moves the selected tiki to the board by setting its status to `ready`
|
||||
You define the name, caption colors, hotkey, and `ruki` expressions for filtering and actions. Save this into a `workflow.yaml` file in the config directory
|
||||
You define the name, description, hotkey, and `ruki` expressions for filtering and actions. Save this into a `workflow.yaml` file in the config directory
|
||||
|
||||
Likewise the documentation is just a plugin:
|
||||
|
||||
|
|
@ -76,8 +74,6 @@ views:
|
|||
type: doki
|
||||
fetcher: file
|
||||
url: "index.md"
|
||||
foreground: "#ff9966"
|
||||
background: "#2b3a42"
|
||||
key: "F2"
|
||||
```
|
||||
|
||||
|
|
@ -94,8 +90,6 @@ definition that roughly mimics the board:
|
|||
|
||||
```yaml
|
||||
name: Custom
|
||||
foreground: "#5fff87"
|
||||
background: "#005f00"
|
||||
key: "F4"
|
||||
lanes:
|
||||
- name: Ready
|
||||
|
|
|
|||
|
|
@ -57,10 +57,15 @@ func NewPluginView(
|
|||
}
|
||||
|
||||
func (pv *PluginView) build() {
|
||||
// title bar with gradient background using plugin color
|
||||
textColor := config.DefaultColor()
|
||||
if !pv.pluginDef.Foreground.IsDefault() {
|
||||
textColor = pv.pluginDef.Foreground
|
||||
// title bar with gradient background using theme-derived caption colors
|
||||
colors := config.GetColors()
|
||||
pair := colors.CaptionColorForIndex(pv.pluginDef.ConfigIndex)
|
||||
bgColor := pair.Background
|
||||
textColor := pair.Foreground
|
||||
if pv.pluginDef.ConfigIndex < 0 {
|
||||
// code-only plugin (e.g. deps editor) — use explicit Background
|
||||
bgColor = pv.pluginDef.Background
|
||||
textColor = config.DefaultColor()
|
||||
}
|
||||
laneNames := make([]string, len(pv.pluginDef.Lanes))
|
||||
for i, lane := range pv.pluginDef.Lanes {
|
||||
|
|
@ -70,7 +75,7 @@ func (pv *PluginView) build() {
|
|||
for i := range pv.pluginDef.Lanes {
|
||||
laneWidths[i] = pv.pluginConfig.GetWidthForLane(i)
|
||||
}
|
||||
pv.titleBar = NewGradientCaptionRow(laneNames, laneWidths, pv.pluginDef.Background, textColor)
|
||||
pv.titleBar = NewGradientCaptionRow(laneNames, laneWidths, bgColor, textColor)
|
||||
|
||||
// lanes container (rows)
|
||||
pv.lanes = tview.NewFlex().SetDirection(tview.FlexColumn)
|
||||
|
|
|
|||
Loading…
Reference in a new issue