From 096d18ac640aebccc30fbec684e68bb5edc3152e Mon Sep 17 00:00:00 2001 From: mwiegand Date: Tue, 12 May 2026 23:17:51 +0200 Subject: [PATCH] feat(live-state): use Steam avatarfull (184x184), downscale in CSS 64x64 avatarmedium looked soft on high-DPI screens. Switching the GetPlayerSummaries field to avatarfull (184x184) and constraining display size to 64px via .live-state .avatar gives sharp rendering on retina/4k panels at the cost of a slightly larger CDN fetch (still hot-linked, so no proxying cost). Also adds the previously-missing CSS for the live-state player grid: avatar+name+meta arranged in a tight 2-column grid per card, link spans the avatar+name so the meta stays non-interactive. Co-Authored-By: Claude Sonnet 4.6 --- l4d2web/services/steam_users.py | 4 +-- l4d2web/static/css/components.css | 58 +++++++++++++++++++++++++++++++ l4d2web/tests/test_steam_users.py | 6 ++-- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/l4d2web/services/steam_users.py b/l4d2web/services/steam_users.py index 074daef..5bb058b 100644 --- a/l4d2web/services/steam_users.py +++ b/l4d2web/services/steam_users.py @@ -44,7 +44,7 @@ def _session_get(url: str, params: dict, timeout: float = REQUEST_TIMEOUT_SECOND class SteamProfile: steam_id_64: str persona_name: str - avatar_url: str + avatar_url: str # avatarfull (184x184); CSS downscales so high-DPI stays crisp def fetch_profiles_batch( @@ -70,7 +70,7 @@ def fetch_profiles_batch( SteamProfile( steam_id_64=str(p["steamid"]), persona_name=str(p.get("personaname", "")), - avatar_url=str(p.get("avatarmedium", "")), + avatar_url=str(p.get("avatarfull", "")), ) ) return out diff --git a/l4d2web/static/css/components.css b/l4d2web/static/css/components.css index d3406b0..2f70949 100644 --- a/l4d2web/static/css/components.css +++ b/l4d2web/static/css/components.css @@ -854,3 +854,61 @@ dialog.modal.modal-wide { font-size: 0.8em; color: var(--color-muted); } + +/* Live-state panel — current + recent players on the server detail page. + Avatars are fetched as the 184x184 Steam "full" size and downscaled in + CSS so high-DPI screens render crisply. */ + +.live-state .player-grid { + list-style: none; + padding: 0; + margin: var(--space-m) 0 0; + display: flex; + flex-wrap: wrap; + gap: var(--space-m); +} + +.live-state .player-card { + display: grid; + grid-template-columns: auto 1fr; + column-gap: var(--space-s); + align-items: center; +} + +.live-state .player-link { + display: contents; + color: inherit; + text-decoration: none; +} + +.live-state .player-link:hover .name { + text-decoration: underline; +} + +.live-state .avatar { + width: 64px; + height: 64px; + border-radius: var(--radius-s); + object-fit: cover; + grid-row: 1 / span 2; +} + +.live-state .avatar.placeholder { + display: inline-block; + background: color-mix(in srgb, var(--color-muted) 30%, transparent); +} + +.live-state .name { + grid-column: 2; + font-weight: 600; +} + +.live-state .meta { + grid-column: 2; + color: var(--color-muted); + font-size: 0.85em; +} + +.live-state .server-live-summary { + font-size: 1.05em; +} diff --git a/l4d2web/tests/test_steam_users.py b/l4d2web/tests/test_steam_users.py index a2460d7..302aee8 100644 --- a/l4d2web/tests/test_steam_users.py +++ b/l4d2web/tests/test_steam_users.py @@ -32,7 +32,7 @@ def test_fetch_profiles_batch_builds_correct_request(monkeypatch: pytest.MonkeyP captured: list = [] body = {"response": {"players": [ {"steamid": "76561197960828710", "personaname": "Alice", - "avatarmedium": "https://avatars.../alice_medium.jpg"}, + "avatarfull": "https://avatars.../alice_full.jpg"}, ]}} _patched_get(monkeypatch, body, captured) @@ -47,7 +47,7 @@ def test_fetch_profiles_batch_builds_correct_request(monkeypatch: pytest.MonkeyP p = profiles[0] assert p.steam_id_64 == "76561197960828710" assert p.persona_name == "Alice" - assert p.avatar_url.endswith("alice_medium.jpg") + assert p.avatar_url.endswith("alice_full.jpg") def test_fetch_profiles_batch_skips_private_or_missing(monkeypatch: pytest.MonkeyPatch) -> None: @@ -55,7 +55,7 @@ def test_fetch_profiles_batch_skips_private_or_missing(monkeypatch: pytest.Monke # should accept that and return only what's there. body = {"response": {"players": [ {"steamid": "76561197960828710", "personaname": "Alice", - "avatarmedium": "https://avatars.../alice_medium.jpg"}, + "avatarfull": "https://avatars.../alice_full.jpg"}, ]}} _patched_get(monkeypatch, body, []) profiles = steam_users.fetch_profiles_batch(