|
| 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