Skip to content

Commit 6a41f54

Browse files
committed
Make the TUIs adapt to light and dark terminal backgrounds
The submit, view, and modify TUIs were tuned for dark terminals. On light or solarized-light backgrounds the result was hard to read and inverted: primary text used ANSI white (invisible on white), dim chrome used light grays (too faint), and accents used bright cyan (low contrast) — so "active" things looked lighter than "disabled" ones. Introduce a centralized, background-aware color palette and migrate all three TUIs to it: - internal/tui/shared/theme.go: a semantic palette of lipgloss.AdaptiveColor values (primary/muted/faint text, chrome/border, accent, PR-state colors, badge backgrounds, row shade, button, switch). lipgloss resolves the light/dark variant per render from the terminal background, which Bubble Tea detects at startup; terminals that don't report it fall back to dark, preserving the original look. - Replace every hardcoded ANSI color in shared/, submitview/, and modifyview/ with palette roles. The four pre-rendered status icons now render at use-time so their adaptive colors resolve correctly. The submit markdown preview picks glamour's light or dark style from the detected background. - GH_STACK_THEME=auto|light|dark forces the palette for terminals that mis-detect (some SSH/tmux setups); wired via the root command's PersistentPreRun before any render. Documented in the README and CLI docs. Neutral text/chrome use truecolor hex (GitHub Primer-inspired) for predictability across themes, including solarized which repurposes ANSI 8-15; lipgloss downsamples on terminals without truecolor. Tests verify the palette resolves differently for light vs dark and that GH_STACK_THEME is honored.
1 parent d7207ae commit 6a41f54

16 files changed

Lines changed: 379 additions & 155 deletions

File tree

‎README.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,23 @@ gh stack submit
623623

624624
Compared to the typical workflow, there's no need to name branches, run `git add`, or run `git commit` separately. Each `gh stack add -Am "..."` does it all.
625625

626+
## Terminal theme
627+
628+
The interactive screens (`submit`, `modify`, and `view`) automatically adapt their colors to your terminal's background, so they're readable on both dark and light themes. The background is detected from the terminal; if a terminal doesn't report it (some SSH or `tmux` setups), the dark palette is used.
629+
630+
Set `GH_STACK_THEME` to force a palette if detection is wrong:
631+
632+
| Value | Behavior |
633+
|-------|----------|
634+
| `auto` (default) | Detect from the terminal background |
635+
| `light` | Force the light palette |
636+
| `dark` | Force the dark palette |
637+
638+
```bash
639+
# Force the light palette for one command
640+
GH_STACK_THEME=light gh stack view
641+
```
642+
626643
## Exit codes
627644

628645
| Code | Meaning |

‎cmd/root.go‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77

88
"github.com/github/gh-stack/internal/config"
9+
"github.com/github/gh-stack/internal/tui/shared"
910
"github.com/spf13/cobra"
1011
)
1112

