"""视图层共享小构件:名次、球员单元格、排行表、比赛头部行、带球衣号的名字。 被 view_home / view_me 复用,避免重复实现。 """ from __future__ import annotations from typing import Any, Callable, Optional from shiny import ui from . import theme def _medal(rank: int) -> str: return {1: "🥇", 2: "🥈", 3: "🥉"}.get(rank, str(rank)) def _player_cell(r: dict[str, Any], me_id: Optional[int]) -> ui.Tag: parts: list[Any] = [] if r.get("jersey"): parts.append(ui.span(f'#{r["jersey"]}', class_="sde-jersey")) parts.append(r["name"]) if r["user_id"] == me_id: parts.append(ui.span("我", class_="sde-me-tag")) return ui.span(*parts) def _rank_table( rows: list[dict[str, Any]], columns: list[tuple[str, Callable[[dict, int], Any], str]], me_id: Optional[int], ) -> ui.Tag: if not rows: return ui.div("暂无数据", class_="sde-empty") head = ui.tags.tr(*[ui.tags.th(h) for h, _, _ in columns]) body = [] for i, r in enumerate(rows, 1): tds = [ui.tags.td(fn(r, i), class_=(cls or None)) for _, fn, cls in columns] body.append(ui.tags.tr(*tds, class_=("is-me" if r["user_id"] == me_id else None))) table = ui.tags.table( ui.tags.thead(head), ui.tags.tbody(*body), class_="sde-table sde-rank-table" ) return ui.div(table, class_="sde-table-wrap") def _match_top(m: dict[str, Any]) -> ui.Tag: """一场比赛的头部行:日期 · 主客 · 对手 · 比分 · 结果(flex 自动换行)。""" return ui.div( ui.span(m["date"], class_="sde-mc-date"), theme.ha_pill(m["home_away"]), ui.span(m["opponent"], class_="sde-mc-opp"), (ui.span(m["note"], class_="sde-mc-note") if m["note"] else None), ui.span(class_="sde-spacer"), ui.span(m["score_str"], class_="sde-mc-score"), theme.result_badge(m["result"]), class_="sde-mc-top", ) def _name_with_jersey(p: dict[str, Any]) -> str: return f'#{p["jersey"]} {p["display_name"]}' if p.get("jersey") else p["display_name"]