Improve config and add a theme

This commit is contained in:
Andrew-71 2024-05-08 15:56:11 +03:00
parent bfee129443
commit 7830ae3217
8 changed files with 79 additions and 30 deletions

View file

@ -1,6 +1,16 @@
# 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.4.0
* Customisation changes
* Added `title` option to config
* Controls the text in the header, "🌺 Hibiscus.txt" by default
* Added a nice `lavender` theme :)
* No longer ensuring config.Theme ends up inside `/public`, unsure what to do in that regard
* Technical changes to config
* Now only *some* default values are saved to file when creating initial config.txt
* Spaces in config options are now supported (basically just for `title`)
## v0.3.0 ## v0.3.0
* Added themes * Added themes
* Picked theme is set by `theme` key in config. Default is ...`default` * Picked theme is set by `theme` key in config. Default is ...`default`

View file

@ -39,7 +39,9 @@ config
Deleting notes is done by clearing contents and clicking "Save" - the app deletes empty files when saving. Deleting notes is done by clearing contents and clicking "Save" - the app deletes empty files when saving.
### Config options: ### Config options:
Below are defaults of config.txt. The settings are defined in newline separated key=value pairs. Below are available configuration options and their defaults.
The settings are defined as newline separated key=value pairs in config.txt.
If you do not provide an option in your config, it will be using the default.
Please don't include the bash-style "comments" in your actual config, Please don't include the bash-style "comments" in your actual config,
they are provided purely for demonstration only and **will break the config if present**. they are provided purely for demonstration only and **will break the config if present**.
``` ```

View file

