palettes

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 25, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package palettes provides color palette management for markata-go themes.

Overview

Palettes define color schemes using a three-layer architecture:

  • Raw colors: Pure hex values with no semantic meaning
  • Semantic colors: Role-based mappings (text-primary, bg-surface, etc.)
  • Component colors: Fine-grained component styling (code-keyword, button-bg)

Palette Discovery

Palettes are discovered in order:

  1. Project local: ./palettes/{name}.toml
  2. User config: ~/.config/markata-go/palettes/{name}.toml
  3. Built-in: embedded palettes

Usage

// Load a palette by name
p, err := palettes.Load("catppuccin-mocha")
if err != nil {
    log.Fatal(err)
}

// Get resolved colors
textColor := p.Resolve("text-primary")  // Returns "#cdd6f4"

// Generate CSS
css := p.GenerateCSS()

// Check contrast ratios
results := p.CheckContrast()
for _, r := range results {
    if !r.Passed {
        fmt.Printf("FAIL: %s on %s (%.2f:1)\n", r.Foreground, r.Background, r.Ratio)
    }
}

WCAG Compliance

The package includes WCAG 2.1 contrast ratio validation:

  • AA: 4.5:1 for normal text, 3:1 for large text/UI
  • AAA: 7:1 for normal text, 4.5:1 for large text

Index

Constants

View Source
const DefaultChromaThemeDark = "github-dark"

DefaultChromaThemeDark is the default Chroma theme for dark palettes.

View Source
const DefaultChromaThemeLight = "github"

DefaultChromaThemeLight is the default Chroma theme for light palettes.

Variables

View Source
var (
	// ErrPaletteNotFound is returned when a palette cannot be found.
	ErrPaletteNotFound = errors.New("palette not found")

	// ErrInvalidPalette is returned when a palette file is malformed.
	ErrInvalidPalette = errors.New("invalid palette")

	// ErrCircularReference is returned when color references form a cycle.
	ErrCircularReference = errors.New("circular color reference detected")

	// ErrUnknownColor is returned when a color reference cannot be resolved.
	ErrUnknownColor = errors.New("unknown color reference")

	// ErrInvalidHexColor is returned when a hex color value is malformed.
	ErrInvalidHexColor = errors.New("invalid hex color")
)

Common errors returned by the palettes package.

View Source
var AvailableChromaThemes = []string{

	"github",
	"gruvbox-light",
	"solarized-light",
	"catppuccin-latte",
	"rose-pine-dawn",
	"tokyonight-day",
	"modus-operandi",
	"evergarden",
	"xcode",
	"vs",
	"autumn",
	"friendly",
	"tango",
	"trac",
	"perldoc",
	"lovelace",
	"paraiso-light",
	"algol",
	"emacs",

	"github-dark",
	"gruvbox",
	"solarized-dark",
	"catppuccin-frappe",
	"catppuccin-macchiato",
	"catppuccin-mocha",
	"rose-pine",
	"rose-pine-moon",
	"tokyonight-night",
	"tokyonight-storm",
	"tokyonight-moon",
	"nord",
	"dracula",
	"monokai",
	"onedark",
	"doom-one",
	"doom-one2",
	"vim",
	"native",
	"fruity",
	"xcode-dark",
	"modus-vivendi",
	"aura-theme-dark",
	"base16-snazzy",
	"witchhazel",
	"paraiso-dark",
	"hrdark",
	"vulcan",
	"rrt",
}

AvailableChromaThemes returns a list of all Chroma themes that are known to work. This is a subset of all Chroma styles, focusing on popular, well-maintained themes.

View Source
var DefaultLoader = NewLoader()

DefaultLoader is the default palette loader instance.

View Source
var RequiredChecks = []ContrastCheckSpec{

	{"text-primary", "bg-primary", 4.5, "AA"},
	{"text-primary", "bg-surface", 4.5, "AA"},
	{"text-primary", "bg-elevated", 4.5, "AA"},

	{"text-secondary", "bg-primary", 4.5, "AA"},
	{"text-muted", "bg-primary", 3.0, "AA Large"},

	{"link", "bg-primary", 4.5, "AA"},
	{"accent", "bg-primary", 3.0, "AA Large"},

	{"success", "bg-primary", 3.0, "UI"},
	{"warning", "bg-primary", 3.0, "UI"},
	{"error", "bg-primary", 3.0, "UI"},
	{"info", "bg-primary", 3.0, "UI"},

	{"code-text", "code-bg", 4.5, "AA"},
	{"code-comment", "code-bg", 3.0, "AA Large"},
	{"code-keyword", "code-bg", 4.5, "AA"},

	{"button-primary-text", "button-primary-bg", 4.5, "AA"},
	{"button-secondary-text", "button-secondary-bg", 4.5, "AA"},
}

