Documentation
¶
Overview ¶
Package theme is the single source of style for internal/ui: semantic roles, never raw colours at call sites. This file defines the role enum only; embedded theme data, the contrast/CVD validators, the palette search, and the degradation ladder land after user review of this list.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type ContrastCheck ¶
ContrastCheck is one required foreground/background pair and the WCAG 2.1 ratio it must meet. Body text needs 4.5:1 (AA); large text and UI components need 3:1. AllContrastChecks is the single source of truth for which pairs the UI actually renders — role.RoleBorder is deliberately absent: no state is carried by border alone, so it is decorative and exempt from WCAG 1.4.11 (wireframes.md section 7).
func AllContrastChecks ¶
func AllContrastChecks() []ContrastCheck
type ContrastFailure ¶
type ContrastFailure struct {
Check ContrastCheck
Ratio float64
}
ContrastFailure is one gate-table check a theme did not meet.
func ValidateContrast ¶
func ValidateContrast(t Theme) ([]ContrastFailure, error)
ValidateContrast checks every gate-table pair against a theme's colours and returns every failure found (nil if the theme passes clean).
func (ContrastFailure) String ¶
func (f ContrastFailure) String() string
type Dichromacy ¶
type Dichromacy int
Dichromacy is a colour-vision deficiency simulated by the Vienot, Brettel and Mollon (1999) LMS model: sRGB -> linear -> LMS (via the Hunt-Pointer-Estevez matrix), project out the missing cone response in LMS space, convert back. research-panes.md section 3.
const ( Protanopia Dichromacy = iota Deuteranopia Tritanopia )
type Role ¶
type Role string
Role names one semantic colour slot. A Theme maps every Role to a colour; a view layer never holds a literal colour, only a Role.
const ( RoleBG Role = "bg" RoleBGSubtle Role = "bg-subtle" RoleBGInset Role = "bg-inset" RoleFG Role = "fg" RoleFGMuted Role = "fg-muted" RoleFGSubtle Role = "fg-subtle" RoleBorder Role = "border" // decorative; no state, exempt from WCAG 1.4.11 RoleBorderFocus Role = "border-focus" // carries state; must meet 3:1 RoleAccent Role = "accent" // chrome only: prompt marker, focus ring, selection. Never a status. RoleAccentFG Role = "accent-fg" RoleSuccess Role = "success" RoleWarning Role = "warning" RoleDanger Role = "danger" RoleInfo Role = "info" )
Base roles. wireframes.md section 7.
const ( RoleKeyword Role = "keyword" RoleString Role = "string" RoleNumber Role = "number" RoleComment Role = "comment" RoleFunction Role = "function" RoleType Role = "type" RoleVariable Role = "variable" )
Syntax roles. wireframes.md section 7.
const ( RoleDiffAddFG Role = "diff-add-fg" RoleDiffAddBG Role = "diff-add-bg" RoleDiffDelFG Role = "diff-del-fg" RoleDiffDelBG Role = "diff-del-bg" RoleDiffHunk Role = "diff-hunk" )
Diff roles. wireframes.md section 7.
const ( RoleBGSelection Role = "bg-selection" // picker/completion selected row; not accent RoleDiffAddEmphBG Role = "diff-add-emph-bg" // word-level diff emphasis RoleDiffDelEmphBG Role = "diff-del-emph-bg" // word-level diff emphasis RoleGutter Role = "gutter" // dimmer than border, not decorative RoleLink Role = "link" // actionable file paths/URLs; distinct from info RoleFGInverse Role = "fg-inverse" // text on success/warning/danger fills )
Roles the Phase 0 mock needed that the original supplied list did not contain. wireframes.md section 7 / research.md finding 3.
func AllRoles ¶
func AllRoles() []Role
AllRoles lists every role a Theme must define, in the order shown in wireframes-panes.md section 18.
func StatusRoles ¶
func StatusRoles() []Role
StatusRoles is the set that must stay mutually separable under dichromat simulation. research-panes.md section 3: accent is chrome and is exempt from this check.
type SearchOptions ¶
type SearchOptions struct {
// MinContrast is the WCAG contrast ratio each candidate colour must
// meet against bg (config.WCAGAALarge is the conventional floor for
// a status word).
MinContrast float64
// Iterations bounds how many full {success,warning,danger,info}
// candidate sets are tried. More iterations trade search time for a
// better worst-case separation.
Iterations int
// Seed makes the search reproducible: same bg + options + seed
// always finds the same palette.
Seed int64
}
SearchOptions configures SearchStatusPalette.
type SearchResult ¶
type SearchResult struct {
Colors map[Role]string
WorstDE float64
Detail []SeparationPair
}
SearchResult is one candidate palette and its measured worst-case separation.
func SearchStatusPalette ¶
func SearchStatusPalette(bg string, opts SearchOptions) (SearchResult, error)
SearchStatusPalette searches hue/saturation/lightness space for a {success, warning, danger, info} set that meets MinContrast against bg and maximises worst-case CVD separation (WorstCaseSeparation), within the conventional hue windows in statusHueWindows.
research-panes.md section 3.2: hand-picking a status palette lost to this kind of search by 4x on worst-case separation. This function is for generating a *new* first-party or user theme against the constraint; it never rewrites an existing theme's shipped colours.
type SeparationPair ¶
type SeparationPair struct {
A, B Role
WorstDE float64
WorstUnder string // "normal", "protanopia", "deuteranopia", or "tritanopia"
}
SeparationPair is one status-role pair's worst measured separation across normal vision and all three dichromacies.
func HardFailSeparation ¶
func HardFailSeparation(t Theme) (worst float64, detail []SeparationPair, ok bool, err error)
HardFailSeparation reports whether a theme's worst-case status separation meets its own documented CVDBudget. This is the build-time gate: hard-fail for first-party themes, informational for third-party (research-panes.md section 3.1: no third-party palette in the survey was CVD-clean, so a hard gate there would reject nearly every upstream scheme).
func WorstCaseSeparation ¶
func WorstCaseSeparation(colors map[Role]string, roles []Role) (worst float64, detail []SeparationPair, err error)
WorstCaseSeparation measures every pair of the given status roles under normal vision and all three dichromacies, and returns the worst (smallest) dE found, plus the per-pair detail. research-panes.md section 3: the set that must stay separable is {success, warning, danger, info}; accent is chrome and is exempt.
type Style ¶
type Style struct {
Hex string // set for TrueColor and Tier256; empty otherwise
ANSI16 int // set for Tier16; -1 otherwise
NoColor bool // true for TierASCII and TierNoTTY
Bold bool
Dim bool
}
Style is the fully-resolved, tier-appropriate representation of one role: a hex colour where the tier supports it, an explicit ANSI16 index at the 16-colour tier, and structural emphasis that survives every tier including no-colour (research-panes.md section 2.1: NO_COLOR "disables colors but preserves text decoration").
type Theme ¶
type Theme struct {
Name string `json:"name"`
Label string `json:"label"`
Dark bool `json:"dark"`
FirstParty bool `json:"first_party"`
CVDBudget float64 `json:"cvd_budget"`
Credits string `json:"credits,omitempty"`
Colors map[Role]string `json:"colors"`
// ANSI16 gives each role an explicit ANSI SGR colour index (0-15) for
// the 16-colour degradation tier. A generic nearest-RGB downsample
// turns an achromatic accent to silver (research.md finding 8); this
// map is the fix, authored per theme rather than computed.
ANSI16 map[Role]int `json:"ansi16"`
}
Theme is data, not code: a Role -> hex colour map, plus an explicit 16-colour tier map and the CVD budget this theme trades against. A view layer never holds a literal colour, only a Role, and looks it up through a Theme via Resolve.
func LoadUserDir ¶
LoadUserDir loads user-supplied theme JSON files from a config directory. A missing directory is not an error: it means no user themes are installed.
func (Theme) Ansi16 ¶
Ansi16 returns the ANSI SGR colour index (0-15) for a role, and whether it is defined.
func (Theme) Resolve ¶
Resolve returns the Style a role should render as at the given tier. Tier256 uses the theme's truecolor hex and lets the terminal/library downsample it (research.md finding 8: safe at 256, only 16 needs an explicit map); Tier16 uses the theme's authored ANSI16 index directly, never a computed nearest match.
type Tier ¶
type Tier = colorprofile.Profile
Tier is the colour-profile degradation tier. It re-exports colorprofile.Profile directly rather than wrapping it, so Detect below stays a thin pass-through to the library the design calls for (research-panes.md section 2.1) instead of a hand-rolled duplicate.
const ( TierTrueColor Tier = colorprofile.TrueColor Tier256 Tier = colorprofile.ANSI256 Tier16 Tier = colorprofile.ANSI TierASCII Tier = colorprofile.Ascii TierNoTTY Tier = colorprofile.NoTTY )