feat(web): theme import/export, more themable colors, hideable local/ical calendars
Theme: - Export/import themes via UI as <date>_<time>.theme (JSON, readable keys, link to THEME.md). Import is partial-aware: only present params are written (server accepts partial); prompts before importing files with unknown params. - Dynamic favicon + theme-color tinted to the primary colour on load/save. - New themable colours: general hover-highlight, day hover/selected/bg, today background, plus two unified sidebar action-icon colours (inactive/active) covering bell, hide, delete and read-only icons. - All new colours are per-setting syncable; documented in THEME.md. UX: - Styled confirm dialog (#modal-confirm) replaces window.confirm() for calendar delete and account disconnect. - Birthday/local calendars and iCal subscriptions can now be hidden from the sidebar via Settings (new sidebar_hidden column + hide toggle). Backend: additive nullable columns + idempotent migrations for user_settings colours and local_calendars/ical_subscriptions.sidebar_hidden. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,13 @@ DEFAULT_SYNC = {
|
||||
"cache_months": False,
|
||||
"month_view_paged": False,
|
||||
"surface_color": False,
|
||||
"hover_highlight_color": True,
|
||||
"icon_inactive_color": True,
|
||||
"icon_active_color": True,
|
||||
"day_hover_color": True,
|
||||
"day_selected_color": True,
|
||||
"day_bg_color": True,
|
||||
"today_bg_color": True,
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +79,13 @@ class SettingsUpdate(BaseModel):
|
||||
line_color: Optional[str] = None
|
||||
bg_color: Optional[str] = None
|
||||
surface_color: Optional[str] = None
|
||||
hover_highlight_color: Optional[str] = None
|
||||
icon_inactive_color: Optional[str] = None
|
||||
icon_active_color: Optional[str] = None
|
||||
day_hover_color: Optional[str] = None
|
||||
day_selected_color: Optional[str] = None
|
||||
day_bg_color: Optional[str] = None
|
||||
today_bg_color: Optional[str] = None
|
||||
private_event_visibility: Optional[str] = None
|
||||
group_visible_calendar_id: Optional[int] = None
|
||||
default_reminder_minutes: Optional[int] = None # null = off
|
||||
@@ -100,6 +114,13 @@ def _settings_dict(s: models.UserSettings) -> dict:
|
||||
"line_color": s.line_color,
|
||||
"bg_color": s.bg_color,
|
||||
"surface_color": s.surface_color,
|
||||
"hover_highlight_color": s.hover_highlight_color,
|
||||
"icon_inactive_color": s.icon_inactive_color,
|
||||
"icon_active_color": s.icon_active_color,
|
||||
"day_hover_color": s.day_hover_color,
|
||||
"day_selected_color": s.day_selected_color,
|
||||
"day_bg_color": s.day_bg_color,
|
||||
"today_bg_color": s.today_bg_color,
|
||||
"private_event_visibility": s.private_event_visibility or "busy",
|
||||
"group_visible_calendar_id": s.group_visible_calendar_id,
|
||||
"default_reminder_minutes": s.default_reminder_minutes,
|
||||
@@ -165,7 +186,7 @@ def update_settings(
|
||||
# For these three override colours, an explicit null is meaningful
|
||||
# ("reset to default") and must be persisted as NULL. All other fields
|
||||
# keep the previous behaviour where a null/missing value is ignored.
|
||||
NULLABLE_OVERRIDES = {"text_color", "line_color", "bg_color", "surface_color", "group_visible_calendar_id", "default_reminder_minutes", "default_event_duration_minutes", "share_calendar_icon"}
|
||||
NULLABLE_OVERRIDES = {"text_color", "line_color", "bg_color", "surface_color", "hover_highlight_color", "icon_inactive_color", "icon_active_color", "day_hover_color", "day_selected_color", "day_bg_color", "today_bg_color", "group_visible_calendar_id", "default_reminder_minutes", "default_event_duration_minutes", "share_calendar_icon"}
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
|
||||
# Merge sync-flag overrides into the stored account-wide JSON map. Only known
|
||||
|
||||
Reference in New Issue
Block a user