RequiredChecks defines all contrast checks that palettes should pass. These are the minimum requirements for WCAG AA compliance.

View Source
var StrictChecks = []ContrastCheckSpec{

	{"text-primary", "bg-primary", 7.0, "AAA"},
	{"text-secondary", "bg-primary", 7.0, "AAA"},
	{"link", "bg-primary", 7.0, "AAA"},

	{"text-muted", "bg-primary", 4.5, "AAA Large"},
	{"accent", "bg-primary", 4.5, "AAA Large"},
}

StrictChecks defines additional checks for AAA compliance.

View Source
var WCAGRequirements = map[WCAGLevel]ContrastRequirement{
	WCAGLevelA:   {NormalText: 3.0, LargeText: 3.0, UI: 3.0},
	WCAGLevelAA:  {NormalText: 4.5, LargeText: 3.0, UI: 3.0},
	WCAGLevelAAA: {NormalText: 7.0, LargeText: 4.5, UI: 4.5},
}

WCAGRequirements defines contrast requirements for each WCAG level.

Functions

func BuiltinNames

func BuiltinNames() []string

BuiltinNames returns the names of all built-in palettes.

func ChromaTheme

func ChromaTheme(paletteName string) string

ChromaTheme returns the Chroma syntax highlighting theme name that best matches the given palette name. If no specific mapping exists, it returns a sensible default based on the palette's variant (light/dark).

This mapping allows the site's color palette to automatically drive the code highlighting theme, providing a cohesive visual experience.

func ChromaThemeForVariant

func ChromaThemeForVariant(variant Variant) string

ChromaThemeForVariant returns a default Chroma theme for the given variant. Used as a fallback when no specific palette mapping exists.

func ContrastRatio

func ContrastRatio(fg, bg Color) float64

ContrastRatio calculates the WCAG 2.1 contrast ratio between two colors. Returns a value between 1:1 (same color) and 21:1 (black/white).

func ContrastRatioFromHex

func ContrastRatioFromHex(fgHex, bgHex string) (float64, error)

ContrastRatioFromHex calculates contrast ratio from hex color strings.

func FormatContrastResult

func FormatContrastResult(r ContrastCheck) string

FormatContrastResult formats a single contrast check result as a string.

func FormatContrastSummary

func FormatContrastSummary(summary ContrastSummary) string

FormatContrastSummary formats a contrast summary as a human-readable string.

func GenerateDarkModeCSS

func GenerateDarkModeCSS(lightPalette, darkPalette *Palette) string

GenerateDarkModeCSS generates CSS with dark mode media query. Uses lightPalette for default and darkPalette for prefers-color-scheme: dark.

func GetEffectivePalettes added in v0.5.0

func GetEffectivePalettes(palette, paletteLight, paletteDark string) (light, dark string)

GetEffectivePalettes returns the actual palette names to use for light and dark modes. It respects explicit overrides while providing intelligent defaults.

Parameters:

  • palette: the base palette from config (e.g., "everforest")
  • paletteLight: explicit light variant override (optional)
  • paletteDark: explicit dark variant override (optional)

Returns:

  • light: the palette name to use for light mode
  • dark: the palette name to use for dark mode

func HasBuiltin

func HasBuiltin(name string) bool

HasBuiltin checks if a palette name exists in built-in palettes.

func MeetsWCAG

func MeetsWCAG(ratio float64, level WCAGLevel, isLargeText bool) bool

MeetsWCAG checks if a contrast ratio meets the specified WCAG level.

func MeetsWCAGUI

func MeetsWCAGUI(ratio float64, level WCAGLevel) bool

MeetsWCAGUI checks if a contrast ratio meets WCAG for UI components.

Types

type CSSFormat

type CSSFormat struct {
	// UseReferences determines whether semantic/component colors should
	// use var(--palette-*) references or resolved hex values.
	UseReferences bool

	// Prefix for raw color CSS variables (default: "palette")
	RawPrefix string

	// Prefix for semantic color CSS variables (default: "color")
	SemanticPrefix string

	// Prefix for component color CSS variables (default: none, use name directly)
	ComponentPrefix string

	// IncludeRaw includes raw color definitions
	IncludeRaw bool

	// IncludeSemantic includes semantic color definitions
	IncludeSemantic bool

	// IncludeComponents includes component color definitions
	IncludeComponents bool

	// Minify removes whitespace for smaller output
	Minify bool
}

