From cd10db1a72487919313747845ad7c0afa43cfb15 Mon Sep 17 00:00:00 2001 From: gitea-actions Date: Thu, 20 Aug 2026 19:37:44 +0200 Subject: [PATCH] =?UTF-8?q?tabule:=20nejnov=C4=9Bj=C5=A1=C3=AD=20kolo=20na?= =?UTF-8?q?ho=C5=99e=20a=20sou=C4=8Dty=20nad=20histori=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Po sto kolech byla tabule k ničemu: na obrazovku se vešla kola 1–14 a řádek se součty skončil asi 4 500 pixelů pod okrajem. Tabule tedy ukazovala nejstarší historii a nic z toho, co se právě děje. - kola se řadí od nejnovějšího, poslední zápis je vždy nahoře - součty se přesunuly z patičky nad historii, hned pod jména hráčů - tabule ukazuje posledních 15 kol, zbytek shrne řádka "... a dalších 85 kol"; má ukazovat stav, ne archiv, a nepřekresluje se pak zbytečně každé dvě vteřiny přes tři sta buněk - skloňování kol podle češtiny (1 kolo / 2 kola / 5 kol) Co-Authored-By: Claude Opus 5 --- static/style.css | 14 ++++++++++---- templates/_sheet.html | 31 ++++++++++++++++++----------- tests/test_web.py | 45 +++++++++++++++++++++++++++++++++++++++++++ web.py | 29 ++++++++++++++++++++++++---- 4 files changed, 100 insertions(+), 19 deletions(-) diff --git a/static/style.css b/static/style.css index c1f467b..11d567a 100644 --- a/static/style.css +++ b/static/style.css @@ -144,14 +144,20 @@ a { color: var(--ink); } text-transform: uppercase; } -.sheet tfoot td { - border-top: 2px solid var(--ink); +.sheet .totals td { + border-bottom: 2px solid var(--ink); font-size: 2.1rem; font-weight: 700; - padding-top: 0.7rem; } -.sheet tfoot .label { font-weight: 400; } +.sheet .totals .label { font-weight: 400; font-size: 0.85rem; } + +.sheet .more td { + text-align: left; + color: var(--ink-soft); + font-size: 0.85rem; + font-family: var(--font-ui); +} /* --- nuly za sebou ------------------------------------------------------- */ diff --git a/templates/_sheet.html b/templates/_sheet.html index 9b2294c..369f61a 100644 --- a/templates/_sheet.html +++ b/templates/_sheet.html @@ -16,6 +16,20 @@ {% endfor %} + + {# Součty patří nahoru: po padesáti kolech by je jinak nikdo neviděl. #} + + + Celkem + {% for name in game.names %} + + {{ totals[name]|cislo }} + {%- if streaks[name] %} {{ '✕' * streaks[name] }}{% endif %} + + {% endfor %} + + + {% for row in rows %} @@ -41,17 +55,12 @@ {% endfor %} {% endfor %} - - - - Celkem - {% for name in game.names %} - - {{ totals[name]|cislo }} - {%- if streaks[name] %} {{ '✕' * streaks[name] }}{% endif %} - - {% endfor %} + + {% if hidden %} + + … a dalších {{ hidden|kola }} - + {% endif %} + diff --git a/tests/test_web.py b/tests/test_web.py index 6a24620..b10660e 100644 --- a/tests/test_web.py +++ b/tests/test_web.py @@ -191,3 +191,48 @@ def test_sin_slavy(client): def test_sin_slavy_bez_her(client): assert "Rekordy přibudou po první hře" in text(client.get("/stats")) + + +def test_zapisnik_zacina_nejnovejsim_kolem(client): + game_id = start_game(client, "Adam", final_score=99999) + for value in (111, 222, 333): + score(client, game_id, value) + + panel = text(client.get(f"/board/{game_id}/panel")) + + assert panel.index("333") < panel.index("222") < panel.index("111") + + +def test_soucty_jsou_nad_koly(client): + game_id = start_game(client, "Adam", final_score=99999) + score(client, game_id, 450) + + panel = text(client.get(f"/board/{game_id}/panel")) + + assert panel.index("Celkem") < panel.index(">450<") + + +def test_tabule_useka_starou_historii(client): + game_id = start_game(client, "Adam", final_score=999999) + for value in range(1, 31): + score(client, game_id, value * 10) + + panel = text(client.get(f"/board/{game_id}/panel")) + + assert "a dalších 15 kol" in panel + assert "300" in panel # nejnovější kolo tam je + assert ">150<" not in panel # patnácté odspodu už ne + + +def test_kratka_hra_nic_neuseka(client): + game_id = start_game(client, "Adam", final_score=99999) + score(client, game_id, 100) + + assert "a dalších" not in text(client.get(f"/board/{game_id}/panel")) + + +@pytest.mark.parametrize("count, expected", [ + (1, "1 kolo"), (2, "2 kola"), (4, "4 kola"), (5, "5 kol"), (22, "22 kol"), +]) +def test_sklonovani_kol(count, expected): + assert web.kola(count) == expected diff --git a/web.py b/web.py index 34a4bdc..e8749ef 100644 --- a/web.py +++ b/web.py @@ -20,6 +20,10 @@ app = Flask(__name__) PORT = int(os.environ.get("DICE_PORT", 8000)) +# Kolik kol tabule ukáže. Zbytek historie je na hráčích, ne na tabuli — +# ta má ukazovat stav, ne archiv. +BOARD_ROUNDS = 15 + # --- připojení k databázi --------------------------------------------------- @@ -87,6 +91,15 @@ def datum(value: str) -> str: return f"{int(den[2])}. {int(den[1])}. {den[0]}" +@app.template_filter("kola") +def kola(count: int) -> str: + if count == 1: + return "1 kolo" + if 2 <= count <= 4: + return f"{count} kola" + return f"{count} kol" + + @app.template_filter("cislo") def cislo(value: int) -> str: """Tisíce se v češtině oddělují mezerou.""" @@ -95,8 +108,11 @@ def cislo(value: int) -> str: # --- zápisník --------------------------------------------------------------- -def scoresheet(game: Game) -> list[dict]: - """Řádky zápisníku po kolech. +def scoresheet(game: Game) -> tuple[list[dict], int]: + """Řádky zápisníku po kolech, od nejnovějšího. + + Naposledy odehrané kolo patří nahoru — po padesáti kolech by jinak bylo + to podstatné mimo obrazovku. Vrací i počet kol, která se nevešla. Tahy zapsané před posledním vynulováním se přeškrtnou — přesně tak, jak by se škrtaly na papíře. @@ -118,19 +134,24 @@ def scoresheet(game: Game) -> list[dict]: }) rows.append({"round": number, "cells": cells}) - return rows + rows.reverse() + hidden = max(0, len(rows) - BOARD_ROUNDS) + + return rows[:BOARD_ROUNDS], hidden def view(game: Game, game_id: int, row) -> dict: """Společný podklad pro zápisník i pro zadávací pohled.""" totals = game.totals() winner = row["winner_name"] if row["status"] == storage.STATUS_FINISHED else "" + rows, hidden = scoresheet(game) return { "game": game, "game_id": game_id, "row": row, "totals": totals, - "rows": scoresheet(game), + "rows": rows, + "hidden": hidden, "streaks": {name: game.zero_streak(name) for name in game.names}, "standings": game.standings(), "winner": winner,