UI: unified design system, light/dark themes, redesigned pages and player UI
Tokens and components in styles.css, shared Ui (dialogs, toasts), icons, bottom tab bar on mobile, keyboard/gamepad navigation, library shelf with filters and conversion badges, hero game page, restyled player screens. Games list now returns per-game version counts. Adds docs/UI_DESIGN.md. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
51a7e77e56
commit
9ee3e1ff6e
27 files changed
+2399
-508
No files matched your search
@@ -3,7 +3,7 @@ from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
from PIL import Image, UnidentifiedImageError
|
||||
from sqlalchemy import exists, or_, select, true
|
||||
from sqlalchemy import exists, func, or_, select, true
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
|
||||
from app.blobs import put_bytes
|
||||
@@ -40,7 +40,7 @@ def can_edit_game(user: User, game: Game) -> bool:
|
||||
|
||||
|
||||
@router.get("", response_model=list[GameOut])
|
||||
async def list_games(user: Player, db: DB, q: str = "", tag: str = "") -> list[Game]:
|
||||
async def list_games(user: Player, db: DB, q: str = "", tag: str = "") -> list[dict]:
|
||||
stmt = select(Game).order_by(Game.title)
|
||||
if q.strip():
|
||||
pattern = f"%{q.strip()}%"
|
||||
@@ -57,7 +57,27 @@ async def list_games(user: Player, db: DB, q: str = "", tag: str = "") -> list[G
|
||||
exists().where(GameVersion.game_id == Game.id, visible_versions_filter(user))
|
||||
| (Game.created_by_id == user.id)
|
||||
)
|
||||
return list((await db.scalars(stmt.limit(500))).all())
|
||||
games = list((await db.scalars(stmt.limit(500))).all())
|
||||
counts: dict[int, dict[str, int]] = {}
|
||||
if games:
|
||||
rows = await db.execute(
|
||||
select(GameVersion.game_id, GameVersion.status, func.count())
|
||||
.where(GameVersion.game_id.in_([g.id for g in games]), visible_versions_filter(user))
|
||||
.group_by(GameVersion.game_id, GameVersion.status)
|
||||
)
|
||||
for game_id, st, n in rows:
|
||||
key = "ready" if st == "ready" else "failed" if st == "failed" else "pending"
|
||||
counts.setdefault(game_id, {}).setdefault(key, 0)
|
||||
counts[game_id][key] += n
|
||||
return [
|
||||
{
|
||||
**GameOut.model_validate(g).model_dump(),
|
||||
"ready_versions": counts.get(g.id, {}).get("ready", 0),
|
||||
"pending_versions": counts.get(g.id, {}).get("pending", 0),
|
||||
"failed_versions": counts.get(g.id, {}).get("failed", 0),
|
||||
}
|
||||
for g in games
|
||||
]
|
||||
|
||||
|
||||
@router.post("", response_model=GameOut, status_code=201)
|
||||
|
||||
Reference in new issue
Block a user