CSSFormat specifies how CSS should be generated.

func DefaultCSSFormat

func DefaultCSSFormat() CSSFormat

DefaultCSSFormat returns the default CSS format options.

type Color

type Color struct {
	R, G, B uint8
}

Color represents an RGB color with methods for contrast calculation.

func ColorFromStdlib

func ColorFromStdlib(c color.Color) Color

ColorFromStdlib converts a standard library color.Color to our Color type.

func ParseHexColor

func ParseHexColor(hex string) (Color, error)

ParseHexColor parses a hex color string into a Color. Supports formats: #RGB, #RGBA, #RRGGBB, #RRGGBBAA (with or without #).

func (Color) AdjustForContrast

func (c Color) AdjustForContrast(bg Color, minRatio float64) (Color, bool)

AdjustForContrast adjusts the color to meet a minimum contrast ratio against a background. Returns the adjusted color and whether adjustment was successful.

func (Color) Darken

func (c Color) Darken(amount float64) Color

Darken returns a darker version of the color. amount should be between 0 (no change) and 1 (black).

func (Color) Hex

func (c Color) Hex() string

Hex returns the color as a hex string with # prefix.

func (Color) Lighten

func (c Color) Lighten(amount float64) Color

Lighten returns a lighter version of the color. amount should be between 0 (no change) and 1 (white).

func (Color) RGBA

func (c Color) RGBA() (r, g, b, a uint32)

RGBA implements the color.Color interface.

func (Color) RelativeLuminance

func (c Color) RelativeLuminance() float64

RelativeLuminance calculates the relative luminance of the color. Based on WCAG 2.1 definition using sRGB color space. Returns a value between 0 (black) and 1 (white).

type ColorResolutionError

type ColorResolutionError struct {
	Color   string // Color name that failed to resolve
	Palette string // Palette name
	Message string // Human-readable error message
	Err     error  // Underlying error
}

ColorResolutionError provides context for color resolution failures.

func NewColorResolutionError

func NewColorResolutionError(color, palette, message string, err error) *ColorResolutionError

NewColorResolutionError creates a new ColorResolutionError.

func (*ColorResolutionError) Error

func (e *ColorResolutionError) Error() string

func (*ColorResolutionError) Unwrap

func (e *ColorResolutionError) Unwrap() error

type ContrastCheck

type ContrastCheck struct {
	Foreground    string   `json:"foreground"`     // Foreground color name
	Background    string   `json:"background"`     // Background color name
	ForegroundHex string   `json:"foreground_hex"` // Resolved foreground hex
	BackgroundHex string   `json:"background_hex"` // Resolved background hex
	Ratio         float64  `json:"ratio"`          // Calculated contrast ratio
	Required      float64  `json:"required"`       // Minimum required ratio
	Level         string   `json:"level"`          // WCAG level: "AA", "AAA", "AA Large", "UI"
	Passed        bool     `json:"passed"`         // Whether the check passed
	PassedLevels  []string `json:"passed_levels"`  // All WCAG levels that pass
}

ContrastCheck represents a single contrast validation result.

type ContrastCheckSpec

type ContrastCheckSpec struct {
	Foreground string  // Foreground color name (semantic or component)
	Background string  // Background color name (semantic or component)
	MinRatio   float64 // Minimum required ratio
	Level      string  // WCAG level description
}

ContrastCheckSpec defines a contrast check to perform.

type ContrastRequirement

type ContrastRequirement struct {
	NormalText float64 // Minimum for normal text
	LargeText  float64 // Minimum for large text (18pt+ or 14pt bold)
	UI         float64 // Minimum for UI components
}

ContrastRequirement defines minimum contrast ratios for different contexts.

type ContrastSummary

type ContrastSummary struct {
	Palette      string          `json:"palette"`
	Total        int             `json:"total"`
	Passed       int             `json:"passed"`
	Failed       int             `json:"failed"`
	Skipped      int             `json:"skipped"` // Colors not found
	AllPassed    bool            `json:"all_passed"`
	FailedChecks []ContrastCheck `json:"failed_checks,omitempty"`
}

ContrastSummary provides a summary of contrast check results.

func SummarizeContrast

func SummarizeContrast(paletteName string, results []ContrastCheck) ContrastSummary

SummarizeContrast generates a summary from contrast check results.

type Loader

