fix(5.10): logo ROMFAST in stanga header (ca romfast.ro) + tooltip tema doar numele temei

- US-012c: logo .brand-logo mutat in header-left (32px, aliniat stanga); env badge mutat sub titlu in header-center; titlul ramane centrat; responsiv pastrat.
- US-014b: title-ul butonului de tema = doar numele temei curente (Light/Dark/Petrol/Auto), fara enumerarea ciclului; aria-label informativ + aria-live pastrate (a11y).

Regresie 896 passed, 1 skipped, 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-06-25 20:37:00 +00:00
parent 5a964a1a8d
commit 074b6e7c8a
3 changed files with 96 additions and 53 deletions

View File

@@ -121,15 +121,20 @@
desktop neschimbat (fara regresie). Orice regula mobila noua reutilizeaza 767px. */
body { margin:0; font:15px/1.5 "IBM Plex Sans",system-ui,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
background:var(--bg); color:var(--ink); -webkit-font-smoothing:antialiased; }
/* US-012 (PRD 5.10): grila 3 coloane — stanga (env badge echilibru) | centru (titlu+wordmark) | dreapta (controale). */
/* US-012c (PRD 5.10): grila 3 coloane — stanga (logo ROMFAST) | centru (titlu+env) | dreapta (controale). */
header { padding:16px 24px; border-bottom:1px solid var(--line);
display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:8px; }
.header-left { display:flex; align-items:center; }
.header-center { display:flex; flex-direction:column; align-items:center; text-align:center; }
.header-right { display:flex; align-items:center; justify-content:flex-end; gap:8px; }
/* US-012b: logo PNG ROMFAST sub titlu — 28px inaltime, centrat, fara filtre de culoare.
Logo are fundal transparent + culori proprii (ROM rosu + FAST albastru) -> ok pe toate temele. */
.brand-logo { height:28px; width:auto; display:block; margin:3px auto 0; }
/* US-012c: logo PNG ROMFAST in header-left (brand top-left ca pe romfast.ro).
32px inaltime — usor mai mare decat in header-center (28px) pentru vizibilitate ca brand anchor.
margin:0 — aliniat stanga, NU centrat (era `margin:3px auto 0` cand era sub titlu).
Logo transparent: ok pe dark/light/petrol fara filtre de culoare. */
.brand-logo { height:32px; width:auto; display:block; margin:0; }
/* Env badge mic sub titlu in header-center (US-012c): nu mai echilibreaza optic dreapta
(logo-ul face asta), ci identifica mediul langa titlu. Pastrat mic, color:var(--muted). */
.header-center .env { font-size:11px; margin-top:2px; }
header h1 { font-size:20px; margin:0; font-weight:700; letter-spacing:-.01em; }
header .env { font-size:12px; color:var(--muted); border:1px solid var(--line); padding:2px 8px; border-radius:99px; }
main { padding:24px; max-width:1100px; margin:0 auto; }
@@ -342,8 +347,8 @@
.detaliu-actiuni-jos button { width:100%; }
/* Header + nav colapsate: pe mobil trece de la grid la flex wrap.
Randul 1: [env badge stanga] [controale dreapta] (margin-left:auto pe .header-right).
Randul 2: [titlu + wordmark centrat, full-width]. Fara scroll orizontal, tinte >=44px. */
Randul 1: [logo ROMFAST stanga] [controale dreapta] (margin-left:auto pe .header-right).
Randul 2: [titlu + env mic centrat, full-width]. Fara scroll orizontal, tinte >=44px. */
header { display:flex; flex-wrap:wrap; padding:12px 16px; gap:8px; align-items:center; }
.header-left { order:0; flex:0 0 auto; }
.header-center { order:2; width:100%; text-align:center; }
@@ -412,18 +417,19 @@
</style>
</head>
<body>
{# US-012 (PRD 5.10): grila 3 coloane — stanga (env badge) | centru (titlu+wordmark) | dreapta (controale). #}
{# US-012c (PRD 5.10): grila 3 coloane — stanga (logo ROMFAST) | centru (titlu+env) | dreapta (controale).
Decizie env badge: mutat in header-center sub <h1> (mic, color:muted) — nu suprapune logo-ul
si pastreaza centrarea optica a titlului in coloana auto. #}
<header>
{# Celula stanga: badge env (test/prod) — echilibru optic fata de controalele din dreapta #}
{# Celula stanga: logo ROMFAST (US-012c: brand top-left ca pe romfast.ro) #}
<div class="header-left">
<span class="env">{{ rar_env }}</span>
{# US-012b/c: logo PNG real, 288x175 RGBA transparent — ok pe toate temele fara filtre. #}
<img src="/static/romfast_logo.png" alt="ROMFAST" class="brand-logo">
</div>
{# Celula centru: titlu + wordmark 'by ROMFAST' #}
{# Celula centru: titlu + badge env mic (US-012c: env mutat din header-left aici) #}
<div class="header-center">
<h1>Gateway RAR AUTOPASS</h1>
{# US-012b (decizie user): logo PNG real in loc de wordmark text.
288x175 RGBA fundal transparent — lizibil pe light/dark/petrol fara filtre. #}
<img src="/static/romfast_logo.png" alt="ROMFAST" class="brand-logo">
<span class="env">{{ rar_env }}</span>
</div>
{# Celula dreapta: comutator tema + versiune + meniu cont #}
<div class="header-right">
@@ -487,8 +493,6 @@
var ICONS = {light:'&#9728;', dark:'&#9790;', petrol:'&#9680;', auto:'&#9689;'};
var LABELS = {light:'Light', dark:'Dark', petrol:'Petrol', auto:'Auto'};
var NEXT = {light:'Dark', dark:'Petrol', petrol:'Auto', auto:'Light'};
var TOOLTIP_CICLU = 'Ciclu: Light → Dark → Petrol → Auto';
function _stored() {
try { var v = localStorage.getItem('theme'); return (v && VALID[v]) ? v : 'auto'; } catch(e) { return 'auto'; }
}
@@ -500,7 +504,7 @@
var s = VALID[stored] ? stored : 'auto';
btn.innerHTML = ICONS[s];
btn.setAttribute('aria-label', 'Tema: ' + LABELS[s] + ', apasa pentru ' + NEXT[s]);
btn.title = 'Tema: ' + LABELS[s] + '. ' + TOOLTIP_CICLU;
btn.title = LABELS[s]; // US-014b: doar numele temei (ex. "Petrol"), nu ciclul intreg
}
function _setTheme(t) {
document.documentElement.setAttribute('data-theme', _resolved(t));

View File

@@ -1,12 +1,15 @@
"""Teste US-012 / US-012b (PRD 5.10): Header logo ROMFAST + titlu centrat.
"""Teste US-012 / US-012b / US-012c (PRD 5.10): Header logo ROMFAST + titlu centrat.
TDD: testele se scriu INAINTE de implementare (RED), dupa implementare trec (GREEN).
US-012b (decizie user): logo-ul PNG real (/static/romfast_logo.png) in loc de wordmark text.
US-012b (decizie user): logo PNG real (/static/romfast_logo.png) in loc de wordmark text.
US-012c (decizie user): logo mutat din header-center in header-left (brand top-left ca pe romfast.ro).
Decizie env badge: mutat in header-center (sub <h1>, mic, color:var(--muted)) — nu suprapune
logo-ul si pastreaza centrarea optica a titlului in coloana auto a grilei.
Testeaza:
- test_header_contine_by_romfast: <img src="/static/romfast_logo.png" alt="ROMFAST" class="brand-logo">
- test_titlu_centrat: titlul e in structura centrata (grila 3 coloane), controale la dreapta
- test_header_contine_by_romfast: img brand-logo in .header-left (NU in header-center)
- test_titlu_centrat: titlul e in .header-center (grila 3 coloane), controale la dreapta
"""
from __future__ import annotations
@@ -45,52 +48,78 @@ def _get_style(html: str) -> str:
return m.group(1)
def _get_div_content(html: str, cls: str) -> str | None:
"""Extrage continutul primului div cu clasa `cls` (non-nested)."""
m = re.search(
r'<div[^>]+class=["\'][^"\']*' + re.escape(cls) + r'[^"\']*["\'][^>]*>(.*?)</div>',
html,
re.DOTALL,
)
return m.group(1) if m else None
# ── test_header_contine_by_romfast ────────────────────────────────────────────
def test_header_contine_by_romfast(client):
"""Header contine logo-ul ROMFAST ca <img> (US-012b: decizie user — PNG real).
"""Logo-ul ROMFAST (<img class='brand-logo'>) trebuie sa fie in .header-LEFT (US-012c).
Decizie user: brand top-left ca pe romfast.ro — logo in prima celula a grilei, nu sub titlu.
Verifica:
- <img src="/static/romfast_logo.png"> prezent in header
- Atribut alt non-gol (ex. alt="ROMFAST") pentru accesibilitate
- Imaginea are clasa brand-logo (pentru stilizare CSS)
- NU mai exista spanurile text .romfast-rom / .romfast-fast (wordmark text inlocuit)
- img cu romfast_logo.png SI class brand-logo exista in interiorul .header-left
- img cu romfast_logo.png NU exista in interiorul .header-center (a fost mutat)
- alt non-gol pe img (accesibilitate)
- .header-center NU mai contine clasele .romfast-rom / .romfast-fast (curatenie)
"""
resp = client.get("/login")
assert resp.status_code == 200
header = _get_header(resp.text)
# Gaseste toate tag-urile <img> din header si cauta logo-ul
img_tags = re.findall(r'<img[^>]+>', header, re.IGNORECASE)
logo_tag = next(
(t for t in img_tags if "romfast_logo.png" in t),
# Extrage continutul .header-left si .header-center
left_content = _get_div_content(header, "header-left")
center_content = _get_div_content(header, "header-center")
assert left_content is not None, ".header-left lipseste din <header>"
assert center_content is not None, ".header-center lipseste din <header>"
# 1. img cu romfast_logo.png IN .header-left
img_tags_left = re.findall(r'<img[^>]+>', left_content, re.IGNORECASE)
logo_in_left = next(
(t for t in img_tags_left if "romfast_logo.png" in t),
None,
)
# 1. <img> cu src="/static/romfast_logo.png" prezent in header
assert logo_tag is not None, (
"<img> cu 'romfast_logo.png' negasit in header. "
"Decizie user (US-012b): logo-ul PNG real trebuie sa apara in header. "
f"Header: {header[:500]}"
assert logo_in_left is not None, (
"<img> cu 'romfast_logo.png' negasit in .header-left. "
"US-012c: logo-ul trebuie sa fie in celula STANGA a grilei (brand top-left). "
f"Continut .header-left: {left_content[:400]}"
)
# 2. Atribut alt non-gol pe imaginea logo-ului (accesibilitate)
alt_match = re.search(r'alt=["\']([^"\']+)["\']', logo_tag, re.IGNORECASE)
# 2. img cu romfast_logo.png NU mai e in .header-center
img_tags_center = re.findall(r'<img[^>]+>', center_content, re.IGNORECASE)
logo_in_center = next(
(t for t in img_tags_center if "romfast_logo.png" in t),
None,
)
assert logo_in_center is None, (
"<img> cu 'romfast_logo.png' inca e in .header-center — trebuie mutat in .header-left. "
f"Continut .header-center: {center_content[:400]}"
)
# 3. alt non-gol pe logo (accesibilitate)
alt_match = re.search(r'alt=["\']([^"\']+)["\']', logo_in_left, re.IGNORECASE)
assert alt_match and alt_match.group(1).strip(), (
"Imaginea logo lipseste atributul alt (sau e gol). "
f"Tag gasit: {logo_tag}"
"Imaginea logo din .header-left lipseste atributul alt (sau e gol). "
f"Tag gasit: {logo_in_left}"
)
# 3. Clasa brand-logo aplicata (pentru controlul inaltimii CSS)
assert "brand-logo" in logo_tag, (
"class='brand-logo' lipseste de pe <img> logo. "
f"Tag gasit: {logo_tag}"
# 4. class brand-logo prezent pe img
assert "brand-logo" in logo_in_left, (
"class='brand-logo' lipseste de pe <img> logo din .header-left. "
f"Tag gasit: {logo_in_left}"
)
# 4. Spanurile text (wordmark vechi .romfast-rom / .romfast-fast) NU mai exista
# 5. Spanurile text (wordmark vechi) NU exista in header
assert "romfast-rom" not in header and "romfast-fast" not in header, (
"Clasele .romfast-rom / .romfast-fast (wordmark text) inca prezente in header. "
"Trebuie inlocuite complet de <img> logo. "
f"Header snippet: {header[:500]}"
)
@@ -104,7 +133,7 @@ def test_titlu_centrat(client):
- CSS contine grid-template-columns cu 3 coloane pe header (1fr auto 1fr sau similar)
- Header contine un element cu clasa 'header-center' (sau similar) care contine h1
- Controalele (button tema-toggle) sunt la dreapta (in header-right sau margin-left:auto)
- Badge-ul env e in grila (header-left sau similar), nu flotant
- header-left exista (celula stanga a grilei, contine logo dupa US-012c)
"""
resp = client.get("/login")
assert resp.status_code == 200
@@ -157,7 +186,7 @@ def test_titlu_centrat(client):
f"Continut .header-right: {right_content[:300]}"
)
# 4. Badge-ul env e in header-left (nu mai e aruncat dupa h1)
# 4. header-left exista in grila (contine logo dupa US-012c)
left_div = re.search(
r'<div[^>]+class=["\'][^"\']*header-left[^"\']*["\'][^>]*>(.*?)</div>',
header,
@@ -165,11 +194,5 @@ def test_titlu_centrat(client):
)
assert left_div, (
"Element cu clasa 'header-left' negasit in <header>. "
"Badge-ul env trebuie sa fie in celula stanga a grilei (echilibru optic). "
f"Header snippet: {header[:600]}"
)
left_content = left_div.group(1)
assert 'class="env"' in left_content or "class='env'" in left_content, (
"Badge-ul .env nu e in .header-left. "
f"Continut .header-left: {left_content[:200]}"
)

View File

@@ -161,3 +161,19 @@ def test_buton_cicleaza_temele(client):
'Regiune aria-live="polite" negasita in HTML. '
"Necesara pentru a anunta schimbarea temei catre screen-readers."
)
# 6. US-014b (decizie user): title-ul vizual al butonului = DOAR numele temei, NU ciclul.
# Verificam in sursa JS ca variabila TOOLTIP_CICLU (sirul cu "Ciclu: Light → Dark → ...") nu
# mai e folosita in title. aria-label-ul informativ (curenta+urmatoarea) RAMANE neschimbat.
assert 'TOOLTIP_CICLU' not in html, (
"Variabila TOOLTIP_CICLU inca prezenta in JS — title-ul trebuie simplificat. "
"US-014b: btn.title trebuie sa fie DOAR LABELS[s] (ex. 'Light'), "
"nu 'Tema: X. Ciclu: Light -> Dark -> Petrol -> Auto'. "
"aria-label-ul informativ RAMANE neschimbat."
)
# Verifica ca JS-ul seteaza btn.title la doar LABELS[s] (fara prefix 'Tema:' sau ciclul)
assert re.search(r"btn\.title\s*=\s*LABELS\[", html), (
"btn.title nu e setat la LABELS[s] in JS. "
"US-014b: formatul asteptat: btn.title = LABELS[s] (ex. rezultat: 'Petrol'). "
"Aria-label-ul informativ ramane separat: 'Tema: X, apasa pentru Y'."
)