Add configurable surface/sidebar colour + clearer sync-icon state
- new user_settings.surface_color (nullable, device-local default, not synced): drives the web sidebar / top bar / surfaces; NULL derives from bg_color as before. Added to schema, migration, GET/PUT, NULLABLE_OVERRIDES, DEFAULT_SYNC. - web: surface colour row in the settings table; applyTheme derives the whole surface family from it - web: per-row sync icon now has real styling — ON shows the primary-tinted glyph on a pill, OFF shows a slashed, muted glyph (was previously unstyled, so synced/not-synced looked identical) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -231,6 +231,7 @@ def _migrate():
|
||||
("cache_months", "ALTER TABLE user_settings ADD COLUMN cache_months INTEGER DEFAULT 3"),
|
||||
("month_view_paged", "ALTER TABLE user_settings ADD COLUMN month_view_paged BOOLEAN DEFAULT 0"),
|
||||
("sync_flags", "ALTER TABLE user_settings ADD COLUMN sync_flags TEXT"),
|
||||
("surface_color", "ALTER TABLE user_settings ADD COLUMN surface_color VARCHAR(7)"),
|
||||
):
|
||||
try:
|
||||
conn.execute(text(ddl))
|
||||
|
||||
@@ -100,6 +100,9 @@ class UserSettings(Base):
|
||||
text_color = Column(String(7), nullable=True) # Override für --text-1 (NULL = nutze text_contrast)
|
||||
line_color = Column(String(7), nullable=True) # Override für --border (NULL = nutze line_contrast)
|
||||
bg_color = Column(String(7), nullable=True) # Override für --bg-app (NULL = Default)
|
||||
# Surface/sidebar/topbar colour (web sidebar + top bar, iOS top bar).
|
||||
# NULL = derive from bg_color. Device-local by default (not synced).
|
||||
surface_color = Column(String(7), nullable=True)
|
||||
# How this user's private events appear to other group members:
|
||||
# 'hidden' = invisible, 'busy' = anonymous busy block (default).
|
||||
private_event_visibility = Column(String(10), default="busy")
|
||||
|
||||
@@ -36,6 +36,7 @@ DEFAULT_SYNC = {
|
||||
"share_calendar_icon": False,
|
||||
"cache_months": False,
|
||||
"month_view_paged": False,
|
||||
"surface_color": False,
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +71,7 @@ class SettingsUpdate(BaseModel):
|
||||
text_color: Optional[str] = None
|
||||
line_color: Optional[str] = None
|
||||
bg_color: Optional[str] = None
|
||||
surface_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
|
||||
@@ -97,6 +99,7 @@ def _settings_dict(s: models.UserSettings) -> dict:
|
||||
"text_color": s.text_color,
|
||||
"line_color": s.line_color,
|
||||
"bg_color": s.bg_color,
|
||||
"surface_color": s.surface_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,
|
||||
@@ -162,7 +165,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", "group_visible_calendar_id", "default_reminder_minutes", "default_event_duration_minutes", "share_calendar_icon"}
|
||||
NULLABLE_OVERRIDES = {"text_color", "line_color", "bg_color", "surface_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