diff options
author | Julien Dessaux | 2025-01-30 00:19:16 +0100 |
---|---|---|
committer | Julien Dessaux | 2025-01-30 00:19:16 +0100 |
commit | 98c7d6f5785182117b9fe6ebd6b892f860bc2024 (patch) | |
tree | 261f22399f8f3fce71a2e1c4fc79314c2a8c5efd /pkg/webui | |
parent | fix(webui): fix invalid session cookie handling (diff) | |
download | tfstated-98c7d6f5785182117b9fe6ebd6b892f860bc2024.tar.gz tfstated-98c7d6f5785182117b9fe6ebd6b892f860bc2024.tar.bz2 tfstated-98c7d6f5785182117b9fe6ebd6b892f860bc2024.zip |
feat(webui): bootstrap account settings management with light and dark mode
Diffstat (limited to 'pkg/webui')
-rw-r--r-- | pkg/webui/html/base.html | 6 | ||||
-rw-r--r-- | pkg/webui/html/settings.html | 25 | ||||
-rw-r--r-- | pkg/webui/index.go | 9 | ||||
-rw-r--r-- | pkg/webui/login.go | 7 | ||||
-rw-r--r-- | pkg/webui/routes.go | 2 | ||||
-rw-r--r-- | pkg/webui/settings.go | 53 | ||||
-rw-r--r-- | pkg/webui/state.go | 6 | ||||
-rw-r--r-- | pkg/webui/states.go | 4 | ||||
-rw-r--r-- | pkg/webui/version.go | 8 |
9 files changed, 110 insertions, 10 deletions
diff --git a/pkg/webui/html/base.html b/pkg/webui/html/base.html index c0138ac..4ec6565 100644 --- a/pkg/webui/html/base.html +++ b/pkg/webui/html/base.html @@ -16,6 +16,10 @@ <i>home_storage</i> <span>States</span> </a> +<a href="/settings"{{ if eq .Page.Section "settings" }} class="fill"{{ end}}> + <i>settings</i> + <span>Settings</span> +</a> <a href="/logout"> <i>logout</i> <span>Logout</span> @@ -32,7 +36,7 @@ <link href="https://cdn.jsdelivr.net/npm/beercss@3.8.0/dist/cdn/beer.min.css" rel="stylesheet"> <title>TFSTATED - {{ .Page.Title }}</title> </head> - <body class="dark"> + <body class="{{ if .Page.LightMode }}light{{ else }}dark{{ end }}"> <nav class="left drawer l">{{ template "nav" . }}</nav> <nav class="left m">{{ template "nav" . }}</nav> <nav class="bottom s">{{ template "nav" . }}</nav> diff --git a/pkg/webui/html/settings.html b/pkg/webui/html/settings.html new file mode 100644 index 0000000..4040b9b --- /dev/null +++ b/pkg/webui/html/settings.html @@ -0,0 +1,25 @@ +{{ define "main" }} +<main class="responsive"> + <form action="/settings" method="post"> + <fieldset> + <div class="field middle-align"> + <nav> + <div class="max"> + <h6>Dark Mode</h6> + </div> + <label class="switch icon"> + <input {{ if not .Settings.LightMode }} checked{{ end }} + name="dark-mode" + type="checkbox" + value="1" /> + <span> + <i>dark_mode</i> + </span> + </label> + </nav> + </div> + <button class="small-round" type="submit" value="login">Save</button> + </fieldset> + </form> +</main> +{{ end }} diff --git a/pkg/webui/index.go b/pkg/webui/index.go index 89e5ad6..1168098 100644 --- a/pkg/webui/index.go +++ b/pkg/webui/index.go @@ -3,14 +3,23 @@ package webui import ( "fmt" "net/http" + + "git.adyxax.org/adyxax/tfstated/pkg/model" ) type Page struct { + LightMode bool Precedent string Section string Title string } +func makePage(r *http.Request, page *Page) *Page { + settings := r.Context().Value(model.SettingsContextKey{}).(*model.Settings) + page.LightMode = settings.LightMode + return page +} + func handleIndexGET() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/" { diff --git a/pkg/webui/login.go b/pkg/webui/login.go index 6f688c1..18864b2 100644 --- a/pkg/webui/login.go +++ b/pkg/webui/login.go @@ -2,8 +2,10 @@ package webui import ( "context" + "encoding/json" "fmt" "html/template" + "log/slog" "net/http" "regexp" @@ -113,6 +115,11 @@ func loginMiddleware(db *database.DB, requireSession func(http.Handler) http.Han return } ctx := context.WithValue(r.Context(), model.AccountContextKey{}, account) + var settings model.Settings + if err := json.Unmarshal(account.Settings, &settings); err != nil { + slog.Error("failed to unmarshal account settings", "err", err, "accountId", account.Id) + } + ctx = context.WithValue(ctx, model.SettingsContextKey{}, &settings) next.ServeHTTP(w, r.WithContext(ctx)) })) } diff --git a/pkg/webui/routes.go b/pkg/webui/routes.go index 84017dd..e84f33a 100644 --- a/pkg/webui/routes.go +++ b/pkg/webui/routes.go @@ -16,6 +16,8 @@ func addRoutes( mux.Handle("GET /login", requireSession(handleLoginGET())) mux.Handle("POST /login", requireSession(handleLoginPOST(db))) mux.Handle("GET /logout", requireLogin(handleLogoutGET(db))) + mux.Handle("GET /settings", requireLogin(handleSettingsGET(db))) + mux.Handle("POST /settings", requireLogin(handleSettingsPOST(db))) mux.Handle("GET /states", requireLogin(handleStatesGET(db))) mux.Handle("GET /state/{id}", requireLogin(handleStateGET(db))) mux.Handle("GET /static/", cache(http.FileServer(http.FS(staticFS)))) diff --git a/pkg/webui/settings.go b/pkg/webui/settings.go new file mode 100644 index 0000000..eb0910f --- /dev/null +++ b/pkg/webui/settings.go @@ -0,0 +1,53 @@ +package webui + +import ( + "html/template" + "net/http" + + "git.adyxax.org/adyxax/tfstated/pkg/database" + "git.adyxax.org/adyxax/tfstated/pkg/model" +) + +type SettingsPage struct { + Page *Page + Settings *model.Settings +} + +var settingsTemplates = template.Must(template.ParseFS(htmlFS, "html/base.html", "html/settings.html")) + +func handleSettingsGET(db *database.DB) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + settings := r.Context().Value(model.SettingsContextKey{}).(*model.Settings) + render(w, settingsTemplates, http.StatusOK, SettingsPage{ + Page: makePage(r, &Page{Title: "Settings", Section: "settings"}), + Settings: settings, + }) + }) +} + +func handleSettingsPOST(db *database.DB) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if err := r.ParseForm(); err != nil { + errorResponse(w, http.StatusBadRequest, err) + return + } + darkMode := r.FormValue("dark-mode") + settings := model.Settings{ + LightMode: darkMode != "1", + } + account := r.Context().Value(model.AccountContextKey{}).(*model.Account) + err := db.SaveAccountSettings(account, &settings) + if err != nil { + errorResponse(w, http.StatusInternalServerError, err) + return + } + render(w, settingsTemplates, http.StatusOK, SettingsPage{ + Page: &Page{ + LightMode: settings.LightMode, + Title: "Settings", + Section: "settings", + }, + Settings: &settings, + }) + }) +} diff --git a/pkg/webui/state.go b/pkg/webui/state.go index c7a6aaf..141d2d8 100644 --- a/pkg/webui/state.go +++ b/pkg/webui/state.go @@ -13,7 +13,7 @@ var stateTemplate = template.Must(template.ParseFS(htmlFS, "html/base.html", "ht func handleStateGET(db *database.DB) http.Handler { type StatesData struct { - Page + Page *Page State *model.State Usernames map[int]string Versions []model.Version @@ -41,11 +41,11 @@ func handleStateGET(db *database.DB) http.Handler { return } render(w, stateTemplate, http.StatusOK, StatesData{ - Page: Page{ + Page: makePage(r, &Page{ Precedent: "/states", Section: "states", Title: state.Path, - }, + }), State: state, Usernames: usernames, Versions: versions, diff --git a/pkg/webui/states.go b/pkg/webui/states.go index d99d310..a0d16ca 100644 --- a/pkg/webui/states.go +++ b/pkg/webui/states.go @@ -12,7 +12,7 @@ var statesTemplates = template.Must(template.ParseFS(htmlFS, "html/base.html", " func handleStatesGET(db *database.DB) http.Handler { type StatesData struct { - Page + Page *Page States []model.State } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -22,7 +22,7 @@ func handleStatesGET(db *database.DB) http.Handler { return } render(w, statesTemplates, http.StatusOK, StatesData{ - Page: Page{Title: "States", Section: "states"}, + Page: makePage(r, &Page{Title: "States", Section: "states"}), States: states, }) }) diff --git a/pkg/webui/version.go b/pkg/webui/version.go index 04c3e6d..2aa1422 100644 --- a/pkg/webui/version.go +++ b/pkg/webui/version.go @@ -14,7 +14,7 @@ var versionTemplate = template.Must(template.ParseFS(htmlFS, "html/base.html", " func handleVersionGET(db *database.DB) http.Handler { type VersionsData struct { - Page + Page *Page Account *model.Account State *model.State Version *model.Version @@ -44,11 +44,11 @@ func handleVersionGET(db *database.DB) http.Handler { } versionData := string(version.Data[:]) render(w, versionTemplate, http.StatusOK, VersionsData{ - Page: Page{ + Page: makePage(r, &Page{ Precedent: fmt.Sprintf("/state/%d", state.Id), - Section: "versions", + Section: "states", Title: state.Path, - }, + }), Account: account, State: state, Version: version, |