Add themes

This commit is contained in:
Andrew-71 2024-05-08 13:12:10 +03:00
parent 806822a9a8
commit bfee129443
12 changed files with 139 additions and 25 deletions

View file

@ -1,6 +1,12 @@
# Changelog # Changelog
This file keeps track of changes in more human-readable fashion 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/<name>.css` and modify colours (or, theoretically, do more)
* Current pre-made themes are `default`, `gruvbox` and `high-contrast`
## v0.2.0 ## v0.2.0
* Added config reload * Added config reload
* Can be reloaded in info page * Can be reloaded in info page

View file

@ -48,7 +48,8 @@ password=admin # Your password
port=7101 # What port to run on (probably leave on 7101 if using docker) 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. 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 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_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 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 enable_scram=false # Whether the app should shut down if there are 3 or more failed login attempts within 100 seconds

21
TODO.md
View file

@ -1,21 +1,32 @@
# TODO # TODO
List of things to add to this project List of things to add to this project
## Agenda ## v1.0.0
* a 512x logo so I can enable PWA * a logo so I can enable PWA (and look cool)
* CI/CD pipeline * Themes
* Better docs in case others want to use this for some reason * Theme in config [X]
* Check export function for improvements * 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 ## Brainstorming
Don't expect any of this, these are ideas floating inside my head Don't expect any of this, these are ideas floating inside my head
* Further info page functionality * Further info page functionality
* Edit config * Edit config
* Statistics e.g. mb taken, number of day pages/notes * Statistics e.g. mb taken, number of day pages/notes
* Test telegram link
* Multi-user support through several username-pass keys * Multi-user support through several username-pass keys
* `/data/<user>/...` * `/data/<user>/...`
* This would be an *extremely* breaking change * This would be an *extremely* breaking change
* How to handle exporting *all*? Admin account? * How to handle exporting *all*? Admin account?
* I don't need this, unless Hibiscus.txt somehow gets popular why bother? * I don't need this, unless Hibiscus.txt somehow gets popular why bother?
Is this even a feature that fits the vision? 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 * *Go* dependency-less? <-- this is a terrible idea

View file

@ -22,6 +22,7 @@ type Config struct {
Timezone *time.Location `config:"timezone" type:"location"` Timezone *time.Location `config:"timezone" type:"location"`
GraceTime time.Duration `config:"grace_period" type:"duration"` GraceTime time.Duration `config:"grace_period" type:"duration"`
Language string `config:"language" type:"string"` Language string `config:"language" type:"string"`
Theme string `config:"theme" type:"string"`
LogToFile bool `config:"log_to_file" type:"bool"` LogToFile bool `config:"log_to_file" type:"bool"`
LogFile string `config:"log_file" type:"string"` LogFile string `config:"log_file" type:"string"`
Scram bool `config:"enable_scram" type:"bool"` Scram bool `config:"enable_scram" type:"bool"`
@ -141,6 +142,7 @@ func ConfigInit() Config {
Password: "admin", Password: "admin",
Timezone: time.Local, Timezone: time.Local,
Language: "en", Language: "en",
Theme: "default",
LogFile: "config/log.txt", LogFile: "config/log.txt",
GraceTime: 0, GraceTime: 0,
} }

View file

@ -4,6 +4,7 @@ port=7101
timezone=Local timezone=Local
grace_period=0s grace_period=0s
language=en language=en
theme=default
log_to_file=false log_to_file=false
log_file=config/log.txt log_file=config/log.txt
enable_scram=false enable_scram=false

View file

@ -15,7 +15,7 @@ type HibiscusInfo struct {
// Info contains app information // Info contains app information
var Info = HibiscusInfo{ var Info = HibiscusInfo{
Version: "0.2.0", Version: "0.3.0",
SourceLink: "https://git.a71.su/Andrew71/hibiscus", SourceLink: "https://git.a71.su/Andrew71/hibiscus",
} }

View file

@ -14,6 +14,7 @@
<link rel="manifest" href="/public/manifest.json" /> <link rel="manifest" href="/public/manifest.json" />
<link rel="icon" type="image/x-icon" href="/public/favicon.ico"> <link rel="icon" type="image/x-icon" href="/public/favicon.ico">
<link rel="stylesheet" href="/public/main.css"> <link rel="stylesheet" href="/public/main.css">
<link rel="stylesheet" href="/public/themes/{{ hibiscusTheme }}.css">
<script src="/public/date.js"></script> <script src="/public/date.js"></script>
<title>Hibiscus.txt</title> <title>Hibiscus.txt</title>
</head> </head>

View file

@ -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 { body {
color: #454545; color: var(--text-light);
background-color: #f5f0e1; background-color: var(--bg-light);
margin: 2em auto; margin: 2em auto;
max-width: 640px; max-width: 640px;
padding: 1em; padding: 1em;
@ -11,33 +38,33 @@ body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
a, a:visited { color: #f85552; } a, a:visited { color: var(--clickable-light); }
a:hover, a:visited:hover { color: #e66868; } a:hover, a:visited:hover { color: var(--clickable-hover-light); }
a.no-accent, a.no-accent:visited { color: #454545; } a.no-accent, a.no-accent:visited { color: var(--text-light); }
a.no-accent:hover, a.no-accent:visited:hover { color: #656565; } a.no-accent:hover, a.no-accent:visited:hover { color: var(--text-hover-light); }
h2 { margin-bottom:12px; } h2 { margin-bottom:12px; }
.list-title { margin-bottom: 0} .list-title { margin-bottom: 0}
.list-desc { margin-top: 0 } .list-desc { margin-top: 0 }
textarea, input { textarea, input {
background: #f5f2ee; background: var(--textarea-bg-light);
max-width: 640px; max-width: 640px;
width: 100%; width: 100%;
display: block; display: block;
resize: vertical; resize: vertical;
outline: 0; outline: 0;
box-shadow: none; box-shadow: none;
border: 0.0625em solid #454545; border: 0.0625em solid var(--textarea-border-light);
margin-bottom: 1em; margin-bottom: 1em;
font-size: 18px; font-size: 18px;
} }
input { height: 2.5em; } input { height: 2.5em; }
button { button {
background-color: #f85552; background-color: var(--clickable-light);
border: none; border: none;
color: #f5f2ee; color: var(--clickable-label-light);
padding: 10px; padding: 10px;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
@ -49,7 +76,7 @@ button {
max-width: 640px; max-width: 640px;
width: 100%; width: 100%;
} }
button:hover { background-color: #e66868; } button:hover { background-color: var(--clickable-hover-light); }
footer { margin-top: auto; } footer { margin-top: auto; }
header > h1, header > p { header > h1, header > p {
@ -60,13 +87,23 @@ header > h1, header > p {
/* Dark theme */ /* Dark theme */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
body { body {
color: #f5f0e1; color: var(--text-dark);
background-color: #2c2825; background-color: var(--bg-dark);
} }
textarea, input { textarea, input {
color: #f5f0e1; color: var(--text-dark);
background-color: #383030; 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); }
} }

View file

@ -0,0 +1 @@
/* Default theme is defined in main.css */

26
public/themes/gruvbox.css Normal file
View file

@ -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;
}

View file

@ -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;
}

View file

@ -7,6 +7,7 @@ import (
"log/slog" "log/slog"
"net/http" "net/http"
"os" "os"
"path"
"strings" "strings"
"time" "time"
) )
@ -27,7 +28,8 @@ type formatEntries func([]string) []Entry
var templateFuncs = map[string]interface{}{ var templateFuncs = map[string]interface{}{
"translatableText": TranslatableText, "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 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 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")) var listTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFiles("./pages/base.html", "./pages/list.html"))