diff --git a/cmd/web/handlers_guestbook.go b/cmd/web/handlers_guestbook.go
index b7adbeb..e137a81 100644
--- a/cmd/web/handlers_guestbook.go
+++ b/cmd/web/handlers_guestbook.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
+	"strconv"
 	"time"
 
 	"git.32bit.cafe/32bitcafe/guestbook/internal/forms"
@@ -23,6 +24,17 @@ func (app *application) getGuestbook(w http.ResponseWriter, r *http.Request) {
 		}
 		return
 	}
+	if !website.Guestbook.Settings.IsVisible {
+		u := app.getCurrentUser(r)
+		if u == nil {
+			app.clientError(w, http.StatusForbidden)
+			return
+		}
+		if u.ID != website.UserId {
+			app.clientError(w, http.StatusForbidden)
+			return
+		}
+	}
 	comments, err := app.guestbookComments.GetAll(website.Guestbook.ID)
 	if err != nil {
 		app.serverError(w, r, err)
@@ -32,6 +44,78 @@ func (app *application) getGuestbook(w http.ResponseWriter, r *http.Request) {
 	views.GuestbookView("Guestbook", data, website, website.Guestbook, comments, forms.CommentCreateForm{}).Render(r.Context(), w)
 }
 
+func (app *application) getGuestbookSettings(w http.ResponseWriter, r *http.Request) {
+	slug := r.PathValue("id")
+	website, err := app.websites.Get(slugToShortId(slug))
+	if err != nil {
+		if errors.Is(err, models.ErrNoRecord) {
+			http.NotFound(w, r)
+		} else {
+			app.serverError(w, r, err)
+		}
+	}
+	data := app.newCommonData(r)
+	views.GuestbookSettingsView(data, website).Render(r.Context(), w)
+}
+
+func (app *application) putGuestbookSettings(w http.ResponseWriter, r *http.Request) {
+	slug := r.PathValue("id")
+	website, err := app.websites.Get(slugToShortId(slug))
+	if err != nil {
+		if errors.Is(err, models.ErrNoRecord) {
+			http.NotFound(w, r)
+		} else {
+			app.serverError(w, r, err)
+		}
+	}
+
+	var form forms.GuestbookSettingsForm
+	err = app.decodePostForm(r, &form)
+	if err != nil {
+		app.clientError(w, http.StatusBadRequest)
+		app.serverError(w, r, err)
+		return
+	}
+	form.CheckField(validator.PermittedValue(form.Visibility, "true", "false"), "gb_visible", "Invalid value")
+	form.CheckField(validator.PermittedValue(form.CommentingEnabled, models.ValidDisableDurations...), "gb_visible", "Invalid value")
+	form.CheckField(validator.PermittedValue(form.WidgetsEnabled, "true", "false"), "gb_remote", "Invalid value")
+	if !form.Valid() {
+		// TODO: rerender template with errors
+		app.clientError(w, http.StatusUnprocessableEntity)
+	}
+
+	c, err := strconv.ParseBool(form.CommentingEnabled)
+	if err != nil {
+		website.Guestbook.Settings.IsCommentingEnabled = false
+		website.Guestbook.Settings.ReenableCommenting, err = app.durationToTime(form.CommentingEnabled)
+		if err != nil {
+			app.serverError(w, r, err)
+		}
+	} else {
+		website.Guestbook.Settings.IsCommentingEnabled = c
+	}
+
+	// can skip error checking for these two since we verify valid values above
+	website.Guestbook.Settings.IsVisible, err = strconv.ParseBool(form.Visibility)
+	if err != nil {
+		app.serverError(w, r, err)
+	}
+	website.Guestbook.Settings.AllowRemoteHostAccess, err = strconv.ParseBool(form.WidgetsEnabled)
+	if err != nil {
+		app.serverError(w, r, err)
+	}
+	err = app.websites.UpdateGuestbookSettings(website.Guestbook.ID, website.Guestbook.Settings)
+	if err != nil {
+		app.serverError(w, r, err)
+		return
+	}
+	app.sessionManager.Put(r.Context(), "flash", "Settings changed successfully")
+	data := app.newCommonData(r)
+	w.Header().Add("HX-Refresh", "true")
+	views.GuestbookSettingsView(data, website).Render(r.Context(), w)
+
+}
+
 func (app *application) getGuestbookComments(w http.ResponseWriter, r *http.Request) {
 	slug := r.PathValue("id")
 	website, err := app.websites.Get(slugToShortId(slug))
@@ -64,7 +148,6 @@ func (app *application) getGuestbookCommentCreate(w http.ResponseWriter, r *http
 		}
 		return
 	}
-
 	data := app.newCommonData(r)
 	form := forms.CommentCreateForm{}
 	views.CreateGuestbookComment("New Comment", data, website, website.Guestbook, form).Render(r.Context(), w)
@@ -82,6 +165,11 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt
 		return
 	}
 
