chore(wip): consolidation intermédiaire multi-tickets (sprints Statistiques, UI, Bug resolution, Serveur-client)
Regroupe l'état de travail en cours réalisé dans un même worktree sur plusieurs tickets/sprints (#85, #136, #145, #155-160, #162-164), mélangeant des tickets QA et inProgress. Ne constitue pas une feature terminée : commit de sauvegarde avant triage/split par ticket en branches feature/* dédiées. Exclut les dossiers d'environnement de build locaux et le heap dump parasite (.gitignore mis à jour). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
174
.ideai/tickets/91/assets/build_mockup.py
Normal file
174
.ideai/tickets/91/assets/build_mockup.py
Normal file
@ -0,0 +1,174 @@
|
||||
import base64
|
||||
import pathlib
|
||||
import textwrap
|
||||
|
||||
root = pathlib.Path("/home/anthony/Documents/Projects/GameTime")
|
||||
anton = base64.b64encode((root / "assets/fonts/Anton-Regular.ttf").read_bytes()).decode()
|
||||
archivo = base64.b64encode((root / "assets/fonts/Archivo-Variable.ttf").read_bytes()).decode()
|
||||
|
||||
# Palette Court Blazer (theme sombre)
|
||||
GOLD = "#C9A24A"
|
||||
CRIMSON = "#D72638"
|
||||
BG = "#080A12"
|
||||
SURFACE = "#141824"
|
||||
TEXT = "#F5F1E8"
|
||||
TEXT_SECONDARY = "#A7ADBA"
|
||||
BORDER = "#242A3A"
|
||||
|
||||
TILE_W = 260
|
||||
TILE_H = 330
|
||||
FACE_D = 216
|
||||
GAP = 24
|
||||
N = 5
|
||||
WIDTH = N * TILE_W + (N + 1) * GAP
|
||||
HEIGHT = TILE_H + 190
|
||||
|
||||
def watch_face(cx, cy, r, label_top, big_value, big_color, status_line, button_label, button_style, disconnected=False):
|
||||
parts = []
|
||||
# bezel
|
||||
parts.append(f'<circle cx="{cx}" cy="{cy}" r="{r+6}" fill="{BORDER}"/>')
|
||||
parts.append(f'<circle cx="{cx}" cy="{cy}" r="{r}" fill="{SURFACE}"/>')
|
||||
# crimson top accent arc (clin d\'oeil liseré 2px des cartes cles, adapte en arc sur le bezel interne)
|
||||
if not disconnected:
|
||||
parts.append(f'<path d="M {cx - r*0.55} {cy - r*0.82} A {r} {r} 0 0 1 {cx + r*0.55} {cy - r*0.82}" '
|
||||
f'fill="none" stroke="{CRIMSON}" stroke-width="3" stroke-linecap="round"/>')
|
||||
else:
|
||||
parts.append(f'<path d="M {cx - r*0.55} {cy - r*0.82} A {r} {r} 0 0 1 {cx + r*0.55} {cy - r*0.82}" '
|
||||
f'fill="none" stroke="{BORDER}" stroke-width="3" stroke-linecap="round"/>')
|
||||
|
||||
top_y = cy - r * 0.44
|
||||
value_y = cy - r * 0.02
|
||||
status_y = cy + r * 0.30
|
||||
btn_cy = cy + r * 0.62
|
||||
btn_w = r * 1.5
|
||||
btn_h = 40
|
||||
|
||||
label_color = TEXT_SECONDARY if not disconnected else "#5A6072"
|
||||
parts.append(
|
||||
f'<text x="{cx}" y="{top_y}" text-anchor="middle" font-family="Archivo" font-weight="600" '
|
||||
f'font-size="13" letter-spacing="1" fill="{label_color}">{label_top}</text>'
|
||||
)
|
||||
|
||||
parts.append(
|
||||
f'<text x="{cx}" y="{value_y}" text-anchor="middle" font-family="Anton" font-size="56" '
|
||||
f'fill="{big_color}">{big_value}</text>'
|
||||
)
|
||||
|
||||
parts.append(
|
||||
f'<text x="{cx}" y="{status_y}" text-anchor="middle" font-family="Archivo" font-weight="400" '
|
||||
f'font-size="13.5" fill="{TEXT_SECONDARY if not disconnected else "#5A6072"}">{status_line}</text>'
|
||||
)
|
||||
|
||||
# button pill
|
||||
bx = cx - btn_w / 2
|
||||
by = btn_cy - btn_h / 2
|
||||
if button_style == "gold_fill":
|
||||
fill, stroke, textcol = GOLD, GOLD, "#1A1206"
|
||||
elif button_style == "crimson_outline":
|
||||
fill, stroke, textcol = "none", CRIMSON, CRIMSON
|
||||
elif button_style == "crimson_fill":
|
||||
fill, stroke, textcol = CRIMSON, CRIMSON, TEXT
|
||||
else: # muted outline (disconnected)
|
||||
fill, stroke, textcol = "none", "#3A4152", TEXT_SECONDARY
|
||||
|
||||
parts.append(
|
||||
f'<rect x="{bx:.1f}" y="{by:.1f}" width="{btn_w:.1f}" height="{btn_h}" rx="{btn_h/2:.1f}" '
|
||||
f'fill="{fill}" stroke="{stroke}" stroke-width="1.6"/>'
|
||||
)
|
||||
parts.append(
|
||||
f'<text x="{cx}" y="{btn_cy + 5}" text-anchor="middle" font-family="Archivo" font-weight="700" '
|
||||
f'font-size="15" fill="{textcol}">{button_label}</text>'
|
||||
)
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
states = [
|
||||
dict(
|
||||
caption="1 — Pret a demarrer",
|
||||
sub="Etape / exercice sous chrono, pas encore lance",
|
||||
label_top="DRIBBLE COMBO",
|
||||
big_value="00:00",
|
||||
big_color=TEXT_SECONDARY,
|
||||
status_line="Serie 2 / 4",
|
||||
button_label="Demarrer",
|
||||
button_style="gold_fill",
|
||||
),
|
||||
dict(
|
||||
caption="2 — Chrono en cours",
|
||||
sub="Le chrono actif tourne (exercice ou etape)",
|
||||
label_top="DRIBBLE COMBO",
|
||||
big_value="00:23",
|
||||
big_color=GOLD,
|
||||
status_line="Serie 2 / 4 - en cours",
|
||||
button_label="Arreter",
|
||||
button_style="crimson_outline",
|
||||
),
|
||||
dict(
|
||||
caption="3 — Chrono en pause",
|
||||
sub="Chrono arrete avec valeur, reprise possible",
|
||||
label_top="DRIBBLE COMBO",
|
||||
big_value="00:23",
|
||||
big_color=GOLD,
|
||||
status_line="Serie 2 / 4 - en pause",
|
||||
button_label="Reprendre",
|
||||
button_style="gold_fill",
|
||||
),
|
||||
dict(
|
||||
caption="4 — Pas de chrono actif",
|
||||
sub="Serie reps/score libre : l'action utile est de conclure",
|
||||
label_top="TIRS EN SUSPENSION",
|
||||
big_value="2 / 4",
|
||||
big_color=GOLD,
|
||||
status_line="Serie en cours",
|
||||
button_label="Terminer la serie",
|
||||
button_style="crimson_fill",
|
||||
),
|
||||
dict(
|
||||
caption="5 — Montre non synchronisee",
|
||||
sub="Perte de liaison : dernier etat connu, sans alarmer",
|
||||
label_top="DERNIERE DONNEE RECUE",
|
||||
big_value="00:23",
|
||||
big_color="#5A6072",
|
||||
status_line="Non synchronisee",
|
||||
button_label="Reessayer",
|
||||
button_style="muted",
|
||||
disconnected=True,
|
||||
),
|
||||
]
|
||||
|
||||
svg_parts = [
|
||||
f'<svg xmlns="http://www.w3.org/2000/svg" width="{WIDTH}" height="{HEIGHT}" viewBox="0 0 {WIDTH} {HEIGHT}">',
|
||||
'<defs><style>',
|
||||
f'@font-face {{ font-family: "Anton"; src: url(data:font/ttf;base64,{anton}) format("truetype"); }}',
|
||||
f'@font-face {{ font-family: "Archivo"; src: url(data:font/ttf;base64,{archivo}) format("truetype"); }}',
|
||||
'</style></defs>',
|
||||
f'<rect x="0" y="0" width="{WIDTH}" height="{HEIGHT}" fill="{BG}"/>',
|
||||
f'<text x="{WIDTH/2}" y="46" text-anchor="middle" font-family="Anton" font-size="30" fill="{TEXT}">GAMETIME — MONTRE SYNCHRONISEE</text>',
|
||||
f'<text x="{WIDTH/2}" y="72" text-anchor="middle" font-family="Archivo" font-weight="400" font-size="15" fill="{TEXT_SECONDARY}">Ecran unique, bouton contextuel unique — style Court Blazer</text>',
|
||||
]
|
||||
|
||||
for i, st in enumerate(states):
|
||||
cx = GAP + TILE_W * i + TILE_W / 2
|
||||
cy = 96 + FACE_D / 2 + 10
|
||||
r = FACE_D / 2
|
||||
svg_parts.append(watch_face(cx, cy, r, st["label_top"], st["big_value"], st["big_color"],
|
||||
st["status_line"], st["button_label"], st["button_style"],
|
||||
disconnected=st.get("disconnected", False)))
|
||||
cap_y = cy + r + 34
|
||||
sub_y = cap_y + 22
|
||||
svg_parts.append(
|
||||
f'<text x="{cx}" y="{cap_y}" text-anchor="middle" font-family="Archivo" font-weight="700" '
|
||||
f'font-size="14" fill="{TEXT}">{st["caption"]}</text>'
|
||||
)
|
||||
lines = textwrap.wrap(st["sub"], width=30)
|
||||
for li, line in enumerate(lines):
|
||||
svg_parts.append(
|
||||
f'<text x="{cx}" y="{sub_y + li * 15}" text-anchor="middle" font-family="Archivo" font-weight="400" '
|
||||
f'font-size="11.5" fill="{TEXT_SECONDARY}">{line}</text>'
|
||||
)
|
||||
|
||||
svg_parts.append('</svg>')
|
||||
|
||||
out = root / ".ideai/tickets/91/assets/watch_screen_mockup.svg"
|
||||
out.write_text("\n".join(svg_parts), encoding="utf-8")
|
||||
print("written", out, out.stat().st_size)
|
||||
BIN
.ideai/tickets/91/assets/watch_screen_mockup.png
Normal file
BIN
.ideai/tickets/91/assets/watch_screen_mockup.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
64
.ideai/tickets/91/assets/watch_screen_mockup.svg
Normal file
64
.ideai/tickets/91/assets/watch_screen_mockup.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 1.1 MiB |
Reference in New Issue
Block a user