@@ -35,6 +36,12 @@ locally, then push to GitHub to create your stack of PRs.`,
3536
Version: Version,
3637
SilenceUsage: true,
3738
SilenceErrors: true,
39+
// Honor GH_STACK_THEME (auto|light|dark) before any command renders, so
40+
// the background-aware TUI palette can be forced when a terminal
41+
// mis-detects its background.
42+
PersistentPreRun: func(_ *cobra.Command, _ []string) {
43+
shared.ApplyThemeOverride()
44+
},
3845
}
3946

4047
root.SetVersionTemplate("gh stack version {{.Version}}\n")

‎docs/src/content/docs/reference/cli.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,19 @@ gh stack feedback "Support for reordering branches"
586586

587587
---
588588

589+
## Environment Variables
590+
591+
| Variable | Values | Description |
592+
|----------|--------|-------------|
593+
| `GH_STACK_THEME` | `auto` (default), `light`, `dark` | Controls the color palette of the interactive screens (`submit`, `modify`, `view`). They adapt to your terminal background automatically; set this to force the light or dark palette when a terminal doesn't report its background (some SSH or `tmux` setups). |
594+
595+
```sh
596+
# Force the light palette for one command
597+
GH_STACK_THEME=light gh stack view
598+
```
599+
600+
---
601+
589602
## Exit Codes
590603

591604
| Code | Meaning |

‎internal/tui/modifyview/model.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1465,7 +1465,7 @@ func (m Model) buildHeaderConfig() shared.HeaderConfig {
14651465
{Icon: "○", Label: branchInfo},
14661466
}
14671467
if pendingSummary != "" {
1468-
yellowStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("3"))
1468+
yellowStyle := lipgloss.NewStyle().Foreground(shared.ColorYellow)
14691469
infoLines = append(infoLines, shared.HeaderInfoLine{Icon: "■", Label: pendingSummary, IconStyle: &yellowStyle})
14701470
} else {
14711471
infoLines = append(infoLines, shared.HeaderInfoLine{Icon: "□", Label: "No pending changes"})

‎internal/tui/modifyview/styles.go‎

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,48 @@
11
package modifyview
22

3-
import "github.com/charmbracelet/lipgloss"
3+
import (
4+
"github.com/charmbracelet/lipgloss"
45

6+
"github.com/github/gh-stack/internal/tui/shared"
7+
)
8+
9+
// Colors come from the background-aware palette in internal/tui/shared so the
10+
// modify view reads well on both dark and light terminals.
511
var (
612
// Action annotation styles (modify-specific)
7-
dropBadge = lipgloss.NewStyle().Foreground(lipgloss.Color("1")) // red
8-
foldBadge = lipgloss.NewStyle().Foreground(lipgloss.Color("3")) // yellow
9-
renameBadge = lipgloss.NewStyle().Foreground(lipgloss.Color("14")) // cyan
10-
moveBadge = lipgloss.NewStyle().Foreground(lipgloss.Color("5")) // magenta/purple
11-
insertBadge = lipgloss.NewStyle().Foreground(lipgloss.Color("2")) // green
13+
dropBadge = lipgloss.NewStyle().Foreground(shared.ColorRed) // drop
14+
foldBadge = lipgloss.NewStyle().Foreground(shared.ColorYellow) // fold
15+
renameBadge = lipgloss.NewStyle().Foreground(shared.ColorAccent) // rename
16+
moveBadge = lipgloss.NewStyle().Foreground(shared.ColorPurple) // move
17+
insertBadge = lipgloss.NewStyle().Foreground(shared.ColorGreen) // insert
1218

1319
// Branch name overrides for drop/fold/insert
14-
dropBranchStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("1")).Strikethrough(true) // red strikethrough
15-
foldBranchStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("3")).Strikethrough(true) // yellow strikethrough
16-
insertBranchStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("2")) // green
20+
dropBranchStyle = lipgloss.NewStyle().Foreground(shared.ColorRed).Strikethrough(true)
21+
foldBranchStyle = lipgloss.NewStyle().Foreground(shared.ColorYellow).Strikethrough(true)
22+
insertBranchStyle = lipgloss.NewStyle().Foreground(shared.ColorGreen)
1723

1824
// Connector color overrides for drop/fold/move/insert
19-
dropConnectorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("1")) // red
20-
foldConnectorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("3")) // yellow
21-
movedConnectorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("5")) // magenta/purple
22-
insertConnectorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("2")) // green
25+
dropConnectorStyle = lipgloss.NewStyle().Foreground(shared.ColorRed)
26+
foldConnectorStyle = lipgloss.NewStyle().Foreground(shared.ColorYellow)
27+
movedConnectorStyle = lipgloss.NewStyle().Foreground(shared.ColorPurple)
28+
insertConnectorStyle = lipgloss.NewStyle().Foreground(shared.ColorGreen)
2329

2430
// Status line styles
25-
statusBarStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
26-
statusCountStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("15")).Bold(true)
27-
statusKeyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("14"))
28-
statusDescStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
31+
statusBarStyle = lipgloss.NewStyle().Foreground(shared.ColorTextMuted)
32+
statusCountStyle = lipgloss.NewStyle().Foreground(shared.ColorText).Bold(true)
33+
statusKeyStyle = lipgloss.NewStyle().Foreground(shared.ColorAccent)
34+
statusDescStyle = lipgloss.NewStyle().Foreground(shared.ColorTextMuted)
2935

3036
// Help overlay styles
3137
helpOverlayStyle = lipgloss.NewStyle().
3238
Border(lipgloss.RoundedBorder()).
33-
BorderForeground(lipgloss.Color("8")).
39+
BorderForeground(shared.ColorBorder).
3440
Padding(1, 2)
35-
helpKeyStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true)
36-
helpDescStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("15"))
37-
helpTitleStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("15")).Bold(true).Underline(true)
41+
helpKeyStyle = lipgloss.NewStyle().Foreground(shared.ColorAccent).Bold(true)
42+
helpDescStyle = lipgloss.NewStyle().Foreground(shared.ColorText)
43+
helpTitleStyle = lipgloss.NewStyle().Foreground(shared.ColorText).Bold(true).Underline(true)
3844

3945
// Transient message styles
40-
transientErrorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("1")) // red
41-
transientInfoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // gray
46+
transientErrorStyle = lipgloss.NewStyle().Foreground(shared.ColorRed)
47+
transientInfoStyle = lipgloss.NewStyle().Foreground(shared.ColorTextMuted)
4248
)

‎internal/tui/shared/header.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ func RenderHeader(b *strings.Builder, cfg HeaderConfig, width, height int) {
361361
}
362362

363363
// disabledShortcutStyle renders both key and desc in dim gray.
364-
var disabledShortcutStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
364+
var disabledShortcutStyle = lipgloss.NewStyle().Foreground(ColorTextFaint)
365365

366366
// renderShortcutEntry renders a single shortcut, dimmed if disabled.
367367
func renderShortcutEntry(sc ShortcutEntry) string {

‎internal/tui/shared/render.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,16 @@ func ResolveConnectorStyle(node BranchNodeData, isFocused bool) (string, lipglos
8888
// StatusIcon returns the appropriate status icon for a branch.
8989
func StatusIcon(node BranchNodeData) string {
9090
if node.Ref.IsMerged() {
91-
return MergedIcon
91+
return mergedIconStyle.Render(mergedGlyph)
9292
}
9393
if node.Ref.IsQueued() {
94-
return QueuedIcon
94+
return queuedIconStyle.Render(queuedGlyph)
9595
}
9696
if !node.IsLinear {
97-
return WarningIcon
97+
return warningIconStyle.Render(warningGlyph)
9898
}
9999
if node.PR != nil && node.PR.Number != 0 {
100-
return OpenIcon
100+
return openIconStyle.Render(openGlyph)
101101
}
102102
return ""
103103
}

‎internal/tui/shared/styles.go‎

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,59 @@ import "github.com/charmbracelet/lipgloss"
44

55
var (
66
// Branch name styles
7-
CurrentBranchStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("14")).Bold(true)
8-
NormalBranchStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("15"))
9-
MergedBranchStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
10-
TrunkStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).Italic(true)
7+
CurrentBranchStyle = lipgloss.NewStyle().Foreground(ColorAccent).Bold(true)
8+
NormalBranchStyle = lipgloss.NewStyle().Foreground(ColorText)
9+
MergedBranchStyle = lipgloss.NewStyle().Foreground(ColorTextMuted)
10+
TrunkStyle = lipgloss.NewStyle().Foreground(ColorTextMuted).Italic(true)
1111

12-
// Status indicators
13-
MergedIcon = lipgloss.NewStyle().Foreground(lipgloss.Color("5")).Render("✓")
14-
WarningIcon = lipgloss.NewStyle().Foreground(lipgloss.Color("3")).Render("⚠")
15-
OpenIcon = lipgloss.NewStyle().Foreground(lipgloss.Color("2")).Render("○")
16-
QueuedIcon = lipgloss.NewStyle().Foreground(lipgloss.Color("130")).Render("◎")
12+
// Status indicator glyphs. These are rendered at use-time (see StatusIcon)
13+
// with the styles below so their adaptive colors resolve against the detected
14+
// terminal background rather than being baked in at package-init time.
15+
mergedGlyph = "✓"
16+
warningGlyph = "⚠"
17+
openGlyph = "○"
18+
queuedGlyph = "◎"
19+
20+
mergedIconStyle = lipgloss.NewStyle().Foreground(ColorPurple)
21+
warningIconStyle = lipgloss.NewStyle().Foreground(ColorYellow)
22+
openIconStyle = lipgloss.NewStyle().Foreground(ColorGreen)
23+
queuedIconStyle = lipgloss.NewStyle().Foreground(ColorYellow)
1724

1825
// PR status styles
19-
PRLinkStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("15")).Underline(true)
20-
PROpenStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("2"))
21-
PRMergedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("5"))
22-
PRClosedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("1"))
23-
PRDraftStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
24-
PRQueuedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("130"))
26+
PRLinkStyle = lipgloss.NewStyle().Foreground(ColorText).Underline(true)
27+
PROpenStyle = lipgloss.NewStyle().Foreground(ColorGreen)
28+
PRMergedStyle = lipgloss.NewStyle().Foreground(ColorPurple)
29+
PRClosedStyle = lipgloss.NewStyle().Foreground(ColorRed)
30+
PRDraftStyle = lipgloss.NewStyle().Foreground(ColorGray)
31+
PRQueuedStyle = lipgloss.NewStyle().Foreground(ColorYellow)
2532

2633
// Diff stats
27-
AdditionsStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("2"))
28-
DeletionsStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("1"))
34+
AdditionsStyle = lipgloss.NewStyle().Foreground(ColorGreen)
35+
DeletionsStyle = lipgloss.NewStyle().Foreground(ColorRed)
2936

3037
// Commit lines
31-
CommitSHAStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("3"))
32-
CommitSubjectStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("15"))
33-
CommitTimeStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
38+
CommitSHAStyle = lipgloss.NewStyle().Foreground(ColorYellow)
39+
CommitSubjectStyle = lipgloss.NewStyle().Foreground(ColorText)
40+
CommitTimeStyle = lipgloss.NewStyle().Foreground(ColorTextMuted)
3441

3542
// Connector lines
36-
ConnectorStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
37-
ConnectorDashedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("3"))
38-
ConnectorFocusedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("15"))
39-
ConnectorCurrentStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("14"))
40-
ConnectorMergedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("5"))
41-
ConnectorQueuedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("130"))
43+
ConnectorStyle = lipgloss.NewStyle().Foreground(ColorBorder)
44+
ConnectorDashedStyle = lipgloss.NewStyle().Foreground(ColorYellow)
45+
ConnectorFocusedStyle = lipgloss.NewStyle().Foreground(ColorText)
46+
ConnectorCurrentStyle = lipgloss.NewStyle().Foreground(ColorAccent)
47+
ConnectorMergedStyle = lipgloss.NewStyle().Foreground(ColorPurple)
48+
ConnectorQueuedStyle = lipgloss.NewStyle().Foreground(ColorYellow)
4249

4350
// Dim text
44-
DimStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("240"))
51+
DimStyle = lipgloss.NewStyle().Foreground(ColorTextFaint)
4552

4653
// Header styles
47-
HeaderBorderStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
48-
HeaderTitleStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("15")).Bold(true)
49-
HeaderInfoStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("14"))
50-
HeaderInfoLabelStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
51-
HeaderShortcutKey = lipgloss.NewStyle().Foreground(lipgloss.Color("15"))
52-
HeaderShortcutDesc = lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
54+
HeaderBorderStyle = lipgloss.NewStyle().Foreground(ColorBorder)
55+
HeaderTitleStyle = lipgloss.NewStyle().Foreground(ColorText).Bold(true)
56+
HeaderInfoStyle = lipgloss.NewStyle().Foreground(ColorAccent)
57+
HeaderInfoLabelStyle = lipgloss.NewStyle().Foreground(ColorTextMuted)
58+
HeaderShortcutKey = lipgloss.NewStyle().Foreground(ColorText)
59+
HeaderShortcutDesc = lipgloss.NewStyle().Foreground(ColorTextMuted)
5360

5461
// Expand/collapse icons
5562
ExpandedIcon = "▾"

‎internal/tui/shared/theme.go‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package shared
2+
3+
import (
4+
"os"
5+
"strings"
6+
7+
"github.com/charmbracelet/lipgloss"
8+
)
9+
10+
// This file defines the shared, background-aware color palette used by every
11+
// gh-stack TUI (submit, view, modify).
12+
//
13+
// Colors are expressed as lipgloss.AdaptiveColor, whose Light/Dark variant is
14+
// chosen at render time from the terminal's detected background. Bubble Tea
15+
// triggers that detection once at startup (see bubbletea/tea_init.go), so the
16+
// right variant is picked automatically; terminals that don't answer the query
17+
// fall back to the dark palette, preserving the original look.
18+
//
19+
// Values are truecolor hex (GitHub Primer-inspired) rather than ANSI palette
20+
// indices so they render consistently across themes — notably solarized, which
21+
// repurposes ANSI 8–15 as background tones. lipgloss downsamples to the nearest
22+
// ANSI color on terminals without truecolor support.
23+
var (
24+
// ColorText is primary/emphasis ink: titles, branch names, links, active
25+
// keys, the description scrollbar thumb.
26+
ColorText = lipgloss.AdaptiveColor{Dark: "#f0f6fc", Light: "#1f2328"}
27+
// ColorTextMuted is secondary ink and dim chrome text: section labels,
28+
// shortcut descriptions, hints, trunk/merged branches, timestamps.
29+
ColorTextMuted = lipgloss.AdaptiveColor{Dark: "#9198a1", Light: "#59636e"}
30+
// ColorTextFaint is disabled/de-emphasized ink: skipped branches, disabled
31+
// shortcuts.
32+
ColorTextFaint = lipgloss.AdaptiveColor{Dark: "#656c76", Light: "#818b98"}
33+
34+
// ColorBorder is structural chrome: panel borders, tree connectors, the
35+
// vertical spine, horizontal rules, scrollbar tracks, segmented-control frame.
36+
ColorBorder = lipgloss.AdaptiveColor{Dark: "#3d444d", Light: "#d1d9e0"}
37+
// ColorRowShade tints the focused (currently-viewed) row's background in the
38+
// left timeline. A neutral wash that reads as a subtle highlight on either
39+
// background — light gray on light terminals, and a lifted slate on dark
40+
// terminals so it stays visible against near-black backgrounds.
41+
ColorRowShade = lipgloss.AdaptiveColor{Dark: "#353941", Light: "#eaeef2"}
42+
43+
// ColorAccent is interactive emphasis: the current/focused branch, keyboard
44+
// shortcut keys, footer accents.
45+
ColorAccent = lipgloss.AdaptiveColor{Dark: "#2dd4bf", Light: "#0a7ea4"}
46+
47+
// Semantic status colors, mirroring how GitHub colors PR states. Reused for
48+
// diff stats (green/red), commit SHAs and warnings (yellow), and modify
49+
// action badges.
50+
ColorBlue = lipgloss.AdaptiveColor{Dark: "#4493f8", Light: "#0969da"} // NEW
51+
ColorGreen = lipgloss.AdaptiveColor{Dark: "#3fb950", Light: "#1a7f37"} // OPEN, additions, insert
52+
ColorGray = lipgloss.AdaptiveColor{Dark: "#9198a1", Light: "#59636e"} // DRAFT
53+
ColorYellow = lipgloss.AdaptiveColor{Dark: "#d29922", Light: "#9a6700"} // QUEUED, warning, commit SHA, fold
54+
ColorPurple = lipgloss.AdaptiveColor{Dark: "#bc8cff", Light: "#8250df"} // MERGED, move
55+
ColorRed = lipgloss.AdaptiveColor{Dark: "#f85149", Light: "#cf222e"} // CLOSED, deletions, drop, errors
56+
57+
// ColorOnFill is text drawn on top of a solid colored fill (e.g. the green
58+
// "selected" pill): near-black on the lighter dark-mode fills, white on the
59+
// darker light-mode fills.
60+
ColorOnFill = lipgloss.AdaptiveColor{Dark: "#0d1117", Light: "#ffffff"}
61+
62+
// ColorButtonFg/ColorButtonBg style the prominent inverted action button
63+
// (e.g. submit). The background inverts against the terminal so the button
64+
// stays prominent in both modes.
65+
ColorButtonBg = lipgloss.AdaptiveColor{Dark: "#f0f6fc", Light: "#1f2328"}
66+
ColorButtonFg = lipgloss.AdaptiveColor{Dark: "#0d1117", Light: "#ffffff"}
67+
)
68+
69+
// ApplyThemeOverride honors the GH_STACK_THEME environment variable, forcing the
70+
// light or dark palette regardless of what the terminal reports. It must be
71+
// called before the first render (e.g. before launching a Bubble Tea program).
72+
//
73+
// GH_STACK_THEME=light force the light palette
74+
// GH_STACK_THEME=dark force the dark palette
75+
// GH_STACK_THEME=auto (or unset) detect from the terminal background
76+
//
77+
// Use this for terminals that don't answer the background query (some SSH/tmux
78+
// setups) and therefore mis-detect.
79+
func ApplyThemeOverride() {
80+
switch strings.ToLower(strings.TrimSpace(os.Getenv("GH_STACK_THEME"))) {
81+
case "light":
82+
lipgloss.SetHasDarkBackground(false)
83+
case "dark":
84+
lipgloss.SetHasDarkBackground(true)
85+
}
86+
}

0 commit comments

Comments
 (0)