+	if !website.Guestbook.CanComment() {
+		app.clientError(w, http.StatusForbidden)
+		return
+	}
+
 	var form forms.CommentCreateForm
 	err = app.decodePostForm(r, &form)
 	if err != nil {
@@ -98,6 +186,7 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt
 	form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank")
 
 	if !form.Valid() {
+		// TODO: use htmx to avoid getting comments again
 		comments, err := app.guestbookComments.GetAll(website.Guestbook.ID)
 		if err != nil {
 			app.serverError(w, r, err)
diff --git a/cmd/web/handlers_user.go b/cmd/web/handlers_user.go
index 772c8d4..8690065 100644
--- a/cmd/web/handlers_user.go
+++ b/cmd/web/handlers_user.go
@@ -3,6 +3,7 @@ package main
 import (
 	"errors"
 	"net/http"
+	"time"
 
 	"git.32bit.cafe/32bitcafe/guestbook/internal/forms"
 	"git.32bit.cafe/32bitcafe/guestbook/internal/models"
@@ -39,7 +40,8 @@ func (app *application) postUserRegister(w http.ResponseWriter, r *http.Request)
 		return
 	}
 	shortId := app.createShortId()
-	err = app.users.Insert(shortId, form.Name, form.Email, form.Password)
+	settings := DefaultUserSettings()
+	err = app.users.Insert(shortId, form.Name, form.Email, form.Password, settings)
 	if err != nil {
 		if errors.Is(err, models.ErrDuplicateEmail) {
 			form.AddFieldError("email", "Email address is already in use")
@@ -129,3 +131,39 @@ func (app *application) getUser(w http.ResponseWriter, r *http.Request) {
 	data := app.newCommonData(r)
 	views.UserProfile(user.Username, data, user).Render(r.Context(), w)
 }
+
+func (app *application) getUserSettings(w http.ResponseWriter, r *http.Request) {
+	data := app.newCommonData(r)
+	views.UserSettingsView(data, app.timezones).Render(r.Context(), w)
+}
+
+func (app *application) putUserSettings(w http.ResponseWriter, r *http.Request) {
+	user := app.getCurrentUser(r)
+	var form forms.UserSettingsForm
+	err := app.decodePostForm(r, &form)
+	if err != nil {
+		app.clientError(w, http.StatusBadRequest)
+		app.serverError(w, r, err)
+		return
+	}
+	form.CheckField(validator.PermittedValue(form.LocalTimezone, app.timezones...), "timezone", "Invalid value")
+	if !form.Valid() {
+		// TODO: rerender template with errors
+		app.clientError(w, http.StatusUnprocessableEntity)
+	}
+	user.Settings.LocalTimezone, err = time.LoadLocation(form.LocalTimezone)
+	if err != nil {
+		app.serverError(w, r, err)
+		return
+	}
+	err = app.users.UpdateUserSettings(user.ID, user.Settings)
+	if err != nil {
+		app.serverError(w, r, err)
+		return
+	}
+	app.sessionManager.Put(r.Context(), "flash", "Settings changed successfully")
+	data := app.newCommonData(r)
+	w.Header().Add("HX-Refresh", "true")
+	views.UserSettingsView(data, app.timezones).Render(r.Context(), w)
+
+}
diff --git a/cmd/web/handlers_website.go b/cmd/web/handlers_website.go
index 8cb45b8..cb94c72 100644
--- a/cmd/web/handlers_website.go
+++ b/cmd/web/handlers_website.go
@@ -39,25 +39,13 @@ func (app *application) postWebsiteCreate(w http.ResponseWriter, r *http.Request
 		views.WebsiteCreate("Add a Website", data, form).Render(r.Context(), w)
 	}
 	websiteShortID := app.createShortId()
-	websiteId, err := app.websites.Insert(websiteShortID, userId, form.Name, form.SiteUrl, form.AuthorName)
-	if err != nil {
-		app.serverError(w, r, err)
-		return
-	}
-	// TODO: how to handle website creation success but guestbook creation failure?
-	guestbookShortID := app.createShortId()
-	_, err = app.guestbooks.Insert(guestbookShortID, userId, websiteId)
+	_, err = app.websites.Insert(websiteShortID, userId, form.Name, form.SiteUrl, form.AuthorName)
 	if err != nil {
 		app.serverError(w, r, err)
 		return
 	}
 	app.sessionManager.Put(r.Context(), "flash", "Website successfully registered!")
-	if r.Header.Get("HX-Request") == "true" {
-		w.Header().Add("HX-Trigger", "newWebsite")
-		views.WebsiteCreateButton().Render(r.Context(), w)
-		return
-	}
-	http.Redirect(w, r, fmt.Sprintf("/websites/%s", shortIdToSlug(websiteShortID)), http.StatusSeeOther)
+	http.Redirect(w, r, fmt.Sprintf("/websites/%s/dashboard", shortIdToSlug(websiteShortID)), http.StatusSeeOther)
 }
 
 func (app *application) getWebsiteDashboard(w http.ResponseWriter, r *http.Request) {
@@ -88,7 +76,8 @@ func (app *application) getWebsiteList(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	if r.Header.Get("HX-Request") == "true" {
-		w.Header().Add("HX-Trigger", "newWebsite")
+		views.HxWebsiteList(websites)
+		return
 	}
 	data := app.newCommonData(r)
 	views.WebsiteList("My Websites", data, websites).Render(r.Context(), w)
diff --git a/cmd/web/helpers.go b/cmd/web/helpers.go
index ca0dfdd..7d927d1 100644
--- a/cmd/web/helpers.go
+++ b/cmd/web/helpers.go
@@ -23,8 +23,7 @@ func (app *application) serverError(w http.ResponseWriter, r *http.Request, err
 
 	app.logger.Error(err.Error(), "method", method, "uri", uri)
 	if app.debug {
-		http.Error(w, string(debug.Stack()), http.StatusInternalServerError)
-		app.logger.Error(err.Error(), "method", method, "uri", uri, "stack", string(debug.Stack()))
+		http.Error(w, err.Error()+"\n"+string(debug.Stack()), http.StatusInternalServerError)
 	}
 	http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
 }
@@ -112,3 +111,19 @@ func (app *application) newCommonData(r *http.Request) views.CommonData {
 		IsHtmx:          r.Header.Get("Hx-Request") == "true",
 	}
 }
+
+func DefaultUserSettings() models.UserSettings {
+	return models.UserSettings{
+		LocalTimezone: time.Now().UTC().Location(),
+	}
+}
+
+func (app *application) durationToTime(duration string) (time.Time, error) {
+	var result time.Time
+	offset, err := time.ParseDuration(duration)
+	if err != nil {
+		return result, nil
+	}
+	result = time.Now().UTC().Add(offset)
+	return result, nil
+}
diff --git a/cmd/web/main.go b/cmd/web/main.go
index e1a2bec..ba9115c 100644
--- a/cmd/web/main.go
+++ b/cmd/web/main.go
@@ -7,7 +7,9 @@ import (
 	"log/slog"
 	"net/http"
 	"os"
+	"strings"
 	"time"
+	"unicode"
 
 	"git.32bit.cafe/32bitcafe/guestbook/internal/models"
 	"github.com/alexedwards/scs/sqlite3store"
@@ -20,12 +22,12 @@ type application struct {
 	sequence          uint16
 	logger            *slog.Logger
 	websites          *models.WebsiteModel
-	guestbooks        *models.GuestbookModel
 	users             *models.UserModel
 	guestbookComments *models.GuestbookCommentModel
 	sessionManager    *scs.SessionManager
 	formDecoder       *schema.Decoder
 	debug             bool
+	timezones         []string
 }
 
 func main() {
@@ -55,11 +57,22 @@ func main() {
 		logger:            logger,
 		sessionManager:    sessionManager,
 		websites:          &models.WebsiteModel{DB: db},
-		guestbooks:        &models.GuestbookModel{DB: db},
-		users:             &models.UserModel{DB: db},
+		users:             &models.UserModel{DB: db, Settings: make(map[string]models.Setting)},
 		guestbookComments: &models.GuestbookCommentModel{DB: db},
 		formDecoder:       formDecoder,
 		debug:             *debug,
+		timezones:         getAvailableTimezones(),
+	}
+
+	err = app.users.InitializeSettingsMap()
+	if err != nil {
+		logger.Error(err.Error())
+		os.Exit(1)
+	}
+	err = app.websites.InitializeSettingsMap()
+	if err != nil {
+		logger.Error(err.Error())
+		os.Exit(1)
 	}
 
 	tlsConfig := &tls.Config{
@@ -97,3 +110,50 @@ func openDB(dsn string) (*sql.DB, error) {
 	}
 	return db, nil
 }
+
+func getAvailableTimezones() []string {
+	var zones []string
+	var zoneDirs = []string{
+		"/usr/share/zoneinfo/",
+		"/usr/share/lib/zoneinfo/",
+		"/usr/lib/locale/TZ/",
+	}
+	for _, zd := range zoneDirs {
+		zones = walkTzDir(zd, zones)
+		for idx, zone := range zones {
+			zones[idx] = strings.ReplaceAll(zone, zd+"/", "")
+		}
+	}
+	return zones
+}
+
+func walkTzDir(path string, zones []string) []string {
+	fileInfos, err := os.ReadDir(path)
+	if err != nil {
+		return zones
+	}
+	isAlpha := func(s string) bool {
+		for _, r := range s {
+			if !unicode.IsLetter(r) {
+				return false
+			}
+		}
+		return true
+	}
+	for _, info := range fileInfos {
+		if info.Name() != strings.ToUpper(info.Name()[:1])+info.Name()[1:] {
+			continue
+		}
+		if !isAlpha(info.Name()[:1]) {
+			continue
+		}
+		newPath := path + "/" + info.Name()
+		if info.IsDir() {
+			zones = walkTzDir(newPath, zones)
+		} else {
+			zones = append(zones, newPath)
+		}
+	}
+	return zones
+
+}
diff --git a/cmd/web/routes.go b/cmd/web/routes.go
index cc5b6b5..c2fe48a 100644
--- a/cmd/web/routes.go
+++ b/cmd/web/routes.go
@@ -28,7 +28,8 @@ func (app *application) routes() http.Handler {
 	// mux.Handle("GET /users", protected.ThenFunc(app.getUsersList))
 	mux.Handle("GET /users/{id}", protected.ThenFunc(app.getUser))
 	mux.Handle("POST /users/logout", protected.ThenFunc(app.postUserLogout))
-	mux.Handle("GET /users/settings", protected.ThenFunc(app.notImplemented))
+	mux.Handle("GET /users/settings", protected.ThenFunc(app.getUserSettings))
+	mux.Handle("PUT /users/settings", protected.ThenFunc(app.putUserSettings))
 	mux.Handle("GET /users/privacy", protected.ThenFunc(app.notImplemented))
 	mux.Handle("GET /guestbooks", protected.ThenFunc(app.getAllGuestbooks))
 
@@ -40,7 +41,8 @@ func (app *application) routes() http.Handler {
 	mux.Handle("GET /websites/{id}/dashboard/guestbook/comments/queue", protected.ThenFunc(app.getCommentQueue))
 	mux.Handle("DELETE /websites/{id}/dashboard/guestbook/comments/{commentId}", protected.ThenFunc(app.deleteGuestbookComment))
 	mux.Handle("PUT /websites/{id}/dashboard/guestbook/comments/{commentId}", protected.ThenFunc(app.putHideGuestbookComment))
-	mux.Handle("GET /websites/{id}/dashboard/guestbook/blocklist", protected.ThenFunc(app.getComingSoon))
+	mux.Handle("GET /websites/{id}/dashboard/guestbook/settings", protected.ThenFunc(app.getGuestbookSettings))
+	mux.Handle("PUT /websites/{id}/dashboard/guestbook/settings", protected.ThenFunc(app.putGuestbookSettings))
 	mux.Handle("GET /websites/{id}/dashboard/guestbook/comments/trash", protected.ThenFunc(app.getCommentTrash))
 	mux.Handle("GET /websites/{id}/dashboard/guestbook/themes", protected.ThenFunc(app.getComingSoon))
 	mux.Handle("GET /websites/{id}/dashboard/guestbook/customize", protected.ThenFunc(app.getComingSoon))
diff --git a/db/create-settings-tables.sql b/db/create-settings-tables.sql
new file mode 100644
index 0000000..4708887
--- /dev/null
+++ b/db/create-settings-tables.sql
@@ -0,0 +1,76 @@
+CREATE TABLE setting_groups (
+    Id integer primary key autoincrement,
+    Description varchar(256) NOT NULL
+);
+
+CREATE TABLE setting_data_types (
+    Id integer primary key autoincrement,
+    Description varchar(64) NOT NULL
+);
+
+CREATE TABLE settings (
+    Id integer primary key autoincrement,
+    Description varchar(256) NOT NULL,
+    Constrained boolean NOT NULL,
+    DataType integer NOT NULL,
+    SettingGroup int NOT NULL,
+    MinValue varchar(6),
+    MaxValue varchar(6),
+    FOREIGN KEY (DataType) REFERENCES setting_data_types(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT,
+    FOREIGN KEY (SettingGroup) REFERENCES setting_groups(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT
+);
+
+CREATE TABLE allowed_setting_values (
+    Id integer primary key autoincrement,
+    SettingId integer NOT NULL,
+    ItemValue varchar(256),
+    Caption varchar(256),
+    FOREIGN KEY (SettingId) REFERENCES settings(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT
+);
+
+CREATE TABLE user_settings (
+    Id integer primary key autoincrement,
+    UserId integer NOT NULL,
+    SettingId integer NOT NULL,
+    AllowedSettingValueId integer,
+    UnconstrainedValue varchar(256),
+    FOREIGN KEY (UserId) REFERENCES users(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT,
+    FOREIGN KEY (SettingId) REFERENCES settings(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT,
+    FOREIGN KEY (AllowedSettingValueId) REFERENCES allowed_setting_values(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT
+);
+
+CREATE TABLE guestbook_settings (
+    Id integer primary key autoincrement,
+    GuestbookId integer NOT NULL,
+    SettingId integer NOT NULL,
+    AllowedSettingValueId integer,
+    UnconstrainedValue varchar(256),
+    FOREIGN KEY (GuestbookId) REFERENCES guestbooks(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT,
+    FOREIGN KEY (SettingId) REFERENCES settings(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT,
+    FOREIGN KEY (AllowedSettingValueId) REFERENCES allowed_setting_values(Id)
+        ON DELETE RESTRICT
+        ON UPDATE RESTRICT
+);
+
+INSERT INTO setting_groups (Description) VALUES ('guestbook');
+INSERT INTO setting_groups (Description) VALUES ('user');
+
+INSERT INTO setting_data_types (Description) VALUES ('alphanumeric');
+INSERT INTO setting_data_types (Description) VALUES ('integer');
+INSERT INTO setting_data_types (Description) VALUES ('datetime');
diff --git a/db/create-settings.sql b/db/create-settings.sql
new file mode 100644
index 0000000..87ee494
--- /dev/null
+++ b/db/create-settings.sql
@@ -0,0 +1,9 @@
+INSERT INTO setting_groups (Description) VALUES ("guestbook");
+INSERT INTO setting_groups (Description) VALUES ("user");
+
+INSERT INTO setting_data_types (Description) VALUES ("alphanumeric")
+INSERT INTO setting_data_types (Description) VALUES ("integer")
+INSERT INTO setting_data_types (Description) VALUES ("datetime")
+
+INSERT INTO settings (Description, Constrained, DataType, SettingGroup)
+VALUES ("Local Timezone", 0, 1, 1);
diff --git a/internal/forms/forms.go b/internal/forms/forms.go
index 8d5664f..2014c84 100644
--- a/internal/forms/forms.go
+++ b/internal/forms/forms.go
@@ -29,3 +29,15 @@ type WebsiteCreateForm struct {
 	AuthorName          string `schema:"authorname"`
 	validator.Validator `schema:"-"`
 }
+
+type UserSettingsForm struct {
+	LocalTimezone       string `schema:"timezones"`
+	validator.Validator `schema:"-"`
+}
+
+type GuestbookSettingsForm struct {
+	Visibility          string `schema:"gb_visible"`
+	CommentingEnabled   string `schema:"gb_commenting"`
+	WidgetsEnabled      string `schema:"gb_remote"`
+	validator.Validator `schema:"-"`
+}
diff --git a/internal/models/errors.go b/internal/models/errors.go
index 48a3033..2b02a0b 100644
--- a/internal/models/errors.go
+++ b/internal/models/errors.go
@@ -3,9 +3,11 @@ package models
 import "errors"
 
 var (
-    ErrNoRecord = errors.New("models: no matching record found")
+	ErrNoRecord = errors.New("models: no matching record found")
 
-    ErrInvalidCredentials = errors.New("models: invalid credentials")
+	ErrInvalidCredentials = errors.New("models: invalid credentials")
 
-    ErrDuplicateEmail = errors.New("models: duplicate email")
+	ErrDuplicateEmail = errors.New("models: duplicate email")
+
+	ErrInvalidSettingValue = errors.New("models: invalid setting value")
 )
diff --git a/internal/models/guestbook.go b/internal/models/guestbook.go
deleted file mode 100644
index 21d899e..0000000
--- a/internal/models/guestbook.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package models
-
-import (
-	"database/sql"
-	"time"
-)
-
-type Guestbook struct {
-	ID        int64
-	ShortId   uint64
-	UserId    int64
-	WebsiteId int64
-	Created   time.Time
-	Deleted   time.Time
-	IsActive  bool
-}
-
-type GuestbookModel struct {
-	DB *sql.DB
-}
-
-func (m *GuestbookModel) Insert(shortId uint64, userId int64, websiteId int64) (int64, error) {
-	stmt := `INSERT INTO guestbooks (ShortId, UserId, WebsiteId, Created, IsActive)
-    VALUES(?, ?, ?, ?, TRUE)`
-	result, err := m.DB.Exec(stmt, shortId, userId, websiteId, time.Now().UTC())
-	if err != nil {
-		return -1, err
-	}
-	id, err := result.LastInsertId()
-	if err != nil {
-		return -1, err
-	}
-	return id, nil
-}
-
-func (m *GuestbookModel) Get(shortId uint64) (Guestbook, error) {
-	stmt := `SELECT Id, ShortId, UserId, WebsiteId, Created, Deleted, IsActive FROM guestbooks
-    WHERE ShortId = ?`
-	row := m.DB.QueryRow(stmt, shortId)
-	var g Guestbook
-	var t sql.NullTime
-	err := row.Scan(&g.ID, &g.ShortId, &g.UserId, &g.WebsiteId, &g.Created, &t, &g.IsActive)
-	if err != nil {
-		return Guestbook{}, err
-	}
-	if t.Valid {
-		g.Deleted = t.Time
-	}
-	return g, nil
-}
-
-func (m *GuestbookModel) GetAll(userId int64) ([]Guestbook, error) {
-	stmt := `SELECT Id, ShortId, UserId, WebsiteId, Created, IsActive FROM guestbooks
-    WHERE UserId = ? AND DELETED IS NULL`
-	rows, err := m.DB.Query(stmt, userId)
-	if err != nil {
-		return nil, err
-	}
-	var guestbooks []Guestbook
-	for rows.Next() {
-		var g Guestbook
-		err = rows.Scan(&g.ID, &g.ShortId, &g.UserId, &g.WebsiteId, &g.Created, &g.IsActive)
-		if err != nil {
-			return nil, err
-		}
-		guestbooks = append(guestbooks, g)
-	}
-	if err = rows.Err(); err != nil {
-		return nil, err
-	}
-	return guestbooks, nil
-}
diff --git a/internal/models/settings.go b/internal/models/settings.go
new file mode 100644
index 0000000..9ae8259
--- /dev/null
+++ b/internal/models/settings.go
@@ -0,0 +1,154 @@
+package models
+
+import (
+	"strconv"
+	"time"
+)
+
+type SettingGroup struct {
+	id          int
+	description string
+}
+
+func (g *SettingGroup) Id() int {
+	return g.id
+}
+
+func (g *SettingGroup) Description() string {
+	return g.description
+}
+
+const (
+	SETTING_GROUP_USER      = "user"
+	SETTING_GROUP_GUESTBOOK = "guestbook"
+)
+
+type SettingDataType struct {
+	id          int
+	description string
+}
+
+func (d *SettingDataType) Id() int {
+	return d.id
+}
+
+func (d *SettingDataType) Description() string {
+	return d.description
+}
+
+const (
+	SETTING_TYPE_INTEGER = "integer"
+	SETTING_TYPE_STRING  = "alphanumeric"
+	SETTING_TYPE_DATE    = "datetime"
+)
+
+type Setting struct {
+	id           int
+	description  string
+	constrained  bool
+	dataType     SettingDataType
+	settingGroup SettingGroup
+	minValue     string
+	maxValue     string
+}
+
+func (s *Setting) Id() int {
+	return s.id
+}
+
+func (s *Setting) Description() string {
+	return s.description
+}
+
+func (s *Setting) Constrained() bool {
+	return s.constrained
+}
+
+func (s *Setting) DataType() SettingDataType {
+	return s.dataType
+}
+
+func (s *Setting) SettingGroup() SettingGroup {
+	return s.settingGroup
+}
+
+func (s *Setting) MinValue() string {
+	return s.minValue
+}
+
+func (s *Setting) MaxValue() string {
+	return s.maxValue
+}
+
+func (s *Setting) Validate(value string) bool {
+	switch s.dataType.description {
+	case SETTING_TYPE_INTEGER:
+		return s.validateInt(value)
+	case SETTING_TYPE_STRING:
+		return s.validateAlphanum(value)
+	case SETTING_TYPE_DATE:
+		return s.validateDatetime(value)
+	}
+	return false
+}
+
+func (s *Setting) validateInt(value string) bool {
+	v, err := strconv.ParseInt(value, 10, 0)
+	if err != nil {
+		return false
+	}
+	var min int64
+	var max int64
+	if len(s.minValue) > 0 {
+		min, err = strconv.ParseInt(s.minValue, 10, 0)
+		if err != nil {
+			return false
+		}
+		if v < min {
+			return false
+		}
+	}
+	if len(s.maxValue) > 0 {
+		max, err = strconv.ParseInt(s.maxValue, 10, 0)
+		if err != nil {
+			return false
+		}
+		if v < max {
+			return false
+		}
+	}
+	return true
+}
+
+func (s *Setting) validateDatetime(value string) bool {
+	v, err := time.Parse(time.RFC3339, value)
+	if err != nil {
+		return false
+	}
+	var min time.Time
+	var max time.Time
+
+	if len(s.minValue) > 0 {
+		min, err = time.Parse(time.RFC3339, s.minValue)
+		if err != nil {
+			return false
+		}
+		if v.Before(min) {
+			return false
+		}
+	}
+	if len(s.maxValue) > 0 {
+		max, err = time.Parse(time.RFC3339, s.maxValue)
+		if err != nil {
+			return false
+		}
+		if v.After(max) {
+			return false
+		}
+	}
+	return false
+}
+
+func (s *Setting) validateAlphanum(value string) bool {
+	return len(value) >= 0
+}
diff --git a/internal/models/user.go b/internal/models/user.go
index e4dfbe2..318202d 100644
--- a/internal/models/user.go
+++ b/internal/models/user.go
@@ -10,6 +10,14 @@ import (
 	"golang.org/x/crypto/bcrypt"
 )
 
+type UserSettings struct {
+	LocalTimezone *time.Location
+}
+
+const (
+	SettingUserTimezone = "local_timezone"
+)
+
 type User struct {
 	ID             int64
 	ShortId        uint64
@@ -19,20 +27,54 @@ type User struct {
 	IsBanned       bool
 	HashedPassword []byte
 	Created        time.Time
+	Settings       UserSettings
 }
 
 type UserModel struct {
-	DB *sql.DB
+	DB       *sql.DB
+	Settings map[string]Setting
 }
 
-func (m *UserModel) Insert(shortId uint64, username string, email string, password string) error {
+func (m *UserModel) InitializeSettingsMap() error {
+	if m.Settings == nil {
+		m.Settings = make(map[string]Setting)
+	}
+	stmt := `SELECT settings.Id, settings.Description, Constrained, d.Id, d.Description, g.Id, g.Description, MinValue, MaxValue
+        FROM settings
+        LEFT JOIN setting_data_types d ON settings.DataType = d.Id
+        LEFT JOIN setting_groups g ON settings.SettingGroup = g.Id
+        WHERE SettingGroup = (SELECT Id FROM setting_groups WHERE Description = 'user' LIMIT 1)`
+	result, err := m.DB.Query(stmt)
+	if err != nil {
+		return err
+	}
+	for result.Next() {
+		var s Setting
+		var mn sql.NullString
+		var mx sql.NullString
+		err := result.Scan(&s.id, &s.description, &s.constrained, &s.dataType.id, &s.dataType.description, &s.settingGroup.id, &s.settingGroup.description, &mn, &mx)
+		if mn.Valid {
+			s.minValue = mn.String
+		}
+		if mx.Valid {
+			s.maxValue = mx.String
+		}
+		if err != nil {
+			return err
+		}
+		m.Settings[s.description] = s
+	}
+	return nil
+}
+
+func (m *UserModel) Insert(shortId uint64, username string, email string, password string, settings UserSettings) error {
 	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 12)
 	if err != nil {
 		return err
 	}
 	stmt := `INSERT INTO users (ShortId, Username, Email, IsBanned, HashedPassword, Created)
     VALUES (?, ?, ?, FALSE, ?, ?)`
-	_, err = m.DB.Exec(stmt, shortId, username, email, hashedPassword, time.Now().UTC())
+	result, err := m.DB.Exec(stmt, shortId, username, email, hashedPassword, time.Now().UTC())
 	if err != nil {
 		if sqliteError, ok := err.(sqlite3.Error); ok {
 			if sqliteError.ExtendedCode == 2067 && strings.Contains(sqliteError.Error(), "Email") {
@@ -41,6 +83,14 @@ func (m *UserModel) Insert(shortId uint64, username string, email string, passwo
 		}
 		return err
 	}
+	id, err := result.LastInsertId()
+	if err != nil {
+		return err
+	}
+	err = m.initializeUserSettings(id, settings)
+	if err != nil {
+		return err
+	}
 	return nil
 }
 
@@ -55,6 +105,11 @@ func (m *UserModel) Get(id uint64) (User, error) {
 		}
 		return User{}, err
 	}
+	settings, err := m.GetSettings(u.ID)
+	if err != nil {
+		return u, err
+	}
+	u.Settings = settings
 	return u, nil
 }
 
@@ -69,6 +124,11 @@ func (m *UserModel) GetById(id int64) (User, error) {
 		}
 		return User{}, err
 	}
+	settings, err := m.GetSettings(u.ID)
+	if err != nil {
+		return u, err
+	}
+	u.Settings = settings
 	return u, nil
 }
 
@@ -125,3 +185,75 @@ func (m *UserModel) Exists(id int64) (bool, error) {
 	err := m.DB.QueryRow(stmt, id).Scan(&exists)
 	return exists, err
 }
+
+func (m *UserModel) GetSettings(userId int64) (UserSettings, error) {
+	stmt := `SELECT u.SettingId, a.ItemValue, u.UnconstrainedValue FROM user_settings AS u
+			LEFT JOIN allowed_setting_values AS a ON u.AllowedSettingValueId = a.Id
+			WHERE UserId = ?`
+	var settings UserSettings
+	rows, err := m.DB.Query(stmt, userId)
+	if err != nil {
+		return settings, err
+	}
+	for rows.Next() {
+		var id int
+		var itemValue sql.NullString
+		var unconstrainedValue sql.NullString
+		err = rows.Scan(&id, &itemValue, &unconstrainedValue)
+		if err != nil {
+			return settings, err
+		}
+		switch id {
+		case m.Settings[SettingUserTimezone].id:
+			settings.LocalTimezone, err = time.LoadLocation(unconstrainedValue.String)
+			if err != nil {
+				panic(err)
+			}
+		}
+	}
+	return settings, err
+}
+
+func (m *UserModel) initializeUserSettings(userId int64, settings UserSettings) error {
+	stmt := `INSERT INTO user_settings (UserId, SettingId, AllowedSettingValueId, UnconstrainedValue) 
+		VALUES (?, ?, ?, ?)`
+	_, err := m.DB.Exec(stmt, userId, m.Settings[SettingUserTimezone].id, nil, settings.LocalTimezone.String())
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m *UserModel) UpdateUserSettings(userId int64, settings UserSettings) error {
+	err := m.UpdateSetting(userId, m.Settings[SettingUserTimezone], settings.LocalTimezone.String())
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m *UserModel) UpdateSetting(userId int64, setting Setting, value string) error {
+	valid := setting.Validate(value)
+	if !valid {
+		return ErrInvalidSettingValue
+	}
+	stmt := `UPDATE user_settings SET
+				AllowedSettingValueId=IFNULL(
+					(SELECT Id FROM allowed_setting_values WHERE SettingId = user_settings.SettingId AND ItemValue = ?), AllowedSettingValueId
+				),
+				UnconstrainedValue=(SELECT ? FROM settings WHERE settings.Id = user_settings.SettingId AND settings.Constrained=0)
+			WHERE userId = ?
+			AND SettingId = (SELECT Id from Settings WHERE Description=?);`
+	result, err := m.DB.Exec(stmt, value, value, userId, setting.description)
+	if err != nil {
+		return err
+	}
+	rows, err := result.RowsAffected()
+	if err != nil {
+		return err
+	}
+	if rows != 1 {
+		return ErrInvalidSettingValue
+	}
+	return nil
+}
diff --git a/internal/models/website.go b/internal/models/website.go
index 4142697..456c92d 100644
--- a/internal/models/website.go
+++ b/internal/models/website.go
@@ -2,6 +2,8 @@ package models
 
 import (
 	"database/sql"
+	"errors"
+	"strconv"
 	"time"
 )
 
@@ -17,51 +19,206 @@ type Website struct {
 	Guestbook  Guestbook
 }
 
+type GuestbookSettings struct {
+	IsCommentingEnabled   bool
+	ReenableCommenting    time.Time
+	IsVisible             bool
+	FilteredWords         []string
+	AllowRemoteHostAccess bool
+}
+
+var ValidDisableDurations = []string{"true", "false", "1h", "4h", "8h", "24h", "72h", "168h"}
+
+const (
+	SettingGbCommentingEnabled = "commenting_enabled"
+	SettingGbReenableComments  = "reenable_comments"
+	SettingGbVisible           = "is_visible"
+	SettingGbFilteredWords     = "filtered_words"
+	SettingGbAllowRemote       = "remote_enabled"
+)
+
+type Guestbook struct {
+	ID        int64
+	ShortId   uint64
+	UserId    int64
+	WebsiteId int64
+	Created   time.Time
+	Deleted   time.Time
+	IsActive  bool
+	Settings  GuestbookSettings
+}
+
+func (g Guestbook) CanComment() bool {
+	now := time.Now().UTC()
+	return g.Settings.IsCommentingEnabled && g.Settings.ReenableCommenting.Before(now)
+}
+
 type WebsiteModel struct {
-	DB *sql.DB
+	DB       *sql.DB
+	Settings map[string]Setting
+}
+
+func (m *WebsiteModel) InitializeSettingsMap() error {
+	if m.Settings == nil {
+		m.Settings = make(map[string]Setting)
+	}
+	stmt := `SELECT settings.Id, settings.Description, Constrained, d.Id, d.Description, g.Id, g.Description, MinValue, MaxValue
+        FROM settings
+        LEFT JOIN setting_data_types d ON settings.DataType = d.Id
+        LEFT JOIN setting_groups g ON settings.SettingGroup = g.Id
+        WHERE SettingGroup = (SELECT Id FROM setting_groups WHERE Description = 'guestbook' LIMIT 1)`
+	result, err := m.DB.Query(stmt)
+	if err != nil {
+		return err
+	}
+	for result.Next() {
+		var s Setting
+		var mn sql.NullString
+		var mx sql.NullString
+		err := result.Scan(&s.id, &s.description, &s.constrained, &s.dataType.id, &s.dataType.description, &s.settingGroup.id, &s.settingGroup.description, &mn, &mx)
+		if mn.Valid {
+			s.minValue = mn.String
+		}
+		if mx.Valid {
+			s.maxValue = mx.String
+		}
+		if err != nil {
+			return err
+		}
+		m.Settings[s.description] = s
+	}
+	return nil
 }
 
 func (m *WebsiteModel) Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error) {
 	stmt := `INSERT INTO websites (ShortId, Name, SiteUrl, AuthorName, UserId, Created)
 			VALUES (?, ?, ?, ?, ?, ?)`
-	result, err := m.DB.Exec(stmt, shortId, siteName, siteUrl, authorName, userId, time.Now().UTC())
+	tx, err := m.DB.Begin()
 	if err != nil {
 		return -1, err
 	}
-	id, err := result.LastInsertId()
+
+	result, err := tx.Exec(stmt, shortId, siteName, siteUrl, authorName, userId, time.Now().UTC())
+	// result, err := m.DB.Exec(stmt, shortId, siteName, siteUrl, authorName, userId, time.Now().UTC())
 	if err != nil {
+		if rollbackError := tx.Rollback(); rollbackError != nil {
+			return -1, err
+		}
 		return -1, err
 	}
-	return id, nil
+	websiteId, err := result.LastInsertId()
+	if err != nil {
+		if rollbackError := tx.Rollback(); rollbackError != nil {
+			return -1, err
+		}
+		return -1, err
+	}
+
+	stmt = `INSERT INTO guestbooks (ShortId, UserId, WebsiteId, Created, IsActive)
+    VALUES(?, ?, ?, ?, TRUE)`
+	result, err = tx.Exec(stmt, shortId, userId, websiteId, time.Now().UTC())
+	if err != nil {
+		if rollbackError := tx.Rollback(); rollbackError != nil {
+			return -1, err
+		}
+		return -1, err
+	}
+	guestbookId, err := result.LastInsertId()
+	if err != nil {
+		if rollbackError := tx.Rollback(); rollbackError != nil {
+			return -1, err
+		}
+		return -1, err
+	}
+
+	settings := GuestbookSettings{
+		IsCommentingEnabled:   true,
+		IsVisible:             true,
+		AllowRemoteHostAccess: true,
+	}
+	stmt = `INSERT INTO guestbook_settings (GuestbookId, SettingId, AllowedSettingValueId, UnconstrainedValue) VALUES 
+	(?, ?, ?, ?),
+	(?, ?, ?, ?),
+	(?, ?, ?, ?),
+	(?, ?, ?, ?)`
+	_, err = tx.Exec(stmt,
+		guestbookId, m.Settings[SettingGbCommentingEnabled].id, settings.IsCommentingEnabled, nil,
+		guestbookId, m.Settings[SettingGbReenableComments].id, nil, settings.ReenableCommenting.Format(time.RFC3339),
+		guestbookId, m.Settings[SettingGbVisible].id, settings.IsVisible, nil,
+		guestbookId, m.Settings[SettingGbAllowRemote].id, settings.AllowRemoteHostAccess, nil)
+	if err != nil {
+		if rollbackError := tx.Rollback(); rollbackError != nil {
+			return -1, err
+		}
+		return -1, err
+	}
+
+	if err := tx.Commit(); err != nil {
+		return -1, err
+	}
+	return websiteId, nil
 }
 
 func (m *WebsiteModel) Get(shortId uint64) (Website, error) {
-	stmt := `SELECT w.Id, w.ShortId, w.Name, w.SiteUrl, w.AuthorName, w.UserId, w.Created,
-	g.Id, g.ShortId, g.Created, g.IsActive
-	FROM websites AS w INNER JOIN guestbooks AS g ON w.Id = g.WebsiteId
+	stmt := `SELECT w.Id, w.ShortId, w.Name, w.SiteUrl, w.AuthorName, w.UserId, w.Created
+	FROM websites AS w
 	WHERE w.ShortId = ? AND w.DELETED IS NULL`
-	row := m.DB.QueryRow(stmt, shortId)
-	var w Website
-	err := row.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created,
-		&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive)
+	tx, err := m.DB.Begin()
 	if err != nil {
+		return Website{}, nil
+	}
+	row := tx.QueryRow(stmt, shortId)
+	var w Website
+	err = row.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created)
+	if err != nil {
+		if errors.Is(err, sql.ErrNoRows) {
+			err = ErrNoRecord
+		}
+		if rollbackErr := tx.Rollback(); rollbackErr != nil {
+			return Website{}, err
+		}
 		return Website{}, err
 	}
-	return w, nil
-}
 
-func (m *WebsiteModel) GetById(id int64) (Website, error) {
-	stmt := `SELECT w.Id, w.ShortId, w.Name, w.SiteUrl, w.AuthorName, w.UserId, w.Created,
-	g.Id, g.ShortId, g.Created, g.IsActive
-	FROM websites AS w INNER JOIN guestbooks AS g ON w.Id = g.WebsiteId
-	WHERE w.Id = ? AND w.DELETED IS NULL`
-	row := m.DB.QueryRow(stmt, id)
-	var w Website
-	err := row.Scan(&w.ID, &w.ShortId, &w.Name, &w.SiteUrl, &w.AuthorName, &w.UserId, &w.Created,
-		&w.Guestbook.ID, &w.Guestbook.ShortId, &w.Guestbook.Created, &w.Guestbook.IsActive)
+	stmt = `SELECT Id, ShortId, UserId, WebsiteId, Created, IsActive FROM guestbooks
+    WHERE WebsiteId = ? AND Deleted IS NULL`
+	row = tx.QueryRow(stmt, w.ID)
+	var g Guestbook
+	err = row.Scan(&g.ID, &g.ShortId, &g.UserId, &g.WebsiteId, &g.Created, &g.IsActive)
 	if err != nil {
+		if errors.Is(err, sql.ErrNoRows) {
+			err = ErrNoRecord
+		}
+		if rollbackErr := tx.Rollback(); rollbackErr != nil {
+			return Website{}, err
+		}
 		return Website{}, err
 	}
+
+	gbSettings, err := m.getGuestbookSettings(tx, g.ID)
+	if err != nil {
+		if errors.Is(err, sql.ErrNoRows) {
+			err = ErrNoRecord
+		}
+		if rollbackErr := tx.Rollback(); rollbackErr != nil {
+			return Website{}, err
+		}
+		return Website{}, err
+	}
+
+	err = tx.Commit()
+	if err != nil {
+		return Website{}, nil
+	}
+
+	// if comment disable setting has expired, enable commenting
+	commentingReenabled := time.Now().UTC().After(gbSettings.ReenableCommenting)
+	if commentingReenabled {
+		gbSettings.IsCommentingEnabled = true
+	}
+
+	g.Settings = gbSettings
+	w.Guestbook = g
 	return w, nil
 }
 
@@ -113,3 +270,92 @@ func (m *WebsiteModel) GetAll() ([]Website, error) {
 	}
 	return websites, nil
 }
+
+func (m *WebsiteModel) getGuestbookSettings(tx *sql.Tx, guestbookId int64) (GuestbookSettings, error) {
+	stmt := `SELECT g.SettingId, a.ItemValue, g.UnconstrainedValue FROM guestbook_settings AS g
+			LEFT JOIN allowed_setting_values AS a ON g.AllowedSettingValueId = a.Id
+			WHERE GuestbookId = ?`
+	var settings GuestbookSettings
+	rows, err := tx.Query(stmt, guestbookId)
+	if err != nil {
+		return settings, err
+	}
+	for rows.Next() {
+		var id int
+		var itemValue sql.NullString
+		var unconstrainedValue sql.NullString
+		err = rows.Scan(&id, &itemValue, &unconstrainedValue)
+		if err != nil {
+			return settings, err
+		}
+		switch id {
+		case m.Settings[SettingGbCommentingEnabled].id:
+			settings.IsCommentingEnabled, err = strconv.ParseBool(itemValue.String)
+			if err != nil {
+				return settings, err
+			}
+			break
+		case m.Settings[SettingGbReenableComments].id:
+			settings.ReenableCommenting, err = time.Parse(time.RFC3339, unconstrainedValue.String)
+			if err != nil {
+				return settings, err
+			}
+			break
+		case m.Settings[SettingGbVisible].id:
+			settings.IsVisible, err = strconv.ParseBool(itemValue.String)
+			if err != nil {
+				return settings, err
+			}
+			break
+		case m.Settings[SettingGbAllowRemote].id:
+			settings.AllowRemoteHostAccess, err = strconv.ParseBool(itemValue.String)
+			if err != nil {
+				return settings, err
+			}
+			break
+		}
+	}
+	return settings, nil
+}
+
+func (m *WebsiteModel) UpdateGuestbookSettings(guestbookId int64, settings GuestbookSettings) error {
+	err := m.UpdateSetting(guestbookId, m.Settings[SettingGbVisible], strconv.FormatBool(settings.IsVisible))
+	if err != nil {
+		return err
+	}
+	err = m.UpdateSetting(guestbookId, m.Settings[SettingGbAllowRemote], strconv.FormatBool(settings.AllowRemoteHostAccess))
+	if err != nil {
+		return err
+	}
+	err = m.UpdateSetting(guestbookId, m.Settings[SettingGbCommentingEnabled], strconv.FormatBool(settings.IsCommentingEnabled))
+	if err != nil {
+		return err
+	}
+	err = m.UpdateSetting(guestbookId, m.Settings[SettingGbReenableComments], settings.ReenableCommenting.Format(time.RFC3339))
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (m *WebsiteModel) UpdateSetting(guestbookId int64, setting Setting, value string) error {
+	stmt := `UPDATE guestbook_settings SET
+				AllowedSettingValueId=IFNULL(
+					(SELECT Id FROM allowed_setting_values WHERE SettingId = guestbook_settings.SettingId AND ItemValue = ?), AllowedSettingValueId
+				), 
+				UnconstrainedValue=(SELECT ? FROM settings WHERE settings.Id = guestbook_settings.SettingId AND settings.Constrained=0)
+			WHERE GuestbookId = ?
+			AND SettingId = (SELECT Id from Settings WHERE Description=?);`
+	result, err := m.DB.Exec(stmt, value, value, guestbookId, setting.description)
+	if err != nil {
+		return err
+	}
+	rows, err := result.RowsAffected()
+	if err != nil {
+		return err
+	}
+	if rows != 1 {
+		return ErrInvalidSettingValue
+	}
+	return nil
+}
diff --git a/ui/views/guestbooks.templ b/ui/views/guestbooks.templ
index a8d56b7..5ad5583 100644
--- a/ui/views/guestbooks.templ
+++ b/ui/views/guestbooks.templ
@@ -3,168 +3,229 @@ package views
 import "fmt"
 import "git.32bit.cafe/32bitcafe/guestbook/internal/models"
 import "git.32bit.cafe/32bitcafe/guestbook/internal/forms"
+import "time"
 
 templ GuestbookDashboardCommentsView(title string, data CommonData, website models.Website, guestbook models.Guestbook, comments []models.GuestbookComment) {
-    @base(title, data) {
-        
-            @wSidebar(website)
-            
-                
Comments on { website.SiteUrl }
-                
-                if len(comments) == 0 {
-                    
No comments yet!
-                }
-                for  _, c := range comments {
-                    @GuestbookDashboardCommentView(data, website, c)
-                }
-            
-        
 
-    }
+	@base(title, data) {
+		
+			@wSidebar(website)
+			
+				
Comments on { website.SiteUrl }
+				
+				if len(comments) == 0 {
+					
No comments yet!
+				}
+				for  _, c := range comments {
+					@GuestbookDashboardCommentView(data, website, c)
+				}
+			
+		
 
+	}
 }
 
 templ GuestbookDashboardCommentView(data CommonData, w models.Website, c models.GuestbookComment) {
-    {{ commentUrl := fmt.Sprintf("%s/dashboard/guestbook/comments/%s", wUrl(w), shortIdToSlug(c.ShortId)) }}
-    {{ hxHeaders := fmt.Sprintf("{\"X-CSRF-Token\": \"%s\"}", data.CSRFToken) }}
-    
+	{{ commentUrl := fmt.Sprintf("%s/dashboard/guestbook/comments/%s", wUrl(w), shortIdToSlug(c.ShortId)) }}
+	{{ hxHeaders := fmt.Sprintf("{\"X-CSRF-Token\": \"%s\"}", data.CSRFToken) }}
+	
 }
 
 templ commentForm(form forms.CommentCreateForm) {
-    
-        
-        {{ error, exists := form.FieldErrors["authorName"] }}
-        if exists {
-        
-        }
-        
-    
-    
-        
-        {{ error, exists = form.FieldErrors["authorEmail"] }}
-        if exists {
-        
-        }
-        
-    
-    
-        
-        {{ error, exists = form.FieldErrors["authorSite"] }}
-        if exists {
-        
-        }
-        
-    
-    
-        
-        {{ error, exists = form.FieldErrors["content"] }}
-        if exists {
-        
-        }
-        
-    
-    
-        
-    
+	
+		
+		{{ error, exists := form.FieldErrors["authorName"] }}
+		if exists {
+			
+		}
+		
+	
+	
+		
+		{{ error, exists = form.FieldErrors["authorEmail"] }}
+		if exists {
+			
+		}
+		
+	
+	
+		
+		{{ error, exists = form.FieldErrors["authorSite"] }}
+		if exists {
+			
+		}
+		
+	
+	
+		
+		{{ error, exists = form.FieldErrors["content"] }}
+		if exists {
+			
+		}
+		
+	
+	
+		
+	
 }
 
 templ GuestbookView(title string, data CommonData, website models.Website, guestbook models.Guestbook, comments []models.GuestbookComment, form forms.CommentCreateForm) {
-    {{ postUrl := fmt.Sprintf("/websites/%s/guestbook/comments/create", shortIdToSlug(website.ShortId)) }}
-    if data.IsHtmx {
-        @commentForm(form)
-    } else {
-        
-            
-            { title }
-            
-            
-            
-                
-                    
-                        
Guestbook for { website.Name }
-                        
-                    
-                    
-                    
-                
-            
-        }
-    }
+	{{ postUrl := fmt.Sprintf("/websites/%s/guestbook/comments/create", shortIdToSlug(website.ShortId)) }}
+	if data.IsHtmx {
+		@commentForm(form)
+	} else {
+		
+			
+				{ title }
+				
+			
+			
+				
+					
+						
Guestbook for { website.Name }
+						
+					
+					
+				
+			
+		
+	}
+}
 
-    templ CreateGuestbookComment(title string, data CommonData, website models.Website, guestbook models.Guestbook, form forms.CommentCreateForm) {
-        {{ postUrl := fmt.Sprintf("/websites/%s/guestbook/comments/create", shortIdToSlug(website.ShortId)) }}
-        if data.IsHtmx {
-            
-    } else {
-        @base(title, data) {
-            
-        }
-    }
+templ CreateGuestbookComment(title string, data CommonData, website models.Website, guestbook models.Guestbook, form forms.CommentCreateForm) {
+	{{ postUrl := fmt.Sprintf("/websites/%s/guestbook/comments/create", shortIdToSlug(website.ShortId)) }}
+	if data.IsHtmx {
+		
+	} else {
+		@base(title, data) {
+			
+		}
+	}
+}
+
+templ settingRadio(selected bool, name, id, value string) {
+	
+}
+
+templ GuestbookSettingsView(data CommonData, website models.Website) {
+	{{ putUrl := fmt.Sprintf("/websites/%s/dashboard/guestbook/settings", shortIdToSlug(website.ShortId)) }}
+	{{ gb := website.Guestbook }}
+	@base("Guestbook Settings", data) {
+		
+	}
 }
 
 templ AllGuestbooksView(data CommonData, websites []models.Website) {
-    @base("All Guestbooks", data) {
-        
-            
All Guestbooks
-            
-                This page exists only for testing the service.
-            
-            
-                for _, w := range websites {
-                    - 
-                        {{  gbUrl := fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(w.ShortId))}}
-                        { w.Name }
-                    
 
-                }
-            
-        
 
-    }
-}
\ No newline at end of file
+	@base("All Guestbooks", data) {
+		
+			
All Guestbooks
+			
+				This page exists only for testing the service.
+			
+			
+				for _, w := range websites {
+					- 
+						{{ gbUrl := fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(w.ShortId)) }}
+						{ w.Name }
+					
 
+				}
+			
+		
 
+	}
+}
diff --git a/ui/views/guestbooks_templ.go b/ui/views/guestbooks_templ.go
index aab14aa..5a9bf27 100644
--- a/ui/views/guestbooks_templ.go
+++ b/ui/views/guestbooks_templ.go
@@ -11,6 +11,7 @@ import templruntime "github.com/a-h/templ/runtime"
 import "fmt"
 import "git.32bit.cafe/32bitcafe/guestbook/internal/models"
 import "git.32bit.cafe/32bitcafe/guestbook/internal/forms"
+import "time"
 
 func GuestbookDashboardCommentsView(title string, data CommonData, website models.Website, guestbook models.Guestbook, comments []models.GuestbookComment) templ.Component {
 	return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
@@ -60,7 +61,7 @@ func GuestbookDashboardCommentsView(title string, data CommonData, website model
 			var templ_7745c5c3_Var3 string
 			templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(website.SiteUrl)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 12, Col: 49}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 13, Col: 37}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
 			if templ_7745c5c3_Err != nil {
@@ -131,7 +132,7 @@ func GuestbookDashboardCommentView(data CommonData, w models.Website, c models.G
 			var templ_7745c5c3_Var5 string
 			templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(commentUrl)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 31, Col: 61}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 32, Col: 49}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
 			if templ_7745c5c3_Err != nil {
@@ -144,7 +145,7 @@ func GuestbookDashboardCommentView(data CommonData, w models.Website, c models.G
 			var templ_7745c5c3_Var6 string
 			templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(hxHeaders)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 31, Col: 118}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 32, Col: 106}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
 			if templ_7745c5c3_Err != nil {
@@ -157,7 +158,7 @@ func GuestbookDashboardCommentView(data CommonData, w models.Website, c models.G
 			var templ_7745c5c3_Var7 string
 			templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(commentUrl)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 32, Col: 59}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 33, Col: 47}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
 			if templ_7745c5c3_Err != nil {
@@ -170,7 +171,7 @@ func GuestbookDashboardCommentView(data CommonData, w models.Website, c models.G
 			var templ_7745c5c3_Var8 string
 			templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(hxHeaders)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 32, Col: 116}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 33, Col: 104}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
 			if templ_7745c5c3_Err != nil {
@@ -203,7 +204,7 @@ func GuestbookDashboardCommentView(data CommonData, w models.Website, c models.G
 		var templ_7745c5c3_Var9 string
 		templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(c.AuthorName)
 		if templ_7745c5c3_Err != nil {
-			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 42, Col: 34}
+			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 43, Col: 25}
 		}
 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
 		if templ_7745c5c3_Err != nil {
@@ -231,7 +232,7 @@ func GuestbookDashboardCommentView(data CommonData, w models.Website, c models.G
 			var templ_7745c5c3_Var11 string
 			templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(c.AuthorEmail)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 45, Col: 78}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 46, Col: 66}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
 			if templ_7745c5c3_Err != nil {
@@ -259,7 +260,7 @@ func GuestbookDashboardCommentView(data CommonData, w models.Website, c models.G
 			var templ_7745c5c3_Var13 string
 			templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(c.AuthorSite)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 48, Col: 96}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 49, Col: 85}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
 			if templ_7745c5c3_Err != nil {
@@ -275,9 +276,9 @@ func GuestbookDashboardCommentView(data CommonData, w models.Website, c models.G
 			return templ_7745c5c3_Err
 		}
 		var templ_7745c5c3_Var14 string
-		templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(c.Created.Format("01-02-2006 03:04PM"))
+		templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(c.Created.In(data.CurrentUser.Settings.LocalTimezone).Format("01-02-2006 03:04PM"))
 		if templ_7745c5c3_Err != nil {
-			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 51, Col: 56}
+			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 52, Col: 88}
 		}
 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
 		if templ_7745c5c3_Err != nil {
@@ -290,7 +291,7 @@ func GuestbookDashboardCommentView(data CommonData, w models.Website, c models.G
 		var templ_7745c5c3_Var15 string
 		templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(c.CommentText)
 		if templ_7745c5c3_Err != nil {
-			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 55, Col: 27}
+			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 56, Col: 18}
 		}
 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
 		if templ_7745c5c3_Err != nil {
@@ -338,7 +339,7 @@ func commentForm(form forms.CommentCreateForm) templ.Component {
 			var templ_7745c5c3_Var17 string
 			templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 66, Col: 36}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 67, Col: 31}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
 			if templ_7745c5c3_Err != nil {
@@ -362,7 +363,7 @@ func commentForm(form forms.CommentCreateForm) templ.Component {
 			var templ_7745c5c3_Var18 string
 			templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 74, Col: 36}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 75, Col: 31}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
 			if templ_7745c5c3_Err != nil {
@@ -386,7 +387,7 @@ func commentForm(form forms.CommentCreateForm) templ.Component {
 			var templ_7745c5c3_Var19 string
 			templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 82, Col: 36}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 83, Col: 31}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
 			if templ_7745c5c3_Err != nil {
@@ -410,7 +411,7 @@ func commentForm(form forms.CommentCreateForm) templ.Component {
 			var templ_7745c5c3_Var20 string
 			templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 90, Col: 36}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 91, Col: 31}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
 			if templ_7745c5c3_Err != nil {
@@ -464,7 +465,7 @@ func GuestbookView(title string, data CommonData, website models.Website, guestb
 			var templ_7745c5c3_Var22 string
 			templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(title)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 106, Col: 26}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 107, Col: 18}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
 			if templ_7745c5c3_Err != nil {
@@ -477,7 +478,7 @@ func GuestbookView(title string, data CommonData, website models.Website, guestb
 			var templ_7745c5c3_Var23 string
 			templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 112, Col: 56}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 113, Col: 38}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
 			if templ_7745c5c3_Err != nil {
@@ -499,7 +500,7 @@ func GuestbookView(title string, data CommonData, website models.Website, guestb
 			var templ_7745c5c3_Var25 string
 			templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(data.CSRFToken)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 114, Col: 88}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 115, Col: 68}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
 			if templ_7745c5c3_Err != nil {
@@ -531,7 +532,7 @@ func GuestbookView(title string, data CommonData, website models.Website, guestb
 				var templ_7745c5c3_Var26 string
 				templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinStringErrs(c.AuthorName)
 				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 124, Col: 50}
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 125, Col: 26}
 				}
 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26))
 				if templ_7745c5c3_Err != nil {
@@ -544,7 +545,7 @@ func GuestbookView(title string, data CommonData, website models.Website, guestb
 				var templ_7745c5c3_Var27 string
 				templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(c.Created.Format("01-02-2006 03:04PM"))
 				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 125, Col: 72}
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 126, Col: 48}
 				}
 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
 				if templ_7745c5c3_Err != nil {
@@ -557,7 +558,7 @@ func GuestbookView(title string, data CommonData, website models.Website, guestb
 				var templ_7745c5c3_Var28 string
 				templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(c.CommentText)
 				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 127, Col: 51}
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 128, Col: 24}
 				}
 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
 				if templ_7745c5c3_Err != nil {
@@ -607,7 +608,7 @@ func CreateGuestbookComment(title string, data CommonData, website models.Websit
 			var templ_7745c5c3_Var30 string
 			templ_7745c5c3_Var30, templ_7745c5c3_Err = templ.JoinStringErrs(postUrl)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 141, Col: 35}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 142, Col: 25}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var30))
 			if templ_7745c5c3_Err != nil {
@@ -670,7 +671,7 @@ func CreateGuestbookComment(title string, data CommonData, website models.Websit
 	})
 }
 
-func AllGuestbooksView(data CommonData, websites []models.Website) templ.Component {
+func settingRadio(selected bool, name, id, value string) templ.Component {
 	return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
 		templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
 		if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -691,7 +692,87 @@ func AllGuestbooksView(data CommonData, websites []models.Website) templ.Compone
 			templ_7745c5c3_Var33 = templ.NopComponent
 		}
 		ctx = templ.ClearChildren(ctx)
-		templ_7745c5c3_Var34 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "")
+		if templ_7745c5c3_Err != nil {
+			return templ_7745c5c3_Err
+		}
+		return nil
+	})
+}
+
+func GuestbookSettingsView(data CommonData, website models.Website) templ.Component {
+	return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+		templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+		if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+			return templ_7745c5c3_CtxErr
+		}
+		templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+		if !templ_7745c5c3_IsBuffer {
+			defer func() {
+				templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+				if templ_7745c5c3_Err == nil {
+					templ_7745c5c3_Err = templ_7745c5c3_BufErr
+				}
+			}()
+		}
+		ctx = templ.InitializeContext(ctx)
+		templ_7745c5c3_Var37 := templ.GetChildren(ctx)
+		if templ_7745c5c3_Var37 == nil {
+			templ_7745c5c3_Var37 = templ.NopComponent
+		}
+		ctx = templ.ClearChildren(ctx)
+		putUrl := fmt.Sprintf("/websites/%s/dashboard/guestbook/settings", shortIdToSlug(website.ShortId))
+		gb := website.Guestbook
+		templ_7745c5c3_Var38 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
 			templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
 			templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
 			if !templ_7745c5c3_IsBuffer {
@@ -703,50 +784,241 @@ func AllGuestbooksView(data CommonData, websites []models.Website) templ.Compone
 				}()
 			}
 			ctx = templ.InitializeContext(ctx)
-			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "All Guestbooks
This page exists only for testing the service.
")
+			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "")
 			if templ_7745c5c3_Err != nil {
 				return templ_7745c5c3_Err
 			}
-			for _, w := range websites {
-				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "
- ")
-				if templ_7745c5c3_Err != nil {
-					return templ_7745c5c3_Err
-				}
-				gbUrl := fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(w.ShortId))
-				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "")
-				if templ_7745c5c3_Err != nil {
-					return templ_7745c5c3_Err
-				}
-				var templ_7745c5c3_Var36 string
-				templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs(w.Name)
-				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 164, Col: 77}
-				}
-				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36))
-				if templ_7745c5c3_Err != nil {
-					return templ_7745c5c3_Err
-				}
-				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "
 ")
+			templ_7745c5c3_Err = wSidebar(website).Render(ctx, templ_7745c5c3_Buffer)
+			if templ_7745c5c3_Err != nil {
+				return templ_7745c5c3_Err
+			}
+			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "
  ")
+			if templ_7745c5c3_Err != nil {
+				return templ_7745c5c3_Err
+			}
+			if !website.Guestbook.CanComment() {
+				localtime := gb.Settings.ReenableCommenting.In(data.CurrentUser.Settings.LocalTimezone)
+				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "")
+				if templ_7745c5c3_Err != nil {
+					return templ_7745c5c3_Err
+				}
+			}
+			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "
  
 ")
 			if templ_7745c5c3_Err != nil {
 				return templ_7745c5c3_Err
 			}
 			return nil
 		})
-		templ_7745c5c3_Err = base("All Guestbooks", data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var34), templ_7745c5c3_Buffer)
+		templ_7745c5c3_Err = base("Guestbook Settings", data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var38), templ_7745c5c3_Buffer)
+		if templ_7745c5c3_Err != nil {
+			return templ_7745c5c3_Err
+		}
+		return nil
+	})
+}
+
+func AllGuestbooksView(data CommonData, websites []models.Website) templ.Component {
+	return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+		templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+		if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+			return templ_7745c5c3_CtxErr
+		}
+		templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+		if !templ_7745c5c3_IsBuffer {
+			defer func() {
+				templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+				if templ_7745c5c3_Err == nil {
+					templ_7745c5c3_Err = templ_7745c5c3_BufErr
+				}
+			}()
+		}
+		ctx = templ.InitializeContext(ctx)
+		templ_7745c5c3_Var44 := templ.GetChildren(ctx)
+		if templ_7745c5c3_Var44 == nil {
+			templ_7745c5c3_Var44 = templ.NopComponent
+		}
+		ctx = templ.ClearChildren(ctx)
+		templ_7745c5c3_Var45 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+			templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+			templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+			if !templ_7745c5c3_IsBuffer {
+				defer func() {
+					templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+					if templ_7745c5c3_Err == nil {
+						templ_7745c5c3_Err = templ_7745c5c3_BufErr
+					}
+				}()
+			}
+			ctx = templ.InitializeContext(ctx)
+			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "All Guestbooks
This page exists only for testing the service.
")
+			if templ_7745c5c3_Err != nil {
+				return templ_7745c5c3_Err
+			}
+			for _, w := range websites {
+				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "- ")
+				if templ_7745c5c3_Err != nil {
+					return templ_7745c5c3_Err
+				}
+				gbUrl := fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(w.ShortId))
+				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "")
+				if templ_7745c5c3_Err != nil {
+					return templ_7745c5c3_Err
+				}
+				var templ_7745c5c3_Var47 string
+				templ_7745c5c3_Var47, templ_7745c5c3_Err = templ.JoinStringErrs(w.Name)
+				if templ_7745c5c3_Err != nil {
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/guestbooks.templ`, Line: 225, Col: 59}
+				}
+				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var47))
+				if templ_7745c5c3_Err != nil {
+					return templ_7745c5c3_Err
+				}
+				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "
 ")
+				if templ_7745c5c3_Err != nil {
+					return templ_7745c5c3_Err
+				}
+			}
+			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "
 ")
+			if templ_7745c5c3_Err != nil {
+				return templ_7745c5c3_Err
+			}
+			return nil
+		})
+		templ_7745c5c3_Err = base("All Guestbooks", data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var45), templ_7745c5c3_Buffer)
 		if templ_7745c5c3_Err != nil {
 			return templ_7745c5c3_Err
 		}
diff --git a/ui/views/users.templ b/ui/views/users.templ
index 46467c8..4fb839b 100644
--- a/ui/views/users.templ
+++ b/ui/views/users.templ
@@ -5,79 +5,99 @@ import (
 	"git.32bit.cafe/32bitcafe/guestbook/internal/models"
 )
 
-templ UserLogin (title string, data CommonData, form forms.UserLoginForm) {
-    @base(title, data) {
-        Login
-        
-    }
+templ UserLogin(title string, data CommonData, form forms.UserLoginForm) {
+	@base(title, data) {
+		Login
+		
+	}
 }
 
-templ UserRegistration (title string, data CommonData, form forms.UserRegistrationForm) {
-    @base(title, data) {
-        User Registration
-        
-    }
+templ UserRegistration(title string, data CommonData, form forms.UserRegistrationForm) {
+	@base(title, data) {
+		User Registration
+		
+	}
 }
 
-templ UserProfile (title string, data CommonData, user models.User) {
-    @base(title, data) {
-        { user.Username }
-        { user.Email }
-    }
+templ UserProfile(title string, data CommonData, user models.User) {
+	@base(title, data) {
+		{ user.Username }
+		{ user.Email }
+	}
 }
 
-templ UserSettings () {
+templ UserSettingsView(data CommonData, timezones []string) {
+	{{ user := data.CurrentUser }}
+	@base("User Settings", data) {
+		
+			
User Settings
+			
+		
+	}
 }
diff --git a/ui/views/users_templ.go b/ui/views/users_templ.go
index 661a6f5..c791e2d 100644
--- a/ui/views/users_templ.go
+++ b/ui/views/users_templ.go
@@ -53,7 +53,7 @@ func UserLogin(title string, data CommonData, form forms.UserLoginForm) templ.Co
 			var templ_7745c5c3_Var3 string
 			templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(data.CSRFToken)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 12, Col: 73}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 12, Col: 64}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
 			if templ_7745c5c3_Err != nil {
@@ -71,7 +71,7 @@ func UserLogin(title string, data CommonData, form forms.UserLoginForm) templ.Co
 				var templ_7745c5c3_Var4 string
 				templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 14, Col: 42}
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 14, Col: 30}
 				}
 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
 				if templ_7745c5c3_Err != nil {
@@ -95,7 +95,7 @@ func UserLogin(title string, data CommonData, form forms.UserLoginForm) templ.Co
 				var templ_7745c5c3_Var5 string
 				templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 20, Col: 48}
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 20, Col: 33}
 				}
 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
 				if templ_7745c5c3_Err != nil {
@@ -113,7 +113,7 @@ func UserLogin(title string, data CommonData, form forms.UserLoginForm) templ.Co
 			var templ_7745c5c3_Var6 string
 			templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(form.Email)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 22, Col: 66}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 22, Col: 55}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
 			if templ_7745c5c3_Err != nil {
@@ -132,7 +132,7 @@ func UserLogin(title string, data CommonData, form forms.UserLoginForm) templ.Co
 				var templ_7745c5c3_Var7 string
 				templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 28, Col: 48}
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 28, Col: 33}
 				}
 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
 				if templ_7745c5c3_Err != nil {
@@ -197,7 +197,7 @@ func UserRegistration(title string, data CommonData, form forms.UserRegistration
 			var templ_7745c5c3_Var10 string
 			templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(data.CSRFToken)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 43, Col: 73}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 43, Col: 64}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
 			if templ_7745c5c3_Err != nil {
@@ -220,7 +220,7 @@ func UserRegistration(title string, data CommonData, form forms.UserRegistration
 				var templ_7745c5c3_Var11 string
 				templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 48, Col: 48}
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 48, Col: 33}
 				}
 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
 				if templ_7745c5c3_Err != nil {
@@ -238,7 +238,7 @@ func UserRegistration(title string, data CommonData, form forms.UserRegistration
 			var templ_7745c5c3_Var12 string
 			templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(form.Name)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 50, Col: 81}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 50, Col: 70}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
 			if templ_7745c5c3_Err != nil {
@@ -261,7 +261,7 @@ func UserRegistration(title string, data CommonData, form forms.UserRegistration
 				var templ_7745c5c3_Var13 string
 				templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 56, Col: 48}
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 56, Col: 33}
 				}
 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
 				if templ_7745c5c3_Err != nil {
@@ -279,7 +279,7 @@ func UserRegistration(title string, data CommonData, form forms.UserRegistration
 			var templ_7745c5c3_Var14 string
 			templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(form.Email)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 58, Col: 76}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 58, Col: 65}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
 			if templ_7745c5c3_Err != nil {
@@ -302,7 +302,7 @@ func UserRegistration(title string, data CommonData, form forms.UserRegistration
 				var templ_7745c5c3_Var15 string
 				templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(error)
 				if templ_7745c5c3_Err != nil {
-					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 64, Col: 48}
+					return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 64, Col: 33}
 				}
 				_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
 				if templ_7745c5c3_Err != nil {
@@ -367,7 +367,7 @@ func UserProfile(title string, data CommonData, user models.User) templ.Componen
 			var templ_7745c5c3_Var18 string
 			templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(user.Username)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 77, Col: 27}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 77, Col: 21}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
 			if templ_7745c5c3_Err != nil {
@@ -380,7 +380,7 @@ func UserProfile(title string, data CommonData, user models.User) templ.Componen
 			var templ_7745c5c3_Var19 string
 			templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(user.Email)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 78, Col: 23}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/users.templ`, Line: 78, Col: 17}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
 			if templ_7745c5c3_Err != nil {
@@ -400,7 +400,7 @@ func UserProfile(title string, data CommonData, user models.User) templ.Componen
 	})
 }
 
-func UserSettings() templ.Component {
+func UserSettingsView(data CommonData, timezones []string) templ.Component {
 	return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
 		templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
 		if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
@@ -421,6 +421,111 @@ func UserSettings() templ.Component {
 			templ_7745c5c3_Var20 = templ.NopComponent
 		}
 		ctx = templ.ClearChildren(ctx)
+		user := data.CurrentUser
+		templ_7745c5c3_Var21 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+			templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+			templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+			if !templ_7745c5c3_IsBuffer {
+				defer func() {
+					templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+					if templ_7745c5c3_Err == nil {
+						templ_7745c5c3_Err = templ_7745c5c3_BufErr
+					}
+				}()
+			}
+			ctx = templ.InitializeContext(ctx)
+			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "User Settings
")
+			if templ_7745c5c3_Err != nil {
+				return templ_7745c5c3_Err
+			}
+			return nil
+		})
+		templ_7745c5c3_Err = base("User Settings", data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var21), templ_7745c5c3_Buffer)
+		if templ_7745c5c3_Err != nil {
+			return templ_7745c5c3_Err
+		}
 		return nil
 	})
 }
diff --git a/ui/views/websites.templ b/ui/views/websites.templ
index 5dbf533..d778676 100644
--- a/ui/views/websites.templ
+++ b/ui/views/websites.templ
@@ -4,151 +4,141 @@ import "fmt"
 import "git.32bit.cafe/32bitcafe/guestbook/internal/models"
 import "git.32bit.cafe/32bitcafe/guestbook/internal/forms"
 
-func wUrl (w models.Website) string {
-    return fmt.Sprintf("/websites/%s", shortIdToSlug(w.ShortId))
+func wUrl(w models.Website) string {
+	return fmt.Sprintf("/websites/%s", shortIdToSlug(w.ShortId))
 }
 
 templ wSidebar(website models.Website) {
-    {{ dashUrl := wUrl(website) + "/dashboard" }}
-    {{ gbUrl := wUrl(website) + "/guestbook" }}
-    
+	{{ dashUrl := wUrl(website) + "/dashboard" }}
+	{{ gbUrl := wUrl(website) + "/guestbook" }}
+	
 }
 
-templ displayWebsites (websites []models.Website) {
-    if len(websites) == 0 {
-        No Websites yet. Register a website.
-    } else {
-        
-            for _, w := range websites {
-                - 
-                    { w.Name }
-                
 
-            }
-        
-    }
+templ displayWebsites(websites []models.Website) {
+	if len(websites) == 0 {
+		No Websites yet. Register a website.
+	} else {
+		
+			for _, w := range websites {
+				- 
+					{ w.Name }
+				
 
+			}
+		
+	}
 }
 
 templ websiteCreateForm(csrfToken string, form forms.WebsiteCreateForm) {
-    
-    
-        {{ err, exists := form.FieldErrors["sitename"]}}
-        
-        if exists {
-            
-        }
-        
-    
-    
-        {{ err, exists = form.FieldErrors["siteurl"] }}
-        
-        if exists {
-            
-        }
-        
-    
-    
-        {{ err, exists = form.FieldErrors["authorname"] }}
-        
-        if exists {
-            
-        }
-        
-    
-    
-        
-    
+	
+	
+		{{ err, exists := form.FieldErrors["sitename"] }}
+		
+		if exists {
+			
+		}
+		
+	
+	
+		{{ err, exists = form.FieldErrors["siteurl"] }}
+		
+		if exists {
+			
+		}
+		
+	
+	
+		{{ err, exists = form.FieldErrors["authorname"] }}
+		
+		if exists {
+			
+		}
+		
+	
+	
+		
+	
 }
 
 templ WebsiteCreateButton() {
-    
+	
 }
 
 templ WebsiteList(title string, data CommonData, websites []models.Website) {
-    if data.IsHtmx {
-        @displayWebsites(websites)
-    } else {
-        @base(title, data) {
-            My Websites
-            
-                @WebsiteCreateButton()
-            
-            
-                @displayWebsites(websites)
-            
-        }
-    }
+	@base(title, data) {
+		My Websites
+		
+			@WebsiteCreateButton()
+		
+		
+			@displayWebsites(websites)
+		
+	}
 }
 
 templ WebsiteDashboard(title string, data CommonData, website models.Website) {
-    @base(title, data) {
-        
-            @wSidebar(website) 
-            
-                
{ website.Name }
-                
-                    Stats and stuff will go here.
-                
-            
-        
 
-    }
+	@base(title, data) {
+		
+			@wSidebar(website)
+			
+				
{ website.Name }
+				
+					Stats and stuff will go here.
+				
+			
+		
 
+	}
 }
 
 templ WebsiteDashboardComingSoon(title string, data CommonData, website models.Website) {
-    @base(title, data) {
-        
-            @wSidebar(website) 
-            
-                
{ website.Name }
-                
-                    Coming Soon
-                
-            
-        
 
-    }
+	@base(title, data) {
+		
+			@wSidebar(website)
+			
+				
{ website.Name }
+				
+					Coming Soon
+				
+			
+		
 
+	}
 }
 
 templ WebsiteCreate(title string, data CommonData, form forms.WebsiteCreateForm) {
-    if data.IsHtmx {
-        
-    } else {
-        
-    }
-}
\ No newline at end of file
+	
+}
diff --git a/ui/views/websites_hx.templ b/ui/views/websites_hx.templ
new file mode 100644
index 0000000..28ba2eb
--- /dev/null
+++ b/ui/views/websites_hx.templ
@@ -0,0 +1,7 @@
+package views
+
+import "git.32bit.cafe/32bitcafe/guestbook/internal/models"
+
+templ HxWebsiteList(websites []models.Website) {
+	@displayWebsites(websites)
+}
diff --git a/ui/views/websites_hx_templ.go b/ui/views/websites_hx_templ.go
new file mode 100644
index 0000000..cb3cbf2
--- /dev/null
+++ b/ui/views/websites_hx_templ.go
@@ -0,0 +1,42 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.3.833
+package views
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import templruntime "github.com/a-h/templ/runtime"
+
+import "git.32bit.cafe/32bitcafe/guestbook/internal/models"
+
+func HxWebsiteList(websites []models.Website) templ.Component {
+	return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+		templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+		if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+			return templ_7745c5c3_CtxErr
+		}
+		templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+		if !templ_7745c5c3_IsBuffer {
+			defer func() {
+				templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+				if templ_7745c5c3_Err == nil {
+					templ_7745c5c3_Err = templ_7745c5c3_BufErr
+				}
+			}()
+		}
+		ctx = templ.InitializeContext(ctx)
+		templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+		if templ_7745c5c3_Var1 == nil {
+			templ_7745c5c3_Var1 = templ.NopComponent
+		}
+		ctx = templ.ClearChildren(ctx)
+		templ_7745c5c3_Err = displayWebsites(websites).Render(ctx, templ_7745c5c3_Buffer)
+		if templ_7745c5c3_Err != nil {
+			return templ_7745c5c3_Err
+		}
+		return nil
+	})
+}
+
+var _ = templruntime.GeneratedTemplate
diff --git a/ui/views/websites_templ.go b/ui/views/websites_templ.go
index fbe1f45..2d6d6a6 100644
--- a/ui/views/websites_templ.go
+++ b/ui/views/websites_templ.go
@@ -46,7 +46,7 @@ func wSidebar(website models.Website) templ.Component {
 		var templ_7745c5c3_Var2 string
 		templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name)
 		if templ_7745c5c3_Err != nil {
-			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 16, Col: 30}
+			return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 16, Col: 21}
 		}
 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
 		if templ_7745c5c3_Err != nil {
@@ -101,21 +101,21 @@ func wSidebar(website models.Website) templ.Component {
 		if templ_7745c5c3_Err != nil {
 			return templ_7745c5c3_Err
 		}
-		var templ_7745c5c3_Var8 templ.SafeURL = templ.URL(dashUrl + "/guestbook/blocklist")
+		var templ_7745c5c3_Var8 templ.SafeURL = templ.URL(dashUrl + "/guestbook/comments/trash")
 		_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(string(templ_7745c5c3_Var8)))
 		if templ_7745c5c3_Err != nil {
 			return templ_7745c5c3_Err
 		}
-		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">Block usersTrashTrash- My Websites
")
+			if templ_7745c5c3_Err != nil {
+				return templ_7745c5c3_Err
+			}
+			templ_7745c5c3_Err = WebsiteCreateButton().Render(ctx, templ_7745c5c3_Buffer)
+			if templ_7745c5c3_Err != nil {
+				return templ_7745c5c3_Err
+			}
+			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "
")
+			if templ_7745c5c3_Err != nil {
+				return templ_7745c5c3_Err
+			}
 			templ_7745c5c3_Err = displayWebsites(websites).Render(ctx, templ_7745c5c3_Buffer)
 			if templ_7745c5c3_Err != nil {
 				return templ_7745c5c3_Err
 			}
-		} else {
-			templ_7745c5c3_Var22 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
-				templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
-				templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
-				if !templ_7745c5c3_IsBuffer {
-					defer func() {
-						templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
-						if templ_7745c5c3_Err == nil {
-							templ_7745c5c3_Err = templ_7745c5c3_BufErr
-						}
-					}()
-				}
-				ctx = templ.InitializeContext(ctx)
-				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "
My Websites
")
-				if templ_7745c5c3_Err != nil {
-					return templ_7745c5c3_Err
-				}
-				templ_7745c5c3_Err = WebsiteCreateButton().Render(ctx, templ_7745c5c3_Buffer)
-				if templ_7745c5c3_Err != nil {
-					return templ_7745c5c3_Err
-				}
-				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "
")
-				if templ_7745c5c3_Err != nil {
-					return templ_7745c5c3_Err
-				}
-				templ_7745c5c3_Err = displayWebsites(websites).Render(ctx, templ_7745c5c3_Buffer)
-				if templ_7745c5c3_Err != nil {
-					return templ_7745c5c3_Err
-				}
-				templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
")
-				if templ_7745c5c3_Err != nil {
-					return templ_7745c5c3_Err
-				}
-				return nil
-			})
-			templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var22), templ_7745c5c3_Buffer)
+			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
 ")
 			if templ_7745c5c3_Err != nil {
 				return templ_7745c5c3_Err
 			}
+			return nil
+		})
+		templ_7745c5c3_Err = base(title, data).Render(templ.WithChildren(ctx, templ_7745c5c3_Var22), templ_7745c5c3_Buffer)
+		if templ_7745c5c3_Err != nil {
+			return templ_7745c5c3_Err
 		}
 		return nil
 	})
@@ -482,7 +475,7 @@ func WebsiteDashboard(title string, data CommonData, website models.Website) tem
 			var templ_7745c5c3_Var25 string
 			templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 121, Col: 34}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 117, Col: 22}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
 			if templ_7745c5c3_Err != nil {
@@ -550,7 +543,7 @@ func WebsiteDashboardComingSoon(title string, data CommonData, website models.We
 			var templ_7745c5c3_Var28 string
 			templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(website.Name)
 			if templ_7745c5c3_Err != nil {
-				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 135, Col: 34}
+				return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/views/websites.templ`, Line: 131, Col: 22}
 			}
 			_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
 			if templ_7745c5c3_Err != nil {
@@ -591,32 +584,17 @@ func WebsiteCreate(title string, data CommonData, form forms.WebsiteCreateForm)
 			templ_7745c5c3_Var29 = templ.NopComponent
 		}
 		ctx = templ.ClearChildren(ctx)
-		if data.IsHtmx {
-			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "")
-			if templ_7745c5c3_Err != nil {
-				return templ_7745c5c3_Err
-			}
-		} else {
-			templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "")
-			if templ_7745c5c3_Err != nil {
-				return templ_7745c5c3_Err
-			}
+		templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "")
+		if templ_7745c5c3_Err != nil {
+			return templ_7745c5c3_Err
 		}
 		return nil
 	})
 
No comments yet!
- } - for _, c := range comments { -{ c.AuthorName }
- { c.Created.Format("01-02-2006 03:04PM") } -- { c.CommentText } -
-