diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/i18n/el.go | 8 | ||||
| -rw-r--r-- | internal/web/static/blog.css | 18 | ||||
| -rw-r--r-- | internal/web/templates/dashboard/design.html | 17 | ||||
| -rw-r--r-- | internal/web/theme.go | 25 | ||||
| -rw-r--r-- | internal/web/web_test.go | 18 |
5 files changed, 70 insertions, 16 deletions
diff --git a/internal/i18n/el.go b/internal/i18n/el.go index bdec8a2..2afef53 100644 --- a/internal/i18n/el.go +++ b/internal/i18n/el.go @@ -389,6 +389,14 @@ var el = map[string]string{ "Tall": "Ψηλό", "menu in the header": "μενού στην κεφαλίδα", "Underline": "Υπογράμμιση", + "Spread out": "Απλωμένοι", + "Spacing": "Απόσταση", + "Tight": "Σφιχτή", + "Wide": "Πλατιά", + "Current page": "Τρέχουσα σελίδα", + "Underlined": "Υπογραμμισμένη", + "Boxed": "Σε πλαίσιο", + "Not marked": "Χωρίς σήμανση", "Uppercase, spaced": "Κεφαλαία, αραιά", "Show the date on posts": "Εμφάνιση ημερομηνίας στις δημοσιεύσεις", "Show tags with a # in front": "Εμφάνιση των ετικετών με # μπροστά", diff --git a/internal/web/static/blog.css b/internal/web/static/blog.css index 054532d..7b91dbe 100644 --- a/internal/web/static/blog.css +++ b/internal/web/static/blog.css @@ -32,7 +32,23 @@ img { max-width: 100%; height: auto; } /* menu link styles (body.nav-*, from the theme's switches; colours are the theme CSS's) */ .nav-bold .site-nav a { font-weight: bold; } .nav-upper .site-nav a { text-transform: uppercase; letter-spacing: 0.05em; } -.nav-ul-always .site-nav a, .nav-ul-hover .site-nav a:hover, .site-nav a.active { text-decoration: underline; } +.nav-ul-always .site-nav a, .nav-ul-hover .site-nav a:hover { text-decoration: underline; } +.nav-size-small .site-nav a { font-size: 0.9em; } +.nav-size-large .site-nav a { font-size: 1.15em; } +.nav-gap-tight .site-nav a { padding-left: 0.4em; padding-right: 0.4em; } +.nav-gap-wide .site-nav a { padding-left: 1.4em; padding-right: 1.4em; } +.nav-active-underline .site-nav a.active { text-decoration: underline; } +.nav-active-bold .site-nav a.active { font-weight: bold; } +.nav-active-box .site-nav a.active { box-shadow: inset 0 0 0 1px currentColor; border-radius: 3px; } +.nav-center .nav-inner { text-align: center; } +.nav-right .nav-inner { text-align: right; } +/* spread: the header's links share the bar evenly — justified text with a + full-width last line, which old browsers lay out too; line-height 0 keeps + that forced line from adding height, the links carry their own. A floated + search box just shortens the line. */ +.nav-spread .site-header .nav-inner { text-align: justify; line-height: 0; } +.nav-spread .site-header .nav-inner > a, .nav-spread .site-header .search-form { line-height: 1.5; } +.nav-spread .site-header .nav-inner::after { content: ""; display: inline-block; width: 100%; } .body-wrap { padding: 1.5em 1em; } .content { padding: 1.5em 2em; border-radius: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.15); } .page-title { margin-top: 0; } diff --git a/internal/web/templates/dashboard/design.html b/internal/web/templates/dashboard/design.html index 7b11e44..ec4f70d 100644 --- a/internal/web/templates/dashboard/design.html +++ b/internal/web/templates/dashboard/design.html @@ -154,12 +154,29 @@ <option value="left"{{if eq $t.NavAlign "left"}} selected{{end}}>{{t "Left"}}</option> <option value="center"{{if eq $t.NavAlign "center"}} selected{{end}}>{{t "Centred"}}</option> <option value="right"{{if eq $t.NavAlign "right"}} selected{{end}}>{{t "Right"}}</option> + <option value="spread"{{if eq $t.NavAlign "spread"}} selected{{end}}>{{t "Spread out"}}</option> + </select></label> + <label>{{t "Size"}}<br><select name="nav_size"> + <option value="small"{{if eq $t.NavSize "small"}} selected{{end}}>{{t "Small"}}</option> + <option value="normal"{{if eq $t.NavSize "normal"}} selected{{end}}>{{t "Normal"}}</option> + <option value="large"{{if eq $t.NavSize "large"}} selected{{end}}>{{t "Large"}}</option> + </select></label> + <label>{{t "Spacing"}}<br><select name="nav_gap"> + <option value="tight"{{if eq $t.NavGap "tight"}} selected{{end}}>{{t "Tight"}}</option> + <option value="normal"{{if eq $t.NavGap "normal"}} selected{{end}}>{{t "Normal"}}</option> + <option value="wide"{{if eq $t.NavGap "wide"}} selected{{end}}>{{t "Wide"}}</option> </select></label> <label>{{t "Underline"}}<br><select name="nav_underline"> <option value="never"{{if eq $t.NavUnderline "never"}} selected{{end}}>{{t "Never"}}</option> <option value="hover"{{if eq $t.NavUnderline "hover"}} selected{{end}}>{{t "Only on hover"}}</option> <option value="always"{{if eq $t.NavUnderline "always"}} selected{{end}}>{{t "Always"}}</option> </select></label> + <label>{{t "Current page"}}<br><select name="nav_active"> + <option value="underline"{{if eq $t.NavActive "underline"}} selected{{end}}>{{t "Underlined"}}</option> + <option value="bold"{{if eq $t.NavActive "bold"}} selected{{end}}>{{t "Bold"}}</option> + <option value="box"{{if eq $t.NavActive "box"}} selected{{end}}>{{t "Boxed"}}</option> + <option value="none"{{if eq $t.NavActive "none"}} selected{{end}}>{{t "Not marked"}}</option> + </select></label> <label>{{t "Background"}}<br><input type="color" name="nav_bg" value="{{$t.NavBg}}"></label> <label>{{t "Text"}}<br><input type="color" name="nav_text" value="{{$t.NavText}}"></label> </div> diff --git a/internal/web/theme.go b/internal/web/theme.go index 9eae856..031f8fd 100644 --- a/internal/web/theme.go +++ b/internal/web/theme.go @@ -42,7 +42,7 @@ type Theme struct { TitleSize string `json:"title_size"` // normal | small | large (the site title in the header) 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) + NavAlign string `json:"nav_align"` // left | center | right | spread (header menu) // 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, @@ -51,6 +51,9 @@ type Theme struct { NavBold bool `json:"nav_bold"` NavUpper bool `json:"nav_upper"` // uppercase, letter-spaced NavUnderline string `json:"nav_underline"` // hover | never | always + NavSize string `json:"nav_size"` // normal | small | large + NavGap string `json:"nav_gap"` // normal | tight | wide (space around each link) + NavActive string `json:"nav_active"` // underline | bold | box | none: how the current page's link is marked NavBg string `json:"nav_bg"` NavText string `json:"nav_text"` NavHover string `json:"nav_hover"` // "" = same as NavText @@ -115,7 +118,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", NavBold: true, NavUnderline: "hover", NavBg: "#ffffff", NavText: "#222222", + NavAlign: "left", NavBold: true, NavUnderline: "hover", NavSize: "normal", NavGap: "normal", NavActive: "underline", 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", @@ -133,7 +136,7 @@ func ParseTheme(raw json.RawMessage) Theme { // it stood for, and is dropped from the JSON on the next save. switch t.NavStyle { case "uppercase": - t.NavUpper = true + t.NavUpper, t.NavSize = true, "small" // the smaller size was part of that look case "plain": t.NavBold, t.NavUnderline = false, "always" } @@ -205,8 +208,11 @@ func (t *Theme) normalize() { t.HeaderText = color(t.HeaderText, d.HeaderText) 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.NavAlign = pick(t.NavAlign, "left", "center", "right", "spread") t.NavUnderline = pick(t.NavUnderline, "hover", "never", "always") + t.NavSize = pick(t.NavSize, "normal", "small", "large") + t.NavGap = pick(t.NavGap, "normal", "tight", "wide") + t.NavActive = pick(t.NavActive, "underline", "bold", "box", "none") t.NavBg = color(t.NavBg, d.NavBg) t.NavText = color(t.NavText, d.NavText) t.NavHover = optColor(t.NavHover) @@ -278,6 +284,9 @@ func ThemeFromForm(cur Theme, f url.Values) Theme { t.NavBold = on("nav_bold") t.NavUpper = on("nav_upper") t.NavUnderline = get("nav_underline") + t.NavSize = get("nav_size") + t.NavGap = get("nav_gap") + t.NavActive = get("nav_active") t.NavBg = get("nav_bg") t.NavText = get("nav_text") t.NavHover = hover("nav_hover") @@ -522,10 +531,11 @@ 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. +// NavClass is the body classes blog.css draws the menu links from (alignment, +// underline, size, spacing, the current page's mark, weight, case); the theme +// CSS only colours them. func (t Theme) NavClass() string { - c := []string{"nav-ul-" + t.NavUnderline} + c := []string{"nav-" + t.NavAlign, "nav-ul-" + t.NavUnderline, "nav-size-" + t.NavSize, "nav-gap-" + t.NavGap, "nav-active-" + t.NavActive} if t.NavBold { c = append(c, "nav-bold") } @@ -581,7 +591,6 @@ a:hover {{"{"}}{{if .LinkHover}} color:{{.LinkHover}};{{end}}{{if eq .LinkUnderl .site-header a { color:{{.HeaderText}}; } .header-image img { max-height:{{.HeaderImageMaxHeight}}; } .site-nav { background:{{.NavBg}}; } -.nav-inner { text-align:{{.NavAlign}}; } .site-nav a { color:{{.NavText}}; } {{- if .NavHover}} .site-nav a:hover { color:{{.NavHover}}; } diff --git a/internal/web/web_test.go b/internal/web/web_test.go index e12f9e0..45bdf22 100644 --- a/internal/web/web_test.go +++ b/internal/web/web_test.go @@ -107,12 +107,12 @@ func TestThemeNormalizeAndCSS(t *testing.T) { if th.BgColor != "#abcdef" || th.BgImage != "" || th.LogoSize != "large" || th.RuleClass() != "ruled rule-stripes" { t.Errorf("from form: %+v", th) } - if th.LinkHover != "" || th.NavHover != "#00ff00" || th.ShowDates || th.DateFormat != "iso" || th.NavBold || !th.NavUpper { + if th.LinkHover != "" || th.NavHover != "#00ff00" || th.ShowDates || th.DateFormat != "iso" || th.NavBold || !th.NavUpper || th.NavAlign != "center" { t.Errorf("hover checkbox / unticked checkboxes: %+v", th) } css := th.CSS() for _, want := range []string{"background-color:#abcdef", ".site-nav a:hover { color:#00ff00", "a:hover { text-decoration:underline", - "h1, h2, h3, h4, h5, h6 { font-family:Georgia", "text-align:center", "border-radius:0", "padding:2.2em 3em", "@media (max-width: 700px)", ".logo { max-height:140px"} { + "h1, h2, h3, h4, h5, h6 { font-family:Georgia", "border-radius:0", "padding:2.2em 3em", "@media (max-width: 700px)", ".logo { max-height:140px"} { if !strings.Contains(css, want) { t.Errorf("css missing %q:\n%s", want, css) } @@ -143,16 +143,16 @@ func TestThemeNormalizeAndCSS(t *testing.T) { // from stored themes (bold + hover underline is what blog.css always drew). func TestNavStyles(t *testing.T) { th := ParseTheme([]byte(`{"nav_style":"uppercase"}`)) - if !th.NavUpper || !th.NavBold || th.NavUnderline != "hover" || th.NavStyle != "" || strings.Contains(string(th.JSON()), "nav_style") { + if !th.NavUpper || th.NavSize != "small" || !th.NavBold || th.NavUnderline != "hover" || th.NavStyle != "" || strings.Contains(string(th.JSON()), "nav_style") { t.Errorf("uppercase migration: %+v %s", th, th.JSON()) } th = ParseTheme([]byte(`{"nav_style":"plain"}`)) if th.NavBold || th.NavUpper || th.NavUnderline != "always" { t.Errorf("plain migration: %+v", th) } - for _, raw := range []string{`{}`, `{"nav_style":"normal"}`, `{"nav_underline":"wavy"}`} { + for _, raw := range []string{`{}`, `{"nav_style":"normal"}`, `{"nav_underline":"wavy","nav_size":"huge","nav_gap":"x","nav_active":"blink","nav_align":"justify"}`} { th = ParseTheme([]byte(raw)) - if !th.NavBold || th.NavUpper || th.NavUnderline != "hover" || th.NavClass() != "nav-ul-hover nav-bold" { + if !th.NavBold || th.NavUpper || th.NavUnderline != "hover" || th.NavClass() != "nav-left nav-ul-hover nav-size-normal nav-gap-normal nav-active-underline nav-bold" { t.Errorf("%s: %+v %q", raw, th, th.NavClass()) } } @@ -160,10 +160,14 @@ func TestNavStyles(t *testing.T) { if th = ParseTheme([]byte(`{"nav_bold":false,"nav_upper":true,"nav_underline":"never"}`)); th.NavBold || !th.NavUpper || th.NavUnderline != "never" { t.Errorf("stored switches: %+v", th) } - th = ThemeFromForm(DefaultTheme(), url.Values{"nav_underline": {"always"}}) - if th.NavBold || th.NavUpper || th.NavClass() != "nav-ul-always" { + th = ThemeFromForm(DefaultTheme(), url.Values{"nav_underline": {"always"}, "nav_align": {"spread"}, "nav_size": {"large"}, "nav_gap": {"wide"}, "nav_active": {"box"}}) + if th.NavBold || th.NavUpper || th.NavClass() != "nav-spread nav-ul-always nav-size-large nav-gap-wide nav-active-box" { t.Errorf("from form: %+v %q", th, th.NavClass()) } + // Alignment is a class now; the theme CSS says nothing about it. + if css := th.CSS(); strings.Contains(css, "nav-inner") { + t.Errorf("nav align in css: %s", css) + } } // Announcements on post pages are on by default (the look blogs had before |
