aboutsummaryrefslogtreecommitdiffstats
path: root/internal/web/theme.go
diff options
context:
space:
mode:
authorgrm <grm@eyesin.space>2026-09-18 19:17:17 +0300
committergrm <grm@eyesin.space>2026-09-18 19:17:17 +0300
commitb88a7d22c8d79b30de3403c631dd2c5f67669537 (patch)
tree90fd4215595aedee86bfa4603b41e9f8bbfb04d2 /internal/web/theme.go
parent7ac90f8e99dbf763b0fe04a17d7eef19dd22cae8 (diff)
downloadblogspace-b88a7d22c8d79b30de3403c631dd2c5f67669537.tar.gz
blogspace-b88a7d22c8d79b30de3403c631dd2c5f67669537.tar.bz2
blogspace-b88a7d22c8d79b30de3403c631dd2c5f67669537.zip
Make the menu link styles switches that combine
The one "Link style" select (normal, uppercase, plain) could not give uppercase links without the bold, or underlined bold links. Bold, uppercase and the underline (never, on hover, always) are now separate switches, drawn by blog.css from body classes (Theme.NavClass) so the theme CSS only colours the links. A stored nav_style is mapped onto the switches when the theme is read and dropped on the next save; themes without either keep the bold, underline-on-hover look blog.css always had. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
Diffstat (limited to 'internal/web/theme.go')
-rw-r--r--internal/web/theme.go47
1 files changed, 39 insertions, 8 deletions
diff --git a/internal/web/theme.go b/internal/web/theme.go
index 0437f51..9eae856 100644
--- a/internal/web/theme.go
+++ b/internal/web/theme.go
@@ -43,10 +43,17 @@ type Theme struct {
HeaderRule string `json:"header_rule"` // none | line | dots | stripes, drawn beside the title/logo modules in the header
NavAlign string `json:"nav_align"` // left | center | right (header menu)
- NavStyle string `json:"nav_style"` // normal | uppercase | plain (regular weight, underlined)
- NavBg string `json:"nav_bg"`
- NavText string `json:"nav_text"`
- NavHover string `json:"nav_hover"` // "" = same as NavText
+ // The link styles are switches that combine; blog.css draws them from
+ // the body classes NavClass makes. NavStyle is the select they replaced
+ // (normal | uppercase | plain): still decoded from themes saved before,
+ // turned into the switches by ParseTheme and never written again.
+ NavStyle string `json:"nav_style,omitempty"`
+ NavBold bool `json:"nav_bold"`
+ NavUpper bool `json:"nav_upper"` // uppercase, letter-spaced
+ NavUnderline string `json:"nav_underline"` // hover | never | always
+ NavBg string `json:"nav_bg"`
+ NavText string `json:"nav_text"`
+ NavHover string `json:"nav_hover"` // "" = same as NavText
ShowDates bool `json:"show_dates"`
DateFormat string `json:"date_format"` // long | short | iso (rendered by i18n.FormatDate)
@@ -108,7 +115,7 @@ func DefaultTheme() Theme {
ContentStyle: "card", ContentPadding: "normal",
Font: "sans", HeadingFont: "same", FontSize: "normal",
HeaderImageHeight: "medium", HeaderAlign: "left", HeaderBg: "#2f3a4a", HeaderText: "#ffffff", TitleSize: "normal", HeaderRule: "none",
- NavAlign: "left", NavStyle: "normal", NavBg: "#ffffff", NavText: "#222222",
+ NavAlign: "left", NavBold: true, NavUnderline: "hover", NavBg: "#ffffff", NavText: "#222222",
ShowDates: true, DateFormat: "long", PostsPerPage: postsPerPageChoices[0], ListStyle: "full", PostImage: "top", TitleRule: "none", PostNotices: true,
FooterBg: "#2f3a4a", FooterColor: "#d0d5dc", FooterAlign: "center",
LogoSize: "medium",
@@ -122,6 +129,15 @@ func ParseTheme(raw json.RawMessage) Theme {
if len(raw) > 0 {
_ = json.Unmarshal(raw, &t)
}
+ // Themes saved with the old link-style select: it becomes the switches
+ // it stood for, and is dropped from the JSON on the next save.
+ switch t.NavStyle {
+ case "uppercase":
+ t.NavUpper = true
+ case "plain":
+ t.NavBold, t.NavUnderline = false, "always"
+ }
+ t.NavStyle = ""
t.normalize()
return t
}
@@ -190,7 +206,7 @@ func (t *Theme) normalize() {
t.TitleSize = pick(t.TitleSize, "normal", "small", "large")
t.HeaderRule = pick(t.HeaderRule, "none", "line", "dots", "stripes")
t.NavAlign = pick(t.NavAlign, "left", "center", "right")
- t.NavStyle = pick(t.NavStyle, "normal", "uppercase", "plain")
+ t.NavUnderline = pick(t.NavUnderline, "hover", "never", "always")
t.NavBg = color(t.NavBg, d.NavBg)
t.NavText = color(t.NavText, d.NavText)
t.NavHover = optColor(t.NavHover)
@@ -259,7 +275,9 @@ func ThemeFromForm(cur Theme, f url.Values) Theme {
t.TitleSize = get("title_size")
t.HeaderRule = get("header_rule")
t.NavAlign = get("nav_align")
- t.NavStyle = get("nav_style")
+ t.NavBold = on("nav_bold")
+ t.NavUpper = on("nav_upper")
+ t.NavUnderline = get("nav_underline")
t.NavBg = get("nav_bg")
t.NavText = get("nav_text")
t.NavHover = hover("nav_hover")
@@ -504,6 +522,19 @@ func (t Theme) RuleClass() string {
return "ruled rule-" + t.HeaderRule
}
+// NavClass is the body classes blog.css draws the menu links from (weight,
+// case, underline); the theme CSS only colours them.
+func (t Theme) NavClass() string {
+ c := []string{"nav-ul-" + t.NavUnderline}
+ if t.NavBold {
+ c = append(c, "nav-bold")
+ }
+ if t.NavUpper {
+ c = append(c, "nav-upper")
+ }
+ return strings.Join(c, " ")
+}
+
// TitleRuleClass is the body class blog.css draws the rule under page and
// post titles from; the theme CSS only colours it.
func (t Theme) TitleRuleClass() string {
@@ -551,7 +582,7 @@ a:hover {{"{"}}{{if .LinkHover}} color:{{.LinkHover}};{{end}}{{if eq .LinkUnderl
.header-image img { max-height:{{.HeaderImageMaxHeight}}; }
.site-nav { background:{{.NavBg}}; }
.nav-inner { text-align:{{.NavAlign}}; }
-.site-nav a { color:{{.NavText}};{{if eq .NavStyle "uppercase"}} text-transform:uppercase; letter-spacing:0.05em; font-size:0.9em;{{else if eq .NavStyle "plain"}} font-weight:normal; text-decoration:underline;{{end}} }
+.site-nav a { color:{{.NavText}}; }
{{- if .NavHover}}
.site-nav a:hover { color:{{.NavHover}}; }
{{- end}}