feat(profile): keep_screen_awake user preference (default on)
New users column surfaced as an On/Off dropdown in the profile form. The form and API carry "true"/"false" strings with the theme-style ""-guard, so JSON clients that omit the field can't clobber it; anything else is rejected. GET/PUT /api/auth/profile expose keep_screen_awake alongside the other profile fields, and the reader route threads the preference into its template metadata. Integration tests pin the schema default, both values, omission semantics, and rejection — dedicated test user, never testuser.
This commit is contained in:
1 parent
bdb9132b85
commit
c645b8e207
12 files changed
+244
-67
No files matched your search
@@ -667,3 +667,92 @@ func TestUpdatePasswordSelfChange(t *testing.T) {
|
|||||||
assert.Contains(t, rec.Body.String(), "current password required")
|
assert.Contains(t, rec.Body.String(), "current password required")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestProfileKeepScreenAwake pins the keep_screen_awake user preference
|
||||||
|
// end to end: schema default, the "true"/"false" form dropdown contract,
|
||||||
|
// JSON-client omission semantics ("" = untouched), and rejection of
|
||||||
|
// anything else. Uses a dedicated user — never the shared admin.
|
||||||
|
func TestProfileKeepScreenAwake(t *testing.T) {
|
||||||
|
// getProfile fetches the JSON profile and returns keep_screen_awake.
|
||||||
|
getProfile := func(t *testing.T, setup *TestServerSetup, token string) bool {
|
||||||
|
req := httptest.NewRequest("GET", "/api/auth/profile", nil)
|
||||||
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
setup.Server.Config.Handler.ServeHTTP(rec, req)
|
||||||
|
require.Equal(t, http.StatusOK, rec.Code)
|
||||||
|
var body struct {
|
||||||
|
KeepScreenAwake bool `json:"keep_screen_awake"`
|
||||||
|
}
|
||||||
|
require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &body))
|
||||||
|
return body.KeepScreenAwake
|
||||||
|
}
|
||||||
|
putProfile := func(t *testing.T, setup *TestServerSetup, token string, fields map[string]interface{}) *httptest.ResponseRecorder {
|
||||||
|
jsonData, _ := json.Marshal(fields)
|
||||||
|
req := httptest.NewRequest("PUT", "/api/auth/profile", bytes.NewBuffer(jsonData))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
setup.Server.Config.Handler.ServeHTTP(rec, req)
|
||||||
|
return rec
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("fresh user defaults to true", func(t *testing.T) {
|
||||||
|
setup := setupTestServer(t)
|
||||||
|
selfUser := createRegularUserOnce(t, setup.DB)
|
||||||
|
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||||
|
|
||||||
|
row, err := setup.DB.GetUser(context.Background(), pgtype.UUID{Bytes: selfUser.ID, Valid: true})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, row.KeepScreenAwake, "schema default must keep the column TRUE")
|
||||||
|
assert.True(t, getProfile(t, setup, token), "profile API must report the default")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("false persists and reads back", func(t *testing.T) {
|
||||||
|
setup := setupTestServer(t)
|
||||||
|
selfUser := createRegularUserOnce(t, setup.DB)
|
||||||
|
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||||
|
|
||||||
|
rec := putProfile(t, setup, token, map[string]interface{}{"keep_screen_awake": "false"})
|
||||||
|
require.Equal(t, http.StatusOK, rec.Code)
|
||||||
|
assert.False(t, getProfile(t, setup, token))
|
||||||
|
|
||||||
|
row, err := setup.DB.GetUser(context.Background(), pgtype.UUID{Bytes: selfUser.ID, Valid: true})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.False(t, row.KeepScreenAwake)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("flipping back to true persists", func(t *testing.T) {
|
||||||
|
setup := setupTestServer(t)
|
||||||
|
selfUser := createRegularUserOnce(t, setup.DB)
|
||||||
|
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||||
|
|
||||||
|
require.Equal(t, http.StatusOK, putProfile(t, setup, token,
|
||||||
|
map[string]interface{}{"keep_screen_awake": "false"}).Code)
|
||||||
|
require.Equal(t, http.StatusOK, putProfile(t, setup, token,
|
||||||
|
map[string]interface{}{"keep_screen_awake": "true"}).Code)
|
||||||
|
assert.True(t, getProfile(t, setup, token))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("request omitting the field leaves it untouched", func(t *testing.T) {
|
||||||
|
setup := setupTestServer(t)
|
||||||
|
selfUser := createRegularUserOnce(t, setup.DB)
|
||||||
|
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||||
|
|
||||||
|
// JSON clients (the Android app) sync other profile fields
|
||||||
|
// without knowing this one — the default-on preference must
|
||||||
|
// survive such a save.
|
||||||
|
rec := putProfile(t, setup, token, map[string]interface{}{"theme": "nord"})
|
||||||
|
require.Equal(t, http.StatusOK, rec.Code)
|
||||||
|
assert.True(t, getProfile(t, setup, token))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid value is rejected", func(t *testing.T) {
|
||||||
|
setup := setupTestServer(t)
|
||||||
|
selfUser := createRegularUserOnce(t, setup.DB)
|
||||||
|
token := loginUserWithCredentials(t, setup.Server, selfUser.Email, selfUser.Password)
|
||||||
|
|
||||||
|
rec := putProfile(t, setup, token, map[string]interface{}{"keep_screen_awake": "maybe"})
|
||||||
|
assert.Equal(t, http.StatusBadRequest, rec.Code)
|
||||||
|
assert.True(t, getProfile(t, setup, token), "rejected save must not change the preference")
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -42,6 +42,11 @@ CREATE TABLE IF NOT EXISTS users (
|
|||||||
-- mirrors the per-book table's column.
|
-- mirrors the per-book table's column.
|
||||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS default_audio_speed REAL NOT NULL DEFAULT 1.0;
|
ALTER TABLE users ADD COLUMN IF NOT EXISTS default_audio_speed REAL NOT NULL DEFAULT 1.0;
|
||||||
|
|
||||||
|
-- Keep-screen-awake preference: when true, the web reader and audiobook
|
||||||
|
-- player request a Screen Wake Lock so the display doesn't blank/lock
|
||||||
|
-- mid-session. On by default; the profile page's On/Off dropdown owns it.
|
||||||
|
ALTER TABLE users ADD COLUMN IF NOT EXISTS keep_screen_awake BOOLEAN NOT NULL DEFAULT TRUE;
|
||||||
|
|
||||||
-- Create system_settings table
|
-- Create system_settings table
|
||||||
CREATE TABLE IF NOT EXISTS system_settings (
|
CREATE TABLE IF NOT EXISTS system_settings (
|
||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
|||||||
@@ -597,4 +597,5 @@ type Users struct {
|
|||||||
Timezone pgtype.Text `db:"timezone" json:"timezone"`
|
Timezone pgtype.Text `db:"timezone" json:"timezone"`
|
||||||
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||||
DefaultAudioSpeed float32 `db:"default_audio_speed" json:"default_audio_speed"`
|
DefaultAudioSpeed float32 `db:"default_audio_speed" json:"default_audio_speed"`
|
||||||
|
KeepScreenAwake bool `db:"keep_screen_awake" json:"keep_screen_awake"`
|
||||||
}
|
}
|
||||||
@@ -699,6 +699,7 @@ type Querier interface {
|
|||||||
// Update universal progress
|
// Update universal progress
|
||||||
UpdateUniversalProgress(ctx context.Context, arg UpdateUniversalProgressParams) (ReadingProgress, error)
|
UpdateUniversalProgress(ctx context.Context, arg UpdateUniversalProgressParams) (ReadingProgress, error)
|
||||||
UpdateUserDefaultAudioSpeed(ctx context.Context, arg UpdateUserDefaultAudioSpeedParams) error
|
UpdateUserDefaultAudioSpeed(ctx context.Context, arg UpdateUserDefaultAudioSpeedParams) error
|
||||||
|
UpdateUserKeepScreenAwake(ctx context.Context, arg UpdateUserKeepScreenAwakeParams) error
|
||||||
UpdateUserMaxDevices(ctx context.Context, arg UpdateUserMaxDevicesParams) (Users, error)
|
UpdateUserMaxDevices(ctx context.Context, arg UpdateUserMaxDevicesParams) (Users, error)
|
||||||
UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) error
|
UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) error
|
||||||
UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UpdateUserRoleRow, error)
|
UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UpdateUserRoleRow, error)
|
||||||
|
|||||||
@@ -9942,6 +9942,7 @@ SELECT
|
|||||||
u.updated_at,
|
u.updated_at,
|
||||||
u.timezone,
|
u.timezone,
|
||||||
u.default_audio_speed,
|
u.default_audio_speed,
|
||||||
|
u.keep_screen_awake,
|
||||||
(SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count
|
(SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count
|
||||||
FROM users u
|
FROM users u
|
||||||
WHERE u.id = $1
|
WHERE u.id = $1
|
||||||
@@ -9960,6 +9961,7 @@ type GetUserRow struct {
|
|||||||
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `db:"updated_at" json:"updated_at"`
|
||||||
Timezone pgtype.Text `db:"timezone" json:"timezone"`
|
Timezone pgtype.Text `db:"timezone" json:"timezone"`
|
||||||
DefaultAudioSpeed float32 `db:"default_audio_speed" json:"default_audio_speed"`
|
DefaultAudioSpeed float32 `db:"default_audio_speed" json:"default_audio_speed"`
|
||||||
|
KeepScreenAwake bool `db:"keep_screen_awake" json:"keep_screen_awake"`
|
||||||
DeviceCount int64 `db:"device_count" json:"device_count"`
|
DeviceCount int64 `db:"device_count" json:"device_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9979,6 +9981,7 @@ func (q *Queries) GetUser(ctx context.Context, id pgtype.UUID) (GetUserRow, erro
|
|||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.Timezone,
|
&i.Timezone,
|
||||||
&i.DefaultAudioSpeed,
|
&i.DefaultAudioSpeed,
|
||||||
|
&i.KeepScreenAwake,
|
||||||
&i.DeviceCount,
|
&i.DeviceCount,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
@@ -17236,9 +17239,23 @@ func (q *Queries) UpdateUserDefaultAudioSpeed(ctx context.Context, arg UpdateUse
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UpdateUserKeepScreenAwake = `-- name: UpdateUserKeepScreenAwake :exec
|
||||||
|
UPDATE users SET keep_screen_awake = $2, updated_at = NOW() WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateUserKeepScreenAwakeParams struct {
|
||||||
|
ID pgtype.UUID `db:"id" json:"id"`
|
||||||
|
KeepScreenAwake bool `db:"keep_screen_awake" json:"keep_screen_awake"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateUserKeepScreenAwake(ctx context.Context, arg UpdateUserKeepScreenAwakeParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateUserKeepScreenAwake, arg.ID, arg.KeepScreenAwake)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const UpdateUserMaxDevices = `-- name: UpdateUserMaxDevices :one
|
const UpdateUserMaxDevices = `-- name: UpdateUserMaxDevices :one
|
||||||
UPDATE users SET max_devices = $2, updated_at = NOW() WHERE id = $1
|
UPDATE users SET max_devices = $2, updated_at = NOW() WHERE id = $1
|
||||||
RETURNING id, email, username, password_hash, first_name, last_name, role, theme, max_devices, created_at, timezone, updated_at, default_audio_speed
|
RETURNING id, email, username, password_hash, first_name, last_name, role, theme, max_devices, created_at, timezone, updated_at, default_audio_speed, keep_screen_awake
|
||||||
`
|
`
|
||||||
|
|
||||||
type UpdateUserMaxDevicesParams struct {
|
type UpdateUserMaxDevicesParams struct {
|
||||||
@@ -17263,6 +17280,7 @@ func (q *Queries) UpdateUserMaxDevices(ctx context.Context, arg UpdateUserMaxDev
|
|||||||
&i.Timezone,
|
&i.Timezone,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
&i.DefaultAudioSpeed,
|
&i.DefaultAudioSpeed,
|
||||||
|
&i.KeepScreenAwake,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ SELECT
|
|||||||
u.updated_at,
|
u.updated_at,
|
||||||
u.timezone,
|
u.timezone,
|
||||||
u.default_audio_speed,
|
u.default_audio_speed,
|
||||||
|
u.keep_screen_awake,
|
||||||
(SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count
|
(SELECT COUNT(*) FROM devices WHERE user_id = u.id) as device_count
|
||||||
FROM users u
|
FROM users u
|
||||||
WHERE u.id = $1;
|
WHERE u.id = $1;
|
||||||
@@ -515,6 +516,9 @@ UPDATE users SET timezone = $2, updated_at = NOW() WHERE id = $1;
|
|||||||
-- name: UpdateUserDefaultAudioSpeed :exec
|
-- name: UpdateUserDefaultAudioSpeed :exec
|
||||||
UPDATE users SET default_audio_speed = $2, updated_at = NOW() WHERE id = $1;
|
UPDATE users SET default_audio_speed = $2, updated_at = NOW() WHERE id = $1;
|
||||||
|
|
||||||
|
-- name: UpdateUserKeepScreenAwake :exec
|
||||||
|
UPDATE users SET keep_screen_awake = $2, updated_at = NOW() WHERE id = $1;
|
||||||
|
|
||||||
-- Per-book playback speed preference (player plan §8).
|
-- Per-book playback speed preference (player plan §8).
|
||||||
|
|
||||||
-- name: GetAudioPlaybackSpeed :one
|
-- name: GetAudioPlaybackSpeed :one
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ type UserProfile struct {
|
|||||||
Theme string `json:"theme,omitempty"`
|
Theme string `json:"theme,omitempty"`
|
||||||
// User-level default audiobook playback speed (plan §8); 0 omits.
|
// User-level default audiobook playback speed (plan §8); 0 omits.
|
||||||
DefaultAudioSpeed float64 `json:"default_audio_speed,omitempty"`
|
DefaultAudioSpeed float64 `json:"default_audio_speed,omitempty"`
|
||||||
|
// Whether the web reader/player should hold a Screen Wake Lock.
|
||||||
|
KeepScreenAwake bool `json:"keep_screen_awake"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProfileUpdateRequest struct {
|
type ProfileUpdateRequest struct {
|
||||||
@@ -132,6 +134,9 @@ type ProfileUpdateRequest struct {
|
|||||||
Theme string `json:"theme,omitempty" form:"theme" validate:"omitempty"`
|
Theme string `json:"theme,omitempty" form:"theme" validate:"omitempty"`
|
||||||
Timezone string `json:"timezone,omitempty" form:"timezone" validate:"omitempty"`
|
Timezone string `json:"timezone,omitempty" form:"timezone" validate:"omitempty"`
|
||||||
Role string `json:"role,omitempty" form:"role" validate:"omitempty,oneof=user admin"`
|
Role string `json:"role,omitempty" form:"role" validate:"omitempty,oneof=user admin"`
|
||||||
|
// "true"/"false" — the profile dropdown always sends it; JSON clients
|
||||||
|
// that omit it decode as "" and leave the column untouched.
|
||||||
|
KeepScreenAwake string `json:"keep_screen_awake,omitempty" form:"keep_screen_awake" validate:"omitempty,oneof=true false"`
|
||||||
// Per the SPEEDS list bounds; the profile select always sends it,
|
// Per the SPEEDS list bounds; the profile select always sends it,
|
||||||
// JSON clients omit it (0 = untouched).
|
// JSON clients omit it (0 = untouched).
|
||||||
DefaultAudioSpeed float64 `json:"default_audio_speed,omitempty" form:"default_audio_speed" validate:"omitempty,min=0.25,max=4"`
|
DefaultAudioSpeed float64 `json:"default_audio_speed,omitempty" form:"default_audio_speed" validate:"omitempty,min=0.25,max=4"`
|
||||||
@@ -542,6 +547,7 @@ func (h *AuthHandler) GetProfile(c *echo.Context) error {
|
|||||||
Role: user.Role,
|
Role: user.Role,
|
||||||
Theme: user.Theme.String,
|
Theme: user.Theme.String,
|
||||||
DefaultAudioSpeed: float64(user.DefaultAudioSpeed),
|
DefaultAudioSpeed: float64(user.DefaultAudioSpeed),
|
||||||
|
KeepScreenAwake: user.KeepScreenAwake,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,6 +712,22 @@ func (h *AuthHandler) UpdateProfile(c *echo.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep-screen-awake preference. The form dropdown always sends it
|
||||||
|
// ("true"/"false"); JSON clients that omit it decode as "" and leave
|
||||||
|
// the column untouched.
|
||||||
|
if req.KeepScreenAwake != "" {
|
||||||
|
if req.KeepScreenAwake != "true" && req.KeepScreenAwake != "false" {
|
||||||
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "keep_screen_awake must be 'true' or 'false'"})
|
||||||
|
}
|
||||||
|
err := h.db.UpdateUserKeepScreenAwake(c.Request().Context(), database.UpdateUserKeepScreenAwakeParams{
|
||||||
|
ID: targetUserUUID,
|
||||||
|
KeepScreenAwake: req.KeepScreenAwake == "true",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Browser path (htmx modal + profile page): refresh so every rendered
|
// Browser path (htmx modal + profile page): refresh so every rendered
|
||||||
// value (timezone select, table rows, header) reflects the save and the
|
// value (timezone select, table rows, header) reflects the save and the
|
||||||
// modal closes. A bare JSON body swapped into #profile-result read as
|
// modal closes. A bare JSON body swapped into #profile-result read as
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ func getTemplateUserWithTheme(c *echo.Context, cfg *Config) (templates.User, err
|
|||||||
LastName: utils.PgTextString(userDB.LastName),
|
LastName: utils.PgTextString(userDB.LastName),
|
||||||
CreatedAt: userDB.CreatedAt.Time,
|
CreatedAt: userDB.CreatedAt.Time,
|
||||||
DefaultAudioSpeed: float64(userDB.DefaultAudioSpeed),
|
DefaultAudioSpeed: float64(userDB.DefaultAudioSpeed),
|
||||||
|
KeepScreenAwake: userDB.KeepScreenAwake,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ func registerReaderRoutes(cfg *Config) {
|
|||||||
TotalCharacters: mediaItem.TotalCharacters.Int64,
|
TotalCharacters: mediaItem.TotalCharacters.Int64,
|
||||||
EstimatedPages: sync.EstimatedPages(mediaItem.TotalCharacters.Int64),
|
EstimatedPages: sync.EstimatedPages(mediaItem.TotalCharacters.Int64),
|
||||||
TreatAsComic: handlers.ShouldTreatAsComic(libraryWithType.TypeName, mediaItem.FormatGroup),
|
TreatAsComic: handlers.ShouldTreatAsComic(libraryWithType.TypeName, mediaItem.FormatGroup),
|
||||||
|
KeepScreenAwake: user.KeepScreenAwake,
|
||||||
}
|
}
|
||||||
// Render template
|
// Render template
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|||||||
@@ -87,6 +87,16 @@ templ ProfileForm(user User, actionURL string, requireCurrentPassword bool, show
|
|||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs font-semibold uppercase tracking-wide mb-1.5" style="color: var(--text-secondary)">Keep Screen Awake</label>
|
||||||
|
<select
|
||||||
|
name="keep_screen_awake"
|
||||||
|
class="input"
|
||||||
|
>
|
||||||
|
<option value="true" selected?={ user.KeepScreenAwake }>On</option>
|
||||||
|
<option value="false" selected?={ !user.KeepScreenAwake }>Off</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-xs font-semibold uppercase tracking-wide mb-1.5" style="color: var(--text-secondary)">Timezone</label>
|
<label class="block text-xs font-semibold uppercase tracking-wide mb-1.5" style="color: var(--text-secondary)">Timezone</label>
|
||||||
<select
|
<select
|
||||||
|
|||||||
@@ -228,277 +228,297 @@ func ProfileForm(user User, actionURL string, requireCurrentPassword bool, showR
|
|||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</select></div><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Timezone</label> <select name=\"timezone\" class=\"input\"><option value=\"UTC\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</select></div><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Keep Screen Awake</label> <select name=\"keep_screen_awake\" class=\"input\"><option value=\"true\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "UTC" {
|
if user.KeepScreenAwake {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, ">UTC (UTC+0)</option> <option value=\"Pacific/Honolulu\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, ">On</option> <option value=\"false\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Pacific/Honolulu" {
|
if !user.KeepScreenAwake {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, ">Hawaii (UTC-10)</option> <option value=\"America/Anchorage\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, ">Off</option></select></div><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Timezone</label> <select name=\"timezone\" class=\"input\"><option value=\"UTC\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "America/Anchorage" {
|
if user.Timezone == "UTC" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, ">Alaska (UTC-9/-8)</option> <option value=\"America/Los_Angeles\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, ">UTC (UTC+0)</option> <option value=\"Pacific/Honolulu\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "America/Los_Angeles" {
|
if user.Timezone == "Pacific/Honolulu" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, ">Pacific (UTC-8/-7)</option> <option value=\"America/Denver\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, ">Hawaii (UTC-10)</option> <option value=\"America/Anchorage\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "America/Denver" {
|
if user.Timezone == "America/Anchorage" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, ">Mountain (UTC-7/-6)</option> <option value=\"America/Phoenix\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, ">Alaska (UTC-9/-8)</option> <option value=\"America/Los_Angeles\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "America/Phoenix" {
|
if user.Timezone == "America/Los_Angeles" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, ">Mountain - no DST (UTC-7)</option> <option value=\"America/Chicago\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, ">Pacific (UTC-8/-7)</option> <option value=\"America/Denver\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "America/Chicago" {
|
if user.Timezone == "America/Denver" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, ">Central (UTC-6/-5)</option> <option value=\"America/New_York\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, ">Mountain (UTC-7/-6)</option> <option value=\"America/Phoenix\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "America/New_York" {
|
if user.Timezone == "America/Phoenix" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, ">Eastern (UTC-5/-4)</option> <option value=\"America/Sao_Paulo\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, ">Mountain - no DST (UTC-7)</option> <option value=\"America/Chicago\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "America/Sao_Paulo" {
|
if user.Timezone == "America/Chicago" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, ">Brasilia (UTC-3/-2)</option> <option value=\"Europe/London\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, ">Central (UTC-6/-5)</option> <option value=\"America/New_York\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Europe/London" {
|
if user.Timezone == "America/New_York" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, ">British (UTC+0/+1)</option> <option value=\"Europe/Paris\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, ">Eastern (UTC-5/-4)</option> <option value=\"America/Sao_Paulo\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Europe/Paris" {
|
if user.Timezone == "America/Sao_Paulo" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, ">Central European (UTC+1/+2)</option> <option value=\"Europe/Helsinki\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, ">Brasilia (UTC-3/-2)</option> <option value=\"Europe/London\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Europe/Helsinki" {
|
if user.Timezone == "Europe/London" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, ">Eastern European (UTC+2/+3)</option> <option value=\"Europe/Moscow\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, ">British (UTC+0/+1)</option> <option value=\"Europe/Paris\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Europe/Moscow" {
|
if user.Timezone == "Europe/Paris" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, ">Moscow (UTC+3)</option> <option value=\"Asia/Tehran\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, ">Central European (UTC+1/+2)</option> <option value=\"Europe/Helsinki\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Asia/Tehran" {
|
if user.Timezone == "Europe/Helsinki" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, ">Iran (UTC+3:30)</option> <option value=\"Asia/Dubai\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, ">Eastern European (UTC+2/+3)</option> <option value=\"Europe/Moscow\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Asia/Dubai" {
|
if user.Timezone == "Europe/Moscow" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, ">Gulf (UTC+4)</option> <option value=\"Asia/Karachi\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, ">Moscow (UTC+3)</option> <option value=\"Asia/Tehran\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Asia/Karachi" {
|
if user.Timezone == "Asia/Tehran" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, ">Pakistan (UTC+5)</option> <option value=\"Asia/Kolkata\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, ">Iran (UTC+3:30)</option> <option value=\"Asia/Dubai\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Asia/Kolkata" {
|
if user.Timezone == "Asia/Dubai" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, ">India (UTC+5:30)</option> <option value=\"Asia/Dhaka\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, ">Gulf (UTC+4)</option> <option value=\"Asia/Karachi\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Asia/Dhaka" {
|
if user.Timezone == "Asia/Karachi" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, ">Bangladesh (UTC+6)</option> <option value=\"Asia/Bangkok\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, ">Pakistan (UTC+5)</option> <option value=\"Asia/Kolkata\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Asia/Bangkok" {
|
if user.Timezone == "Asia/Kolkata" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, ">Indochina (UTC+7)</option> <option value=\"Asia/Shanghai\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, ">India (UTC+5:30)</option> <option value=\"Asia/Dhaka\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Asia/Shanghai" {
|
if user.Timezone == "Asia/Dhaka" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, ">China (UTC+8)</option> <option value=\"Asia/Tokyo\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, ">Bangladesh (UTC+6)</option> <option value=\"Asia/Bangkok\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Asia/Tokyo" {
|
if user.Timezone == "Asia/Bangkok" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, ">Japan/Korea (UTC+9)</option> <option value=\"Australia/Darwin\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, ">Indochina (UTC+7)</option> <option value=\"Asia/Shanghai\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Australia/Darwin" {
|
if user.Timezone == "Asia/Shanghai" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, ">Australian Central (UTC+9:30)</option> <option value=\"Australia/Sydney\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, ">China (UTC+8)</option> <option value=\"Asia/Tokyo\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Australia/Sydney" {
|
if user.Timezone == "Asia/Tokyo" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, ">Australian Eastern (UTC+10/+11)</option> <option value=\"Pacific/Auckland\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, ">Japan/Korea (UTC+9)</option> <option value=\"Australia/Darwin\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Timezone == "Pacific/Auckland" {
|
if user.Timezone == "Australia/Darwin" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, ">New Zealand (UTC+12/+13)</option></select></div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, ">Australian Central (UTC+9:30)</option> <option value=\"Australia/Sydney\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if user.Timezone == "Australia/Sydney" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, " selected")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, ">Australian Eastern (UTC+10/+11)</option> <option value=\"Pacific/Auckland\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if user.Timezone == "Pacific/Auckland" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, " selected")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, ">New Zealand (UTC+12/+13)</option></select></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if showRoleField {
|
if showRoleField {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "<div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Role</label> <select name=\"role\" class=\"input\"><option value=\"user\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "<div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Role</label> <select name=\"role\" class=\"input\"><option value=\"user\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Role == "user" {
|
if user.Role == "user" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, ">User</option> <option value=\"admin\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, ">User</option> <option value=\"admin\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if user.Role == "admin" {
|
if user.Role == "admin" {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, " selected")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, " selected")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, ">Admin</option></select></div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, ">Admin</option></select></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "</div></div><div x-data=\"profilePasswordForm\"><div class=\"flex items-center gap-2 mb-4\">")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "</div></div><div x-data=\"profilePasswordForm\"><div class=\"flex items-center gap-2 mb-4\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@@ -506,12 +526,12 @@ func ProfileForm(user User, actionURL string, requireCurrentPassword bool, showR
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "<h3 class=\"text-lg font-semibold\" style=\"color: var(--text-primary)\">Change Password</h3></div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "<h3 class=\"text-lg font-semibold\" style=\"color: var(--text-primary)\">Change Password</h3></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if requireCurrentPassword {
|
if requireCurrentPassword {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "<div class=\"space-y-4 max-w-md\"><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Current Password</label> <input type=\"password\" name=\"current_password\" class=\"input\"></div><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">New Password</label> <input type=\"password\" id=\"new-password\" name=\"new_password\" class=\"input\"></div><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Confirm New Password</label> <input type=\"password\" id=\"confirm-password\" name=\"confirm_password\" class=\"input\"></div><div id=\"password-requirements\" class=\"text-xs\"></div><button type=\"button\" id=\"password-submit-btn\" hx-put=\"/api/auth/password\" hx-target=\"#password-result\" hx-swap=\"innerHTML\" hx-include=\"closest form\" class=\"btn btn-primary\">")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "<div class=\"space-y-4 max-w-md\"><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Current Password</label> <input type=\"password\" name=\"current_password\" class=\"input\"></div><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">New Password</label> <input type=\"password\" id=\"new-password\" name=\"new_password\" class=\"input\"></div><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Confirm New Password</label> <input type=\"password\" id=\"confirm-password\" name=\"confirm_password\" class=\"input\"></div><div id=\"password-requirements\" class=\"text-xs\"></div><button type=\"button\" id=\"password-submit-btn\" hx-put=\"/api/auth/password\" hx-target=\"#password-result\" hx-swap=\"innerHTML\" hx-include=\"closest form\" class=\"btn btn-primary\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@@ -519,25 +539,25 @@ func ProfileForm(user User, actionURL string, requireCurrentPassword bool, showR
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "Update Password</button><div id=\"password-result\" class=\"mt-2\"></div></div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "Update Password</button><div id=\"password-result\" class=\"mt-2\"></div></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "<p class=\"text-sm italic mb-4\" style=\"color: var(--text-secondary);\">As an admin, you can change this user's password without knowing their current password.</p><div class=\"space-y-4 max-w-md\"><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">New Password</label> <input type=\"password\" id=\"new-password\" name=\"new_password\" class=\"input\"></div><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Confirm New Password</label> <input type=\"password\" id=\"confirm-password\" name=\"confirm_password\" class=\"input\"></div><div id=\"password-requirements\" class=\"text-xs\"></div><button type=\"button\" id=\"password-submit-btn\" hx-put=\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "<p class=\"text-sm italic mb-4\" style=\"color: var(--text-secondary);\">As an admin, you can change this user's password without knowing their current password.</p><div class=\"space-y-4 max-w-md\"><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">New Password</label> <input type=\"password\" id=\"new-password\" name=\"new_password\" class=\"input\"></div><div><label class=\"block text-xs font-semibold uppercase tracking-wide mb-1.5\" style=\"color: var(--text-secondary)\">Confirm New Password</label> <input type=\"password\" id=\"confirm-password\" name=\"confirm_password\" class=\"input\"></div><div id=\"password-requirements\" class=\"text-xs\"></div><button type=\"button\" id=\"password-submit-btn\" hx-put=\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var9 string
|
var templ_7745c5c3_Var9 string
|
||||||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.ResolveAttributeValue("/api/auth/password/" + user.ID)
|
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.ResolveAttributeValue("/api/auth/password/" + user.ID)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/profile_form.templ`, Line: 211, Col: 46}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/profile_form.templ`, Line: 221, Col: 46}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "\" hx-target=\"#password-result\" hx-swap=\"innerHTML\" hx-include=\"closest form\" class=\"btn btn-primary\">")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "\" hx-target=\"#password-result\" hx-swap=\"innerHTML\" hx-include=\"closest form\" class=\"btn btn-primary\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@@ -545,22 +565,22 @@ func ProfileForm(user User, actionURL string, requireCurrentPassword bool, showR
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "Reset Password</button><div id=\"password-result\" class=\"mt-2\"></div></div>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "Reset Password</button><div id=\"password-result\" class=\"mt-2\"></div></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "</div><div class=\"flex justify-end gap-3 pt-6 border-t\" style=\"border-color: var(--border);\">")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 92, "</div><div class=\"flex justify-end gap-3 pt-6 border-t\" style=\"border-color: var(--border);\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
if showCancelButton {
|
if showCancelButton {
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "<button type=\"button\" @click=\"closeProfileModal()\" class=\"btn btn-secondary\">Cancel</button> ")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 93, "<button type=\"button\" @click=\"closeProfileModal()\" class=\"btn btn-secondary\">Cancel</button> ")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 90, "<button type=\"submit\" class=\"btn btn-primary\">")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 94, "<button type=\"submit\" class=\"btn btn-primary\">")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@@ -568,7 +588,7 @@ func ProfileForm(user User, actionURL string, requireCurrentPassword bool, showR
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 91, "Save Changes</button></div><div id=\"profile-result\" class=\"mt-2\"></div></form>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 95, "Save Changes</button></div><div id=\"profile-result\" class=\"mt-2\"></div></form>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ type User struct {
|
|||||||
// User-level default audiobook playback speed (plan §8); 0 means
|
// User-level default audiobook playback speed (plan §8); 0 means
|
||||||
// "unset" and renders as the 1× option.
|
// "unset" and renders as the 1× option.
|
||||||
DefaultAudioSpeed float64
|
DefaultAudioSpeed float64
|
||||||
|
// Whether the web reader/player should hold a Screen Wake Lock.
|
||||||
|
KeepScreenAwake bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SpeedOption is one entry of the default-playback-speed select — the
|
// SpeedOption is one entry of the default-playback-speed select — the
|
||||||
@@ -289,6 +291,9 @@ type ReaderMetadata struct {
|
|||||||
// TreatAsComic: fixed-layout item in a comics/manga library gets
|
// TreatAsComic: fixed-layout item in a comics/manga library gets
|
||||||
// comic reader treatment (bookmarks only — no highlights, no search).
|
// comic reader treatment (bookmarks only — no highlights, no search).
|
||||||
TreatAsComic bool `json:"treat_as_comic"`
|
TreatAsComic bool `json:"treat_as_comic"`
|
||||||
|
// KeepScreenAwake: user preference — the reader holds a Screen Wake
|
||||||
|
// Lock while open when true.
|
||||||
|
KeepScreenAwake bool `json:"keep_screen_awake"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReadingProgress struct {
|
type ReadingProgress struct {
|
||||||
|
|||||||
Reference in new issue
Block a user