Manual per-calendar color choice for calendar mode
Build and push server image / build-and-push (push) Successful in 49s

Each linked person can pin one of the panel's four non-black/white
colors (Yellow/Red/Blue/Green) to their own calendar instead of relying
on calendar_render.py's old auto-cycle-by-owner-name order -- owner-only,
like adding a calendar in the first place. Colors resolve against
whichever palette a frame actually renders with (including a custom
Advanced configuration override), so a pinned "Blue" stays this frame's
actual blue. Event color bars/dots are also bigger and rounded now
across agenda/week/month views, easier to tell apart at a glance.
This commit is contained in:
2026-07-22 22:30:55 -04:00
parent ffce798754
commit 27cd6b3703
10 changed files with 190 additions and 41 deletions
+39
View File
@@ -469,6 +469,45 @@ def api_calendar_select(
return {"status": "saved", "included": row.included}
CALENDAR_COLOR_INDEX_RANGE = range(2, 6) # Yellow/Red/Blue/Green -- see PALETTE_LABELS
class CalendarColorRequest(BaseModel):
calendar_key: str
color_index: int | None # None clears the pin, reverting to auto-cycle
@router.post("/api/frames/{frame_id}/calendar-color")
def api_calendar_color(
body: CalendarColorRequest,
request: Request,
frame: Frame = Depends(require_frame_view),
db: Session = Depends(get_db),
):
"""Pins a specific panel color to one of your own included calendars
(models.FrameCalendar.color_index) -- always owner-only, unlike
calendar-select's included=False, since recoloring someone else's
calendar isn't the same kind of "I'd rather not see this" veto as
muting it. None clears the pin, reverting calendar_render.py to its
old auto-cycle-by-owner-name behavior for this calendar."""
user = require_user_api(request, db)
if body.color_index is not None and body.color_index not in CALENDAR_COLOR_INDEX_RANGE:
raise HTTPException(400, "color_index must be 2-5 (the panel's non-black/white colors)")
row = db.execute(
select(FrameCalendar).where(
FrameCalendar.frame_id == frame.id,
FrameCalendar.user_id == user.id,
FrameCalendar.calendar_key == body.calendar_key,
)
).scalar_one_or_none()
if row is None:
raise HTTPException(404, "Not included on this frame")
row.color_index = body.color_index
frame.calendar_checked_at = 0.0
db.commit()
return {"status": "saved", "color_index": row.color_index}
def _calendar_photo_inlay(frame: Frame, db: Session):
"""The photo-inlay's source image (any view now, not just agenda), or
None if inlay is off or the frame's photos-mode album isn't