type Loader struct {
	// contains filtered or unexported fields
}

Loader handles palette discovery and loading from multiple sources.

func NewLoader

func NewLoader() *Loader

NewLoader creates a new Loader with default search paths. Search order: built-in, user config, project directory.

func NewLoaderWithPaths

func NewLoaderWithPaths(paths []string) *Loader

NewLoaderWithPaths creates a new Loader with custom search paths.

func (*Loader) AddPath

func (l *Loader) AddPath(path string)

AddPath adds a search path to the loader. Paths added later have higher priority.

func (*Loader) ClearCache

func (l *Loader) ClearCache()

ClearCache clears the palette cache.

func (*Loader) Discover

func (l *Loader) Discover() ([]PaletteInfo, error)

Discover finds all available palettes across all sources. Returns palette info sorted by source priority (built-in first, then user, then project).

func (*Loader) DiscoverByVariant

func (l *Loader) DiscoverByVariant(variant Variant) ([]PaletteInfo, error)

DiscoverByVariant finds all palettes with a specific variant.

func (*Loader) Load

func (l *Loader) Load(name string) (*Palette, error)

Load loads a palette by name. It searches built-in palettes first, then search paths in order. Returns ErrPaletteNotFound if the palette cannot be found.

type Palette

type Palette struct {
	// Metadata
	Name        string  `json:"name" toml:"name"`
	Variant     Variant `json:"variant" toml:"variant"`
	Author      string  `json:"author,omitempty" toml:"author,omitempty"`
	License     string  `json:"license,omitempty" toml:"license,omitempty"`
	Homepage    string  `json:"homepage,omitempty" toml:"homepage,omitempty"`
	Description string  `json:"description,omitempty" toml:"description,omitempty"`

	// Color definitions
	Colors     map[string]string `json:"colors" toml:"colors"`         // Raw colors (hex values)
	Semantic   map[string]string `json:"semantic" toml:"semantic"`     // Semantic mappings (references)
	Components map[string]string `json:"components" toml:"components"` // Component colors (references)

	// Source information (set after loading)
	Source     string `json:"-" toml:"-"` // "built-in", "user", "project"
	SourcePath string `json:"-" toml:"-"` // File path if loaded from file
	// contains filtered or unexported fields
}

Palette represents a complete color palette with metadata and color definitions.

func Load

func Load(name string) (*Palette, error)

Load loads a palette using the default loader.

func LoadBuiltin

func LoadBuiltin(name string) (*Palette, error)

LoadBuiltin loads a built-in palette by name. Returns ErrPaletteNotFound if the palette doesn't exist.

func LoadFromFile

func LoadFromFile(path string) (*Palette, error)

LoadFromFile loads a palette from a specific file path.

func NewPalette

func NewPalette(name string, variant Variant) *Palette

NewPalette creates a new empty palette with the given name and variant.

func (*Palette) AllContrastPairs

func (p *Palette) AllContrastPairs() []ContrastCheckSpec

AllContrastPairs returns all unique foreground/background pairs in the palette. Useful for comprehensive contrast checking.

func (*Palette) CheckContrast

func (p *Palette) CheckContrast() []ContrastCheck

CheckContrast checks all required contrast ratios for the palette. Returns a slice of ContrastCheck results.

func (*Palette) CheckContrastStrict

func (p *Palette) CheckContrastStrict() []ContrastCheck

CheckContrastStrict checks both required and strict contrast ratios. Returns a slice of ContrastCheck results including AAA level checks.

func (*Palette) CheckContrastWith

func (p *Palette) CheckContrastWith(specs []ContrastCheckSpec) []ContrastCheck

CheckContrastWith checks contrast using custom check specifications.

func (*Palette) Clone

func (p *Palette) Clone() *Palette

Clone creates a deep copy of the palette.

func (*Palette) ExportJSON

func (p *Palette) ExportJSON(includeResolved bool) ([]byte, error)

ExportJSON exports the palette as JSON. If includeResolved is true, includes all resolved hex values.

func (*Palette) GenerateCSS

func (p *Palette) GenerateCSS() string

GenerateCSS generates CSS custom properties from the palette.

func (*Palette) GenerateCSSWithFormat

func (p *Palette) GenerateCSSWithFormat(format CSSFormat) string

GenerateCSSWithFormat generates CSS with custom format options.

func (*Palette) GenerateSCSS

func (p *Palette) GenerateSCSS() string

GenerateSCSS generates SCSS variables from the palette.

func (*Palette) GenerateTailwind

func (p *Palette) GenerateTailwind() string

