Documentation
¶
Overview ¶
Package theme defines the per-project design system: a small, versioned set of tokens (colors, typography, spacing, corner radius, logo, legal links) that every end-user surface — the Flutter login screen, hosted web pages, emails — renders from. The token space is deliberately constrained so that every accepted theme produces a legible screen: Validate enforces WCAG AA contrast, curated fonts and sane ranges.
Index ¶
Constants ¶
const ( MinScale = 0.8 MaxScale = 1.4 MinSpacingUnit = 4 MaxSpacingUnit = 16 MaxCornerRadius = 32 )
Token ranges accepted by Validate.
const MinContrast = 4.5
MinContrast is the WCAG AA contrast ratio required between every color and its "on" counterpart, in both the light and the effective dark palette.
const SchemaVersion = 1
SchemaVersion is the version stamped on every encoded theme document. Parse rejects documents with a different version; future schema changes bump it and add an explicit upgrade path.
Variables ¶
var FontFamilies = func() []string { all := fonts.List() names := make([]string, len(all)) for i, f := range all { names[i] = f.Name } return names }()
FontFamilies is the curated set of open-license fonts embedded in the binary (internal/fonts), by display name; Typography.FontFamily must be one of them. Arbitrary font uploads are deliberately out of scope — a fixed set keeps mobile rendering predictable and the binary self-contained.
Functions ¶
func ContrastRatio ¶
ContrastRatio is the WCAG 2.x contrast ratio between two colors: (L1+0.05)/(L2+0.05) with L1 the lighter. Ranges from 1 (identical luminance) to 21 (black on white); order does not matter.
func Encode ¶
Encode serializes the theme as its canonical storage document (a moth.projectconfig.v1.StoredTheme protobuf message), stamping the current schema version. An encoded document is never empty: empty stored bytes keep meaning "the built-in default theme".
func ToProto ¶
func ToProto(t Theme) *projectconfigv1.StoredTheme
ToProto converts the domain theme into its storage message.
Types ¶
type Color ¶
type Color struct {
R, G, B uint8
}
Color is an opaque sRGB color.
func ParseColor ¶
ParseColor parses a strict "#RRGGBB" hex color (case-insensitive). Shorthand (#RGB) and alpha channels are rejected: the theme schema stores one canonical form.
type ColorOverrides ¶
type ColorOverrides struct {
Primary string
OnPrimary string
Background string
OnBackground string
Surface string
OnSurface string
Error string
OnError string
}
ColorOverrides is a partial palette: any empty field is derived from the light palette instead.
type Colors ¶
type Colors struct {
Primary string
OnPrimary string
Background string
OnBackground string
Surface string
OnSurface string
Error string
OnError string
}
Colors is a complete palette: every role and its "on" (foreground) counterpart. Values are #RRGGBB.
func DeriveDark ¶
func DeriveDark(light Colors, o *ColorOverrides) Colors
DeriveDark computes the effective dark palette from the light palette and the optional per-field overrides. The algorithm, applied to every field left empty in o (a nil o derives everything), is deterministic:
- background and surface: the light value blended 88% / 84% toward black — lands in the dark-neutral range while keeping a trace of the brand tint, with surface slightly lighter than background so elevation still reads.
- primary and error: the light value blended 40% toward white — the conventional pastel shift that keeps saturated brand colors legible on dark surfaces.
- every on* color: whichever of black/white contrasts more with its (derived or overridden) counterpart. This always meets WCAG AA: CR(c, white) x CR(c, black) = 21 for any c, so the larger of the two is at least sqrt(21) ~ 4.58 >= MinContrast.
light is assumed valid (see Validate); unparseable inputs derive from black.
type Logo ¶
Logo holds the server-managed asset paths of the uploaded logos, one per color scheme ("/assets/{project}/logo-light.png"). Empty = no logo.
type Shape ¶
type Shape struct {
// CornerRadius in logical pixels; 0..MaxCornerRadius.
CornerRadius int
}
Shape controls component rounding.
type Spacing ¶
type Spacing struct {
// Unit is the base spacing step in logical pixels;
// MinSpacingUnit..MaxSpacingUnit.
Unit int
}
Spacing is the base spacing grid.
type Theme ¶
type Theme struct {
// Version is the schema version of the document (SchemaVersion).
Version int
// Colors is the light palette. All fields are required #RRGGBB values.
Colors Colors
// DarkColors optionally overrides individual dark-palette colors.
// Omitted fields (and a nil struct) are derived from Colors — see
// DeriveDark for the algorithm.
DarkColors *ColorOverrides
Typography Typography
Spacing Spacing
Shape Shape
Logo Logo
Legal Legal
}
Theme is one project's complete design system. It is persisted as a moth.projectconfig.v1.StoredTheme protobuf document (see Encode/Parse).
func Default ¶
func Default() Theme
Default returns the theme applied to projects that never customized anything: the Material baseline palette, Inter at scale 1, an 8px grid and 12px corners.
func FromProto ¶
func FromProto(msg *projectconfigv1.StoredTheme) Theme
FromProto converts a storage message into the domain theme. Nil sub-messages become zero values; an absent dark_colors stays nil so the dark palette derives fully from the light one.
func Parse ¶
Parse decodes a stored theme document (moth.projectconfig.v1.StoredTheme). It rejects documents from a different schema version — including empty input, which callers treat as "default theme" before parsing; it does not validate token values (Validate does).
func ParseLegacyJSON ¶
ParseLegacyJSON decodes a pre-0019 JSON theme document. BACKFILL ONLY: it is exported solely for the one-time store backfill and must not be called from any live read/write path.
func (Theme) EffectiveDark ¶
EffectiveDark returns the dark palette actually rendered: explicit DarkColors overrides where present, derived values everywhere else.
func (Theme) Validate ¶
Validate checks every token of the theme, including the effective dark palette after derivation, and returns the first violation. A theme that validates is guaranteed to render legibly: WCAG AA contrast on every color/on-color pair, a curated font, and in-range scale/spacing/radius.
type Typography ¶
type Typography struct {
// FontFamily must be one of FontFamilies.
FontFamily string
// Scale multiplies every text size; MinScale..MaxScale.
Scale float64
}
Typography selects one of the curated embedded fonts and a global size multiplier.