Alex Dunmow cd88c808b0 initial: standalone check-safety module hoisted from CMS
Static safety/lint runner for the BlockNinja codebase. ~25 invariant
checks across Go and frontend sources. Was at git.dev.alexdunmow.com:block/ninja
in backend/cmd/check-safety/ until the 2026-06-06 consolidation moved
the BlockNinja repos under a shared ~/src/blockninja/ parent.

This repo is the standalone extraction:
- Own go.mod (git.dev.alexdunmow.com/block/check-safety, go 1.26.4)
- Vendored internal/{helpers,theme} from CMS (Go's internal/ rule
  blocks cross-module imports; vendoring is the workaround)
- CLI contract unchanged: `check-safety <target-dir> [--flags]`
- CMS Makefile shells into ../check-safety for safety-check /
  install-safety-checker targets

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 13:04:02 +08:00

326 lines
12 KiB
Go

package theme
// DefaultTheme returns the default theme settings
func DefaultTheme() *Theme {
return &Theme{
LightColors: &ColorScheme{
Background: "0 0% 100%",
Foreground: "0 0% 3.9%",
Card: "0 0% 100%",
CardForeground: "0 0% 3.9%",
Popover: "0 0% 100%",
PopoverForeground: "0 0% 3.9%",
Primary: "0 0% 9%",
PrimaryForeground: "0 0% 98%",
Secondary: "0 0% 96.1%",
SecondaryForeground: "0 0% 9%",
Muted: "0 0% 96.1%",
MutedForeground: "0 0% 45.1%",
Accent: "0 0% 96.1%",
AccentForeground: "0 0% 9%",
Destructive: "0 84.2% 60.2%",
DestructiveForeground: "0 0% 98%",
Border: "0 0% 89.8%",
Input: "0 0% 89.8%",
Ring: "0 0% 3.9%",
},
DarkColors: &ColorScheme{
Background: "0 0% 3.9%",
Foreground: "0 0% 98%",
Card: "0 0% 3.9%",
CardForeground: "0 0% 98%",
Popover: "0 0% 3.9%",
PopoverForeground: "0 0% 98%",
Primary: "0 0% 98%",
PrimaryForeground: "0 0% 9%",
Secondary: "0 0% 14.9%",
SecondaryForeground: "0 0% 98%",
Muted: "0 0% 14.9%",
MutedForeground: "0 0% 63.9%",
Accent: "0 0% 14.9%",
AccentForeground: "0 0% 98%",
Destructive: "0 62.8% 30.6%",
DestructiveForeground: "0 0% 98%",
Border: "0 0% 14.9%",
Input: "0 0% 14.9%",
Ring: "0 0% 83.1%",
},
Typography: &ThemeTypography{
FontHeading: "system",
FontBody: "system",
FontMono: "system",
FontSizeBase: "16",
LineHeightBase: "1.5",
FontWeightBase: "normal",
},
Spacing: &ThemeSpacing{
Radius: "0.5",
ButtonRadius: "0.375",
CardRadius: "0.75",
InputRadius: "0.375",
PillButtons: false,
BorderWidth: "normal",
ContainerWidth: "normal",
SpacingScale: "normal",
},
Effects: &ThemeEffects{
ShadowIntensity: 50,
ShadowColor: "0 0% 0%",
ShadowBlur: "normal",
ElevationPreset: "raised",
TransitionSpeed: "normal",
ReduceMotion: false,
HoverIntensity: "normal",
},
Mode: "system",
Buttons: &ThemeButtons{
Primary: &ButtonTypeConfig{
BgColor: "var(--primary)",
TextColor: "var(--primary-foreground)",
BorderWidth: "0",
Radius: "0.375",
Shadow: "none",
HoverBg: "var(--primary)/90",
},
Secondary: &ButtonTypeConfig{
BgColor: "var(--secondary)",
TextColor: "var(--secondary-foreground)",
BorderWidth: "0",
Radius: "0.375",
Shadow: "none",
HoverBg: "var(--secondary)/80",
},
Outline: &ButtonTypeConfig{
BgColor: "transparent",
TextColor: "var(--primary)",
BorderColor: "var(--border)",
BorderWidth: "1",
Radius: "0.375",
Shadow: "none",
HoverBg: "var(--accent)",
},
Ghost: &ButtonTypeConfig{
BgColor: "transparent",
TextColor: "var(--foreground)",
BorderWidth: "0",
Radius: "0.375",
Shadow: "none",
HoverBg: "var(--accent)",
},
Link: &ButtonTypeConfig{
BgColor: "transparent",
TextColor: "var(--primary)",
BorderWidth: "0",
Radius: "0",
Shadow: "none",
},
Destructive: &ButtonTypeConfig{
BgColor: "var(--destructive)",
TextColor: "var(--destructive-foreground)",
BorderWidth: "0",
Radius: "0.375",
Shadow: "none",
HoverBg: "var(--destructive)/90",
},
},
Inputs: &ThemeInputs{
Default: &InputVariantConfig{
BgColor: "var(--background)",
BorderColor: "var(--input)",
BorderWidth: "1",
TextColor: "var(--foreground)",
FocusRing: "var(--ring)",
FocusBg: "",
FocusBorder: "",
HoverBg: "",
PlaceholderColor: "var(--muted-foreground)",
},
Filled: &InputVariantConfig{
BgColor: "var(--muted)",
BorderColor: "transparent",
BorderWidth: "1",
TextColor: "var(--foreground)",
FocusRing: "var(--ring)",
FocusBg: "var(--background)",
FocusBorder: "var(--input)",
HoverBg: "",
PlaceholderColor: "var(--muted-foreground)",
},
Outlined: &InputVariantConfig{
BgColor: "transparent",
BorderColor: "var(--input)",
BorderWidth: "2",
TextColor: "var(--foreground)",
FocusRing: "var(--ring)",
FocusBg: "",
FocusBorder: "var(--ring)",
HoverBg: "",
PlaceholderColor: "var(--muted-foreground)",
},
Ghost: &InputVariantConfig{
BgColor: "transparent",
BorderColor: "transparent",
BorderWidth: "1",
TextColor: "var(--foreground)",
FocusRing: "var(--ring)",
FocusBg: "var(--background)",
FocusBorder: "var(--input)",
HoverBg: "var(--muted)",
PlaceholderColor: "var(--muted-foreground)",
},
},
Cards: &ThemeCards{
BorderWidth: "1",
BorderStyle: "solid",
BorderColor: "var(--border)",
Shadow: "sm",
ShadowColor: "",
BgOpacity: "100",
BackdropBlur: "none",
HoverEffect: "none",
},
}
}
// Theme represents the complete theme configuration
type Theme struct {
LightColors *ColorScheme `json:"lightColors"`
DarkColors *ColorScheme `json:"darkColors"`
Typography *ThemeTypography `json:"typography"`
Spacing *ThemeSpacing `json:"spacing"`
Effects *ThemeEffects `json:"effects"`
Mode string `json:"mode"`
Buttons *ThemeButtons `json:"buttons,omitempty"`
Inputs *ThemeInputs `json:"inputs,omitempty"`
Cards *ThemeCards `json:"cards,omitempty"`
CustomColors []*CustomColor `json:"customColors,omitempty"`
}
// CustomColor represents a user-defined color variable with light and dark mode values
type CustomColor struct {
Name string `json:"name"` // Variable name (e.g., "brand") - becomes --color-{name}
LightValue string `json:"lightValue"` // HSL value for light mode
DarkValue string `json:"darkValue"` // HSL value for dark mode
Source string `json:"source,omitempty"` // "" = user-created, "pluginname" = plugin-provisioned
}
// ColorScheme represents colors for a single mode (light or dark)
type ColorScheme struct {
Background string `json:"background"`
Foreground string `json:"foreground"`
Card string `json:"card"`
CardForeground string `json:"cardForeground"`
Popover string `json:"popover"`
PopoverForeground string `json:"popoverForeground"`
Primary string `json:"primary"`
PrimaryForeground string `json:"primaryForeground"`
Secondary string `json:"secondary"`
SecondaryForeground string `json:"secondaryForeground"`
Muted string `json:"muted"`
MutedForeground string `json:"mutedForeground"`
Accent string `json:"accent"`
AccentForeground string `json:"accentForeground"`
Destructive string `json:"destructive"`
DestructiveForeground string `json:"destructiveForeground"`
Border string `json:"border"`
Input string `json:"input"`
Ring string `json:"ring"`
}
// ThemeTypography represents typography settings
type ThemeTypography struct {
FontHeading string `json:"fontHeading"`
FontBody string `json:"fontBody"`
FontMono string `json:"fontMono"`
FontSizeBase string `json:"fontSizeBase"`
LineHeightBase string `json:"lineHeightBase"`
FontWeightBase string `json:"fontWeightBase"`
}
// ThemeSpacing represents spacing settings
type ThemeSpacing struct {
Radius string `json:"radius"`
ButtonRadius string `json:"buttonRadius"`
CardRadius string `json:"cardRadius"`
InputRadius string `json:"inputRadius"`
PillButtons bool `json:"pillButtons"`
BorderWidth string `json:"borderWidth"`
ContainerWidth string `json:"containerWidth"`
SpacingScale string `json:"spacingScale"`
}
// ThemeEffects represents shadow, motion, and effect settings
type ThemeEffects struct {
ShadowIntensity int `json:"shadowIntensity"`
ShadowColor string `json:"shadowColor"`
ShadowBlur string `json:"shadowBlur"`
ElevationPreset string `json:"elevationPreset"`
TransitionSpeed string `json:"transitionSpeed"`
ReduceMotion bool `json:"reduceMotion"`
HoverIntensity string `json:"hoverIntensity"`
}
// ButtonTypeConfig represents configuration for a single button type
type ButtonTypeConfig struct {
BgColor string `json:"bgColor"` // CSS value: "var(--primary)" | "transparent" | HSL
TextColor string `json:"textColor"` // CSS value: "var(--primary-foreground)" | HSL
BorderColor string `json:"borderColor"` // CSS value or empty
BorderWidth string `json:"borderWidth"` // "0" | "1" | "2" (px)
Radius string `json:"radius"` // rem value or "pill"
Shadow string `json:"shadow"` // "none" | "sm" | "md" | "lg"
HoverBg string `json:"hoverBg"` // CSS value for hover
HoverText string `json:"hoverText"` // CSS value for hover
Size string `json:"size"` // "sm" | "md" | "lg" - default button size
}
// ThemeButtons represents all button type configurations
type ThemeButtons struct {
Primary *ButtonTypeConfig `json:"primary"`
Secondary *ButtonTypeConfig `json:"secondary"`
Outline *ButtonTypeConfig `json:"outline"`
Ghost *ButtonTypeConfig `json:"ghost"`
Link *ButtonTypeConfig `json:"link"`
Destructive *ButtonTypeConfig `json:"destructive"`
Custom map[string]*ButtonTypeConfig `json:"custom,omitempty"`
}
// InputVariantConfig represents configuration for a single input variant
type InputVariantConfig struct {
BgColor string `json:"bgColor"` // CSS value: "var(--background)" | "var(--muted)" | transparent
BorderColor string `json:"borderColor"` // CSS value: "var(--input)" | "var(--border)"
BorderWidth string `json:"borderWidth"` // "0" | "1" | "2" (px)
TextColor string `json:"textColor"` // CSS value: "var(--foreground)"
FocusRing string `json:"focusRing"` // CSS value: "var(--ring)"
FocusBg string `json:"focusBg"` // Background when focused
FocusBorder string `json:"focusBorder"` // Border when focused
HoverBg string `json:"hoverBg"` // Background on hover (for ghost variant)
PlaceholderColor string `json:"placeholderColor"` // Placeholder text color
}
// ThemeInputs represents all input variant configurations
type ThemeInputs struct {
Default *InputVariantConfig `json:"default"`
Filled *InputVariantConfig `json:"filled"`
Outlined *InputVariantConfig `json:"outlined"`
Ghost *InputVariantConfig `json:"ghost"`
}
// ThemeCards represents card styling configuration
type ThemeCards struct {
// Border
BorderWidth string `json:"borderWidth"` // "0", "1", "2", "4" (px)
BorderStyle string `json:"borderStyle"` // "solid", "dashed", "dotted"
BorderColor string `json:"borderColor"` // CSS var or HSL value
// Shadow
Shadow string `json:"shadow"` // "none", "sm", "md", "lg", "xl"
ShadowColor string `json:"shadowColor"` // HSL for colored shadows
// Glass Effects
BgOpacity string `json:"bgOpacity"` // "100", "90", "80", "70" (percent)
BackdropBlur string `json:"backdropBlur"` // "none", "sm", "md", "lg"
// Hover Effects
HoverEffect string `json:"hoverEffect"` // "none", "lift", "glow", "scale"
}