GenerateTailwind generates Tailwind CSS configuration for the palette.

func (*Palette) Resolve

func (p *Palette) Resolve(name string) string

Resolve resolves a color name to its hex value. It checks in order: resolved cache, raw colors, semantic colors, component colors. Returns empty string if not found.

func (*Palette) ResolveAll

func (p *Palette) ResolveAll() (map[string]string, error)

ResolveAll resolves all colors and returns a map of name -> hex. Returns an error if any color cannot be resolved.

func (*Palette) Validate

func (p *Palette) Validate() []error

Validate validates the palette structure and color references.

type PaletteExport

type PaletteExport struct {
	Name        string            `json:"name"`
	Variant     string            `json:"variant"`
	Author      string            `json:"author,omitempty"`
	License     string            `json:"license,omitempty"`
	Homepage    string            `json:"homepage,omitempty"`
	Description string            `json:"description,omitempty"`
	Colors      map[string]string `json:"colors"`
	Semantic    map[string]string `json:"semantic"`
	Components  map[string]string `json:"components,omitempty"`
	Resolved    map[string]string `json:"resolved,omitempty"`
}

ExportJSON exports the palette as JSON with resolved colors.

type PaletteInfo

type PaletteInfo struct {
	Name        string  `json:"name"`
	Variant     Variant `json:"variant"`
	Description string  `json:"description,omitempty"`
	Author      string  `json:"author,omitempty"`
	Source      string  `json:"source"` // "built-in", "user", "project"
	Path        string  `json:"path,omitempty"`
}

PaletteInfo contains summary information about a palette for listing.

func Discover

func Discover() ([]PaletteInfo, error)

Discover discovers all palettes using the default loader.

func DiscoverBuiltin

func DiscoverBuiltin() []PaletteInfo

DiscoverBuiltin returns info about all built-in palettes.

type PaletteLoadError

type PaletteLoadError struct {
	Name    string // Palette name that failed to load
	Path    string // Path attempted (if applicable)
	Message string // Human-readable error message
	Err     error  // Underlying error
}

PaletteLoadError provides context for palette loading failures.

func NewPaletteLoadError

func NewPaletteLoadError(name, path, message string, err error) *PaletteLoadError

NewPaletteLoadError creates a new PaletteLoadError.

func (*PaletteLoadError) Error

func (e *PaletteLoadError) Error() string

func (*PaletteLoadError) Unwrap

func (e *PaletteLoadError) Unwrap() error

type PaletteVariants added in v0.5.0

type PaletteVariants struct {
	// Light is the light variant palette name (empty if not found)
	Light string `json:"light"`
	// Dark is the dark variant palette name (empty if not found)
	Dark string `json:"dark"`
	// Base is the base palette name without variant suffix
	Base string `json:"base"`
}

PaletteVariants holds the light and dark variants for a palette.

func DetectVariants added in v0.5.0

func DetectVariants(name string) PaletteVariants

DetectVariants detects light and dark palette variants for a given palette name. It uses intelligent mapping rules: 1. If palette ends with "-light" or "-dark", extract base and find pair 2. If palette has no suffix, try appending "-light" and "-dark" 3. For named variants (like catppuccin-latte), use known mappings

Examples:

  • "everforest" -> light: "everforest-light", dark: "everforest-dark"
  • "everforest-light" -> light: "everforest-light", dark: "everforest-dark"
  • "catppuccin-mocha" -> light: "catppuccin-latte", dark: "catppuccin-mocha"
  • "dracula" -> light: "", dark: "dracula" (no light variant)

type ValidationError

type ValidationError struct {
	Field   string // Field that failed validation
	Message string // Human-readable error message
}

ValidationError represents a palette validation failure.

func NewValidationError

func NewValidationError(field, message string) *ValidationError

NewValidationError creates a new ValidationError.

func (*ValidationError) Error

func (e *ValidationError) Error() string

type Variant

type Variant string

Variant represents the light/dark mode of a palette.

const (
	VariantLight Variant = "light"
	VariantDark  Variant = "dark"
)

type WCAGLevel

type WCAGLevel string

WCAGLevel represents WCAG compliance levels.

const (
	WCAGLevelA   WCAGLevel = "A"
	WCAGLevelAA  WCAGLevel = "AA"
	WCAGLevelAAA WCAGLevel = "AAA"
)

func PassedLevels

func PassedLevels(ratio float64, isLargeText bool) []WCAGLevel

PassedLevels returns all WCAG levels that a contrast ratio passes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL