diff --git a/README.md b/README.md index ccc1c2a..0a89e07 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# TBA - monochrome status page +

statsys

TODO: thumbnail -

The cutest lightweight monochrome status page

+

The cutest lightweight status page

+

view demo | install

diff --git a/config.toml b/config.toml index 3de316c..67599c8 100644 --- a/config.toml +++ b/config.toml @@ -9,16 +9,24 @@ link_url = "https://trafficlunar.net" # Users can still switch views manually # # Available options: -# 'minutes' - past 30 minutes -# 'hours' - past 24 hours -# 'days' - past 30 days +# "minutes" - past 30 minutes +# "hours" - past 24 hours +# "days" - past 30 days default_view = "hours" +# Default theme for the status page +# Available themes: https://github.com/trafficlunar/statsys/tree/main/www/themes +# Defaults to "monochrome" +default_theme = "color" +# Set to true to allow users to switch the theme +# Defaults to true +enable_theme_switcher = true + # List of services to monitor [[services]] name = "website" url = "http://localhost:9999/up" -# Response time (in milliseconds) after which the service is considered "Degraded" +# Response time (milliseconds) after which the service is marked as "Degraded" # Defaults to 1000ms latency_threshold = 1000 diff --git a/src/config.go b/src/config.go index 73e377e..cecf405 100644 --- a/src/config.go +++ b/src/config.go @@ -14,11 +14,13 @@ type ServiceConfig struct { } type Config struct { - Title string `toml:"title"` - LinkText string `toml:"link_text"` - LinkUrl string `toml:"link_url"` - DefaultView string `toml:"default_view"` - Services []ServiceConfig `toml:"services"` + Title string `toml:"title"` + LinkText string `toml:"link_text"` + LinkUrl string `toml:"link_url"` + DefaultView string `toml:"default_view"` + DefaultTheme string `toml:"default_theme"` + EnableThemeSwitcher bool `toml:"enable_theme_switcher"` + Services []ServiceConfig `toml:"services"` } var config Config @@ -36,6 +38,7 @@ func LoadConfig() { templateData.Title = config.Title templateData.LinkText = config.LinkText templateData.LinkUrl = config.LinkUrl + templateData.EnableThemeSwitcher = config.EnableThemeSwitcher templateData.Services = make([]Service, len(config.Services)) for index, ser := range config.Services { // default to 1000ms diff --git a/src/http.go b/src/http.go index 88b273c..d11239d 100644 --- a/src/http.go +++ b/src/http.go @@ -39,13 +39,15 @@ type Service struct { } type TemplateData struct { - Title string - View string - LinkText string - LinkUrl string - LastUpdated int64 - IsOperational bool - Services []Service + Title string + View string + Theme string + LinkText string + LinkUrl string + EnableThemeSwitcher bool + LastUpdated int64 + IsOperational bool + Services []Service } type ErrorTemplateData struct { @@ -58,7 +60,8 @@ func ToUpper(s string) string { } var templateData = TemplateData{ - LastUpdated: time.Now().UTC().UnixMilli(), + EnableThemeSwitcher: true, + LastUpdated: time.Now().UTC().UnixMilli(), } var tmpl *template.Template var errorTmpl *template.Template @@ -85,6 +88,7 @@ func index(w http.ResponseWriter, req *http.Request) { data := templateData data.View = req.URL.Query().Get("view") + data.Theme = req.URL.Query().Get("theme") switch data.View { case "hours", "minutes", "days": @@ -96,6 +100,10 @@ func index(w http.ResponseWriter, req *http.Request) { return } + if data.Theme == "" { + data.Theme = config.DefaultTheme + } + if err := tmpl.ExecuteTemplate(w, "index.html", data); err != nil { log.Printf("template execute error: %v", err) renderError(w, http.StatusInternalServerError, "Internal server error") @@ -139,6 +147,7 @@ func StartHttpServer() { mux.HandleFunc("/styles.css", styles) mux.HandleFunc("/favicon.ico", favicon) mux.HandleFunc("/robots.txt", robots) + mux.Handle("/themes/", gzhttp.GzipHandler(http.StripPrefix("/themes/", http.FileServer(http.Dir("www/themes/"))))) mux.Handle("/fonts/", http.StripPrefix("/fonts/", http.FileServer(http.Dir("www/fonts/")))) // wrap with gzip middleware diff --git a/www/index.html b/www/index.html index ccb9a99..780c670 100644 --- a/www/index.html +++ b/www/index.html @@ -13,6 +13,7 @@ } main { + position: relative; display: flex; flex-direction: column; width: 100%; @@ -103,7 +104,7 @@ display: flex; flex-direction: column; gap: 2.5rem; - margin-bottom: 4rem; + margin-bottom: 5rem; } .info { @@ -150,7 +151,6 @@ display: flex; justify-content: end; width: 100%; - /* gap: 0.185rem; */ } .bars > div { @@ -169,14 +169,12 @@ transition: transform 100ms ease-in-out; position: relative; z-index: 0; + border-radius: 3px; } .bars > div:hover .status-bar { transform: translateY(-3px); - } - - .bars > div:hover .status-bar.Online { - background-color: rgba(0, 0, 0, 0.7); + filter: brightness(0.9); } .bars > div:hover .status-bar::after { @@ -208,9 +206,9 @@ } .status-bar.Degraded { - background-image: linear-gradient(to bottom, transparent 30%, white 30%), linear-gradient(to right, transparent 40%, white 40%); - background-size: 6px 7px; - background-position: 3px 4px; + background-color: white; + background-image: linear-gradient(45deg, black 25%, transparent 25%, transparent 50%, black 50%, black 75%, transparent 75%, transparent); + background-size: 8px 8px; } .status-bar.Offline { @@ -276,12 +274,12 @@ color: black; } - #combobox { + .combobox { position: relative; width: 8rem; } - #combobox-trigger { + .combobox-trigger { display: flex; justify-content: space-between; align-items: center; @@ -302,24 +300,23 @@ transition: background-color 100ms ease; } - #combobox-trigger:hover { + .combobox-trigger:hover { background-color: rgba(0, 0, 0, 0.03); } - #combobox-trigger div { + .combobox-trigger div { display: flex; justify-content: center; align-items: center; border-left: 1px solid rgba(0, 0, 0, 0.5); } - #combobox-trigger.open div svg { + .combobox-trigger.open div svg { transform: rotate(180deg); } - #combobox-dropdown { + .combobox-dropdown { position: absolute; - bottom: calc(100% + 0.25rem); width: 100%; background-color: white; border: 1px solid black; @@ -327,9 +324,10 @@ flex-direction: column; z-index: 100; border-radius: 4px; + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); } - #combobox-dropdown.open { + .combobox-dropdown.open { display: flex; } @@ -338,6 +336,7 @@ cursor: pointer; color: black; font-size: 0.825rem; + text-decoration: none; } .combobox-option.selected { @@ -435,6 +434,8 @@ } } + +
@@ -443,6 +444,37 @@

status — {{ .Title }}

+ {{ if .EnableThemeSwitcher }} +
+ + + +
+ {{ end }} +
{{ if .IsOperational }} ✔ {{ else }} ✖ {{ end }} @@ -465,7 +497,7 @@ Degraded
-
+
Online
@@ -555,8 +587,8 @@