From 08da6a47236a4e351a6ce9ab85f2205a37b40f83 Mon Sep 17 00:00:00 2001 From: Alex Dunmow Date: Tue, 4 Aug 2026 00:54:07 +0800 Subject: [PATCH] chore(theme): re-vendor cms theme copies for font size steps Picks up FontSizeStepKeys/DefaultFontSizeSteps/ValidateFontSizeSteps and the FontSizeSteps field on ThemeTypography, so the preset gate's DisallowUnknownFields parse accepts presets shipping fontSizeSteps. Co-Authored-By: Claude Fable 5 --- internal/theme/defaults.go | 1 + internal/theme/fontsize.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/internal/theme/defaults.go b/internal/theme/defaults.go index dcccd0e..37aa3bf 100644 --- a/internal/theme/defaults.go +++ b/internal/theme/defaults.go @@ -236,6 +236,7 @@ type ThemeTypography struct { LineHeightBase string `json:"lineHeightBase"` FontWeightBase string `json:"fontWeightBase"` FontSizeOverrides map[string]string `json:"fontSizeOverrides,omitempty"` + FontSizeSteps map[string]string `json:"fontSizeSteps,omitempty"` } // ThemeSpacing represents spacing settings diff --git a/internal/theme/fontsize.go b/internal/theme/fontsize.go index 990d814..12bb95b 100644 --- a/internal/theme/fontsize.go +++ b/internal/theme/fontsize.go @@ -3,6 +3,7 @@ package theme import ( "fmt" "regexp" + "slices" "sort" "strconv" "strings" @@ -19,6 +20,41 @@ var fontSizeOverrideKeys = map[string]bool{ var fontSizePattern = regexp.MustCompile(`^(\d+(?:\.\d+)?|\.\d+)(rem|px)$`) +var fontSizeStepKeys = []string{"small", "normal", "large", "huge"} + +// FontSizeStepKeys returns the canonical step keys in display order. +func FontSizeStepKeys() []string { + return slices.Clone(fontSizeStepKeys) +} + +// DefaultFontSizeSteps returns the fallback rem value for each step. +func DefaultFontSizeSteps() map[string]string { + return map[string]string{ + "small": "0.875rem", + "normal": "1rem", + "large": "1.125rem", + "huge": "1.25rem", + } +} + +// ValidateFontSizeSteps rejects unknown keys and non-rem values. Steps feed the +// base-size UI chips only and are never emitted to CSS; rem-only so chips always +// scale with visitor preferences. +func ValidateFontSizeSteps(steps map[string]string) error { + for k, v := range steps { + if !slices.Contains(fontSizeStepKeys, k) { + return fmt.Errorf("unknown font size step %q (valid: %s)", k, strings.Join(fontSizeStepKeys, ", ")) + } + if err := ValidateFontSize(v); err != nil { + return err + } + if !strings.HasSuffix(v, "rem") { + return fmt.Errorf("font size step %q must be a rem value, got %q", k, v) + } + } + return nil +} + // FontSizeOverrideKeys returns the canonical override keys, sorted. func FontSizeOverrideKeys() []string { keys := make([]string, 0, len(fontSizeOverrideKeys))