@ -16,13 +16,14 @@ import (
var ConfigFile = "config/config.txt" var ConfigFile = "config/config.txt"
type Config struct { type Config struct {
Username string `config:"username" type:"string"` Username string `config:"username" type:"string" mandatory:"true"`
Password string `config:"password" type:"string"` Password string `config:"password" type:"string" mandatory:"true"`
Port int `config:"port" type:"int"` Port int `config:"port" type:"int" mandatory:"true"`
Timezone *time.Location `config:"timezone" type:"location"` Timezone *time.Location `config:"timezone" type:"location" mandatory:"true"`
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" mandatory:"true"`
Theme string `config:"theme" type:"string"` Theme string `config:"theme" type:"string"`
Title string `config:"title" 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"`
@ -31,15 +32,35 @@ type Config struct {
TelegramChat string `config:"tg_chat" type:"string"` TelegramChat string `config:"tg_chat" type:"string"`
} }
var DefaultConfig = Config{
Username: "admin",
Password: "admin",
Port: 7101,
Timezone: time.Local,
GraceTime: 0,
Language: "en",
Theme: "default",
Title: "🌺 Hibiscus.txt",
LogToFile: false,
LogFile: "config/log.txt",
Scram: false,
TelegramToken: "",
TelegramChat: "",
}
// Save puts modified and mandatory config options into the config.txt file
func (c *Config) Save() error { func (c *Config) Save() error {
output := "" output := ""
v := reflect.ValueOf(*c) v := reflect.ValueOf(*c)
vDefault := reflect.ValueOf(DefaultConfig)
typeOfS := v.Type() typeOfS := v.Type()
for i := 0; i < v.NumField(); i++ { for i := 0; i < v.NumField(); i++ {
key := typeOfS.Field(i).Tag.Get("config") key := typeOfS.Field(i).Tag.Get("config")
value := v.Field(i).Interface() value := v.Field(i).Interface()
if value != "" { mandatory := typeOfS.Field(i).Tag.Get("mandatory")
if (mandatory == "true") || (value != vDefault.Field(i).Interface()) { // Only save non-default values
output += fmt.Sprintf("%s=%v\n", key, value) output += fmt.Sprintf("%s=%v\n", key, value)
} }
} }
@ -70,7 +91,7 @@ func (c *Config) Reload() error {
options := map[string]string{} options := map[string]string{}
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
for scanner.Scan() { for scanner.Scan() {
entry := strings.Split(strings.Replace(scanner.Text(), " ", "", -1), "=") entry := strings.Split(strings.Trim(scanner.Text(), " \t"), "=")
if len(entry) != 2 { if len(entry) != 2 {
continue continue
} }
@ -134,18 +155,8 @@ func (c *Config) Reload() error {
} }
// ConfigInit loads config on startup // ConfigInit loads config on startup
// Some defaults are declared here
func ConfigInit() Config { func ConfigInit() Config {
cfg := Config{ cfg := DefaultConfig
Port: 7101,
Username: "admin",
Password: "admin",
Timezone: time.Local,
Language: "en",
Theme: "default",
LogFile: "config/log.txt",
GraceTime: 0,
}
err := cfg.Reload() err := cfg.Reload()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View file

@ -8,14 +8,14 @@ import (
var infoTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFiles("./pages/base.html", "./pages/info.html")) var infoTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFiles("./pages/base.html", "./pages/info.html"))
type HibiscusInfo struct { type AppInfo struct {
Version string Version string
SourceLink string SourceLink string
} }
// Info contains app information // Info contains app information
var Info = HibiscusInfo{ var Info = AppInfo{
Version: "0.3.0", Version: "0.4.0",
SourceLink: "https://git.a71.su/Andrew71/hibiscus", SourceLink: "https://git.a71.su/Andrew71/hibiscus",
} }

View file

@ -1,6 +1,6 @@
{{define "header"}} {{define "header"}}
<header> <header>
<h1>🌺 Hibiscus.txt</h1> <h1>{{ config.Title }}</h1>
<p>{{translatableText "time.date"}} <span id="today-date">a place</span> <span id="grace" hidden>({{ translatableText "time.grace" }})</span></p> <p>{{translatableText "time.date"}} <span id="today-date">a place</span> <span id="grace" hidden>({{ translatableText "time.grace" }})</span></p>
</header> </header>
{{end}} {{end}}
@ -14,7 +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"> <link rel="stylesheet" href="/public/themes/{{ config.Theme }}.css">
<script src="/public/date.js"></script> <script src="/public/date.js"></script>
<title>Hibiscus.txt</title> <title>Hibiscus.txt</title>
</head> </head>
@ -35,6 +35,6 @@
{{define "footer"}} {{define "footer"}}
<footer> <footer>
<p><a href="/">{{ translatableText "link.today" }}</a> | <a href="/day">{{ translatableText "link.days" }}</a> | <a href="/notes">{{ translatableText "link.notes" }}</a> <p><a href="/">{{ translatableText "link.today" }}</a> | <a href="/day">{{ translatableText "link.days" }}</a> | <a href="/notes">{{ translatableText "link.notes" }}</a>
<span style="float:right;"><a class="no-accent" href="/info" title="{{ translatableText "link.info" }}">{{ hibiscusVersion }}</a></span></p> <span style="float:right;"><a class="no-accent" href="/info" title="{{ translatableText "link.info" }}">v{{ info.Version }}</a></span></p>
</footer> </footer>
{{end}} {{end}}

View file

@ -1,7 +1,7 @@
{{define "main"}} {{define "main"}}
<h2>{{ translatableText "title.info" }}</h2> <h2>{{ translatableText "title.info" }}</h2>
<ul> <ul>
<li>{{ translatableText "info.version" }} - {{ .Version }} (<a href="{{ .SourceLink }}">{{ translatableText "info.version.link" }}</a>)</li> <li>{{ translatableText "info.version" }} - {{ info.Version }} (<a href="{{ .SourceLink }}">{{ translatableText "info.version.link" }}</a>)</li>
<li><a href="/api/export" download="hibiscus">{{ translatableText "info.export" }}</a></li> <li><a href="/api/export" download="hibiscus">{{ translatableText "info.export" }}</a></li>
<li><a href="/readme">{{ translatableText "info.readme" }}</a></li> <li><a href="/readme">{{ translatableText "info.readme" }}</a></li>
<li><a href="/api/reload">{{ translatableText "info.reload" }}</a></li> <li><a href="/api/reload">{{ translatableText "info.reload" }}</a></li>

View file

@ -0,0 +1,26 @@
/* Tell me a secret. */
:root {
/* Light theme */
--text-light: #3c3836;
--bg-light: #e6dffa; /* d4c7fb*/
--clickable-light: #9975f5;
--clickable-hover-light: #765bef;
--clickable-label-light: #e2d8ff;
--text-hover-light: #665c54;
--textarea-bg-light: #f3ecff;
--textarea-border-light: #282828;
/* Dark theme */
--text-dark: #e6dffa;
--bg-dark: #25252a;
--clickable-dark: #9975f5;
--clickable-hover-dark: #765bef;
--clickable-label-dark: #e2d8ff;
--text-hover-dark: #a5a5b9;
--textarea-bg-dark: #27272f;
--textarea-border-dark: #3c3836;
}

View file

@ -7,7 +7,6 @@ import (
"log/slog" "log/slog"
"net/http" "net/http"
"os" "os"
"path"
"strings" "strings"
"time" "time"
) )
@ -28,8 +27,9 @@ 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 }, "info": func() AppInfo { return Info },
"hibiscusTheme": func() string { return path.Clean(Cfg.Theme) }} "config": func() Config { return Cfg },
}
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"))
@ -216,7 +216,7 @@ func PostNote(w http.ResponseWriter, r *http.Request) {
// GetReadme calls GetEntry for readme.txt // GetReadme calls GetEntry for readme.txt
func GetReadme(w http.ResponseWriter, r *http.Request) { func GetReadme(w http.ResponseWriter, r *http.Request) {
GetEntry(w, r, "readme", "readme", true) GetEntry(w, r, "readme.txt", "readme", true)
} }
// PostReadme saves contents of readme.txt file // PostReadme saves contents of readme.txt file