From bfee129443b5607cd243e844a1d3978fe8eb3988 Mon Sep 17 00:00:00 2001 From: Andrew-71 Date: Wed, 8 May 2024 13:12:10 +0300 Subject: [PATCH] Add themes --- CHANGELOG.md | 6 +++ README.md | 3 +- TODO.md | 21 +++++++--- config.go | 2 + config/config.txt | 1 + info.go | 2 +- pages/base.html | 1 + public/main.css | 71 +++++++++++++++++++++++++-------- public/themes/default.css | 1 + public/themes/gruvbox.css | 26 ++++++++++++ public/themes/high-contrast.css | 26 ++++++++++++ routes.go | 4 +- 12 files changed, 139 insertions(+), 25 deletions(-) create mode 100644 public/themes/default.css create mode 100644 public/themes/gruvbox.css create mode 100644 public/themes/high-contrast.css diff --git a/CHANGELOG.md b/CHANGELOG.md index cc36c39..1302467 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog This file keeps track of changes in more human-readable fashion +## v0.3.0 +* Added themes + * Picked theme is set by `theme` key in config. Default is ...`default` + * Themes are defined in `/public/themes/.css` and modify colours (or, theoretically, do more) + * Current pre-made themes are `default`, `gruvbox` and `high-contrast` + ## v0.2.0 * Added config reload * Can be reloaded in info page diff --git a/README.md b/README.md index 454337a..8abbffb 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,8 @@ password=admin # Your password port=7101 # What port to run on (probably leave on 7101 if using docker) timezone=Local # IANA Time zone database identifier ("UTC", Local", "Europe/Moscow" etc.), Defaults to Local if can't parse. grace_period=0s # Time after a new day begins, but before the switch to next day's file. e.g. 2h30m - files will change at 2:30am -language=en # ISO-639 language code (currently supported - en, ru) +language=en # ISO-639 language code (pre-installed - en, ru) +theme=default # Picked theme (pre-installed - default, gruvbox, high-contrast) log_to_file=false # Whether to write logs to a file log_file=config/log.txt # Where to store the log file if it is enabled enable_scram=false # Whether the app should shut down if there are 3 or more failed login attempts within 100 seconds diff --git a/TODO.md b/TODO.md index 836812b..c3bd910 100644 --- a/TODO.md +++ b/TODO.md @@ -1,21 +1,32 @@ # TODO List of things to add to this project -## Agenda -* a 512x logo so I can enable PWA -* CI/CD pipeline -* Better docs in case others want to use this for some reason -* Check export function for improvements +## v1.0.0 +* a logo so I can enable PWA (and look cool) +* Themes + * Theme in config [X] + * Themes + * Default [X] + * Gruvbox [X] + * High contrast [ ] + * Seasons? + * Check for bugs +* Versioned containers via `ghcr.io` or `dockerhub`, +with automatic CI/CD build on release +* Test test test !!!! ## Brainstorming Don't expect any of this, these are ideas floating inside my head * Further info page functionality * Edit config * Statistics e.g. mb taken, number of day pages/notes + * Test telegram link * Multi-user support through several username-pass keys * `/data//...` * This would be an *extremely* breaking change * How to handle exporting *all*? Admin account? * I don't need this, unless Hibiscus.txt somehow gets popular why bother? Is this even a feature that fits the vision? +* Better, *multi-page* docs in case others want to use this for some reason +* Check export function for improvements * *Go* dependency-less? <-- this is a terrible idea diff --git a/config.go b/config.go index d3be98e..983434f 100644 --- a/config.go +++ b/config.go @@ -22,6 +22,7 @@ type Config struct { Timezone *time.Location `config:"timezone" type:"location"` GraceTime time.Duration `config:"grace_period" type:"duration"` Language string `config:"language" type:"string"` + Theme string `config:"theme" type:"string"` LogToFile bool `config:"log_to_file" type:"bool"` LogFile string `config:"log_file" type:"string"` Scram bool `config:"enable_scram" type:"bool"` @@ -141,6 +142,7 @@ func ConfigInit() Config { Password: "admin", Timezone: time.Local, Language: "en", + Theme: "default", LogFile: "config/log.txt", GraceTime: 0, } diff --git a/config/config.txt b/config/config.txt index 20fa453..d6238b0 100644 --- a/config/config.txt +++ b/config/config.txt @@ -4,6 +4,7 @@ port=7101 timezone=Local grace_period=0s language=en +theme=default log_to_file=false log_file=config/log.txt enable_scram=false diff --git a/info.go b/info.go index e4dbdd7..976b521 100644 --- a/info.go +++ b/info.go @@ -15,7 +15,7 @@ type HibiscusInfo struct { // Info contains app information var Info = HibiscusInfo{ - Version: "0.2.0", + Version: "0.3.0", SourceLink: "https://git.a71.su/Andrew71/hibiscus", } diff --git a/pages/base.html b/pages/base.html index 9aaf128..c6bfb1b 100644 --- a/pages/base.html +++ b/pages/base.html @@ -14,6 +14,7 @@ + Hibiscus.txt diff --git a/public/main.css b/public/main.css index 8338463..65834be 100644 --- a/public/main.css +++ b/public/main.css @@ -1,6 +1,33 @@ +/* Default theme */ +:root { + /* Light theme */ + --text-light: #454545; + --bg-light: #f5f0e1; + + --clickable-light: #f85552; + --clickable-hover-light: #e66868; + --clickable-label-light: #f5f2ee; + --text-hover-light: #656565; + + --textarea-bg-light: #f5f2ee; + --textarea-border-light: #454545; + + /* Dark theme */ + --text-dark: #f5f0e1; + --bg-dark: #2c2825; + + --clickable-dark: #f85552; + --clickable-hover-dark: #e66868; + --clickable-label-dark: #f5f2ee; + --text-hover-dark: #656565; + + --textarea-bg-dark: #383030; + --textarea-border-dark: #454545; +} + body { - color: #454545; - background-color: #f5f0e1; + color: var(--text-light); + background-color: var(--bg-light); margin: 2em auto; max-width: 640px; padding: 1em; @@ -11,33 +38,33 @@ body { display: flex; flex-direction: column; } -a, a:visited { color: #f85552; } -a:hover, a:visited:hover { color: #e66868; } -a.no-accent, a.no-accent:visited { color: #454545; } -a.no-accent:hover, a.no-accent:visited:hover { color: #656565; } +a, a:visited { color: var(--clickable-light); } +a:hover, a:visited:hover { color: var(--clickable-hover-light); } +a.no-accent, a.no-accent:visited { color: var(--text-light); } +a.no-accent:hover, a.no-accent:visited:hover { color: var(--text-hover-light); } h2 { margin-bottom:12px; } .list-title { margin-bottom: 0} .list-desc { margin-top: 0 } textarea, input { - background: #f5f2ee; + background: var(--textarea-bg-light); max-width: 640px; width: 100%; display: block; resize: vertical; outline: 0; box-shadow: none; - border: 0.0625em solid #454545; + border: 0.0625em solid var(--textarea-border-light); margin-bottom: 1em; font-size: 18px; } input { height: 2.5em; } button { - background-color: #f85552; + background-color: var(--clickable-light); border: none; - color: #f5f2ee; + color: var(--clickable-label-light); padding: 10px; text-align: center; text-decoration: none; @@ -49,7 +76,7 @@ button { max-width: 640px; width: 100%; } -button:hover { background-color: #e66868; } +button:hover { background-color: var(--clickable-hover-light); } footer { margin-top: auto; } header > h1, header > p { @@ -60,13 +87,23 @@ header > h1, header > p { /* Dark theme */ @media (prefers-color-scheme: dark) { body { - color: #f5f0e1; - background-color: #2c2825; + color: var(--text-dark); + background-color: var(--bg-dark); } textarea, input { - color: #f5f0e1; - background-color: #383030; + color: var(--text-dark); + background-color: var(--textarea-bg-dark); + border-color: var(--textarea-border-dark) } - a.no-accent, a.no-accent:visited { color: #f5f0e1; } - a.no-accent:hover, a.no-accent:visited:hover { color: #a9a8a4; } + + a, a:visited { color: var(--clickable-dark); } + a:hover, a:visited:hover { color: var(--clickable-hover-dark); } + a.no-accent, a.no-accent:visited { color: var(--text-dark); } + a.no-accent:hover, a.no-accent:visited:hover { color: var(--text-hover-dark); } + + button { + background-color: var(--clickable-dark); + color: var(--clickable-label-dark); + } + button:hover { background-color: var(--clickable-hover-dark); } } \ No newline at end of file diff --git a/public/themes/default.css b/public/themes/default.css new file mode 100644 index 0000000..d8ee906 --- /dev/null +++ b/public/themes/default.css @@ -0,0 +1 @@ +/* Default theme is defined in main.css */ \ No newline at end of file diff --git a/public/themes/gruvbox.css b/public/themes/gruvbox.css new file mode 100644 index 0000000..8b85f20 --- /dev/null +++ b/public/themes/gruvbox.css @@ -0,0 +1,26 @@ +/* Based on https://github.com/morhetz/gruvbox, MIT licensed colorscheme for vim */ +:root { + /* Light theme */ + --text-light: #3c3836; + --bg-light: #fbf1c7; + + --clickable-light: #cc241d; + --clickable-hover-light: #9d0006; + --clickable-label-light: #f9f5d7; + --text-hover-light: #665c54; + + --textarea-bg-light: #f9f5d7; + --textarea-border-light: #282828; + + /* Dark theme */ + --text-dark: #ebdbb2; + --bg-dark: #282828; + + --clickable-dark: #cc241d; + --clickable-hover-dark: #fb4934; + --clickable-label-dark: #fbf1c7; + --text-hover-dark: #fbf1c7; + + --textarea-bg-dark: #32302f; + --textarea-border-dark: #3c3836; +} \ No newline at end of file diff --git a/public/themes/high-contrast.css b/public/themes/high-contrast.css new file mode 100644 index 0000000..f2baddd --- /dev/null +++ b/public/themes/high-contrast.css @@ -0,0 +1,26 @@ +/* High contrast theme. It ain't pretty, but it passes WCAG AA and mostly even AAA */ +:root { + /* Light theme */ + --text-light: #000000; + --bg-light: #FFFFFF; + + --clickable-light: #CC0000; + --clickable-hover-light: #CC3333; + --clickable-label-light: #FFFFFF; + --text-hover-light: #666666; + + --textarea-bg-light: #FFFFFF; + --textarea-border-light: #000000; + + /* Dark theme */ + --text-dark: #FFFFFF; + --bg-dark: #000000; + + --clickable-dark: #FF3333; + --clickable-hover-dark: #FF6666; + --clickable-label-dark: #000000; + --text-hover-dark: #e7e7e7; + + --textarea-bg-dark: #000000; + --textarea-border-dark: #666666; +} \ No newline at end of file diff --git a/routes.go b/routes.go index 5dd155b..85ffe0f 100644 --- a/routes.go +++ b/routes.go @@ -7,6 +7,7 @@ import ( "log/slog" "net/http" "os" + "path" "strings" "time" ) @@ -27,7 +28,8 @@ type formatEntries func([]string) []Entry var templateFuncs = map[string]interface{}{ "translatableText": TranslatableText, - "hibiscusVersion": func() string { return "v" + Info.Version }} + "hibiscusVersion": func() string { return "v" + Info.Version }, + "hibiscusTheme": func() string { return path.Clean(Cfg.Theme) }} var editTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFiles("./pages/base.html", "./pages/edit.html")) var viewTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFiles("./pages/base.html", "./pages/entry.html")) var listTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFiles("./pages/base.html", "./pages/list.html"))