Add theming system: custom palettes, per-user colour mode, admin appearance page

- 4 built-in themes (Default, Pastel, High Contrast, Ocean Blue) seeded as
  JSON files in /config/themes/ on startup; custom themes can be created,
  edited, and deleted via the new admin Appearance page
- All theme tokens applied via JS inline CSS properties (no hardcoded CSS blocks)
- New `color_mode` column on users table (migration dd6ad2f2c211); users can
  override the admin-set global default in Settings
- Backend: GET/PATCH /settings/appearance, full CRUD on /settings/themes
- Frontend: AdminAppearancePage with theme grid + colour pickers, SettingsPage
  replaces placeholder with mode selector, useTheme rewritten to fetch from API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curo1305
2026-04-18 01:46:17 +02:00
parent da9b911f1e
commit 608b0b7fe8
15 changed files with 1063 additions and 34 deletions
+14 -2
View File
@@ -1,10 +1,10 @@
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.deps import get_current_user
from app.models.user import User
from app.schemas.user import DashboardPrefsOut, DashboardPrefsUpdate, UserOut
from app.schemas.user import ColorModeUpdate, DashboardPrefsOut, DashboardPrefsUpdate, UserOut
router = APIRouter()
@@ -29,3 +29,15 @@ async def update_preferences(
await db.commit()
await db.refresh(current_user)
return DashboardPrefsOut(app_ids=current_user.dashboard_app_ids or [])
@router.patch("/me/color-mode", response_model=UserOut)
async def update_color_mode(
body: ColorModeUpdate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
current_user.color_mode = body.color_mode
await db.commit()
await db.refresh(current_user)
return current_user