fix(web): tema partajata landing<->aplicatie (cheie theme + 8 teme + icon unic)

- Landing foloseste aceeasi cheie localStorage 'theme' ca aplicatia (era 'lp-theme'),
  deci preferinta de tema se pastreaza intre landing si aplicatie.
- Landing capata cele 8 teme din aplicatie (adaugate light/dark/petrol; auto se
  rezolva la light/dark), aceeasi ordine de ciclare.
- Selector tema: acelasi icon FIX (SVG semicerc din landing) in ambele locuri;
  aplicatia nu mai schimba glifa per tema. Eticheta temei curente ramane.
- Init-ul selectorului din landing nu mai scrie in localStorage (nu mai suprascrie
  alegerea facuta in aplicatie la simpla vizitare).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-07-03 12:39:42 +00:00
parent f02f422560
commit cd24e75325
2 changed files with 35 additions and 22 deletions

View File

@@ -869,12 +869,14 @@
</div>
{% endif %}
{% endif %}
{# US-011 (PRD 5.16): selector tema = pill cu icon + eticheta temei curente.
Eticheta ascunsa pe <=560px via CSS. JS actualizeaza .tema-icon si #tema-label. #}
{# US-011 (PRD 5.16): selector tema = pill cu icon FIX (acelasi SVG ca landing) +
eticheta temei curente. Eticheta ascunsa pe <=560px via CSS. JS actualizeaza
doar #tema-label (iconita nu se mai schimba per tema — consecventa cu landing). #}
<button id="tema-toggle" class="tema-btn"
aria-label="Comuta tema"
title="Comuta tema">
<span class="tema-icon" aria-hidden="true">&#9728;</span>
<svg class="tema-icon" width="17" height="17" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 3a9 9 0 0 0 0 18z" fill="currentColor" stroke="none"/></svg>
<span id="tema-label">Light</span>
</button>
<span class="muted" style="font-size:var(--fs-xs);">v{{ version }}</span>
@@ -951,7 +953,7 @@
</div>
<script>
// Comutator tema ciclic (DRY E2 — PRD 5.15): config traieste intr-o singura structura
// sursa-de-adevar THEMES din care se DERIVA CYCLE/VALID/ICONS/LABELS/NEXT.
// sursa-de-adevar THEMES din care se DERIVA CYCLE/VALID/LABELS/NEXT.
// Adaugarea unei teme noi = O singura intrare in THEMES.
// Ciclu: Light->Dark->Petrol->Grafit->Cobalt->Cupru->Hartie->Auto->(inapoi la Light).
// 'auto' se rezolva la paint prin anti-FOUC (dark OS -> 'dark', light OS -> 'light').
@@ -959,21 +961,20 @@
var btn = document.getElementById('tema-toggle');
if (!btn) return;
// SURSA DE ADEVAR UNICA: adaugarea unei teme = o singura intrare aici.
// Iconite: ☀ Light | ☾ Dark | ◐ Petrol | ◑ Grafit | ◆ Cobalt | ◇ Cupru | ○ Hartie | ◉ Auto
// Iconita e FIXA (acelasi SVG ca landing) — nu se mai deriva din tema.
var THEMES = [
{id:'light', label:'Light', icon:'&#9728;'},
{id:'dark', label:'Dark', icon:'&#9790;'},
{id:'petrol', label:'Petrol', icon:'&#9680;'},
{id:'grafit', label:'Grafit', icon:'&#9681;'},
{id:'cobalt', label:'Cobalt', icon:'&#9670;'},
{id:'cupru', label:'Cupru', icon:'&#9671;'},
{id:'hartie', label:'Hartie', icon:'&#9675;'},
{id:'auto', label:'Auto', icon:'&#9689;'},
{id:'light', label:'Light'},
{id:'dark', label:'Dark'},
{id:'petrol', label:'Petrol'},
{id:'grafit', label:'Grafit'},
{id:'cobalt', label:'Cobalt'},
{id:'cupru', label:'Cupru'},
{id:'hartie', label:'Hartie'},
{id:'auto', label:'Auto'},
];
// Derivate din THEMES (nu literali separati — DRY E2):
var CYCLE = THEMES.map(function(t) { return t.id; });
var VALID = THEMES.reduce(function(a, t) { a[t.id] = 1; return a; }, {});
var ICONS = THEMES.reduce(function(a, t) { a[t.id] = t.icon; return a; }, {});
var LABELS = THEMES.reduce(function(a, t) { a[t.id] = t.label; return a; }, {});
var NEXT = (function() {
var n = {};
@@ -989,9 +990,7 @@
}
function _syncButton(stored) {
var s = VALID[stored] ? stored : 'auto';
// US-011: actualizeaza iconita si eticheta separat (btn e pill, nu se inlocuieste innerHTML intreg)
var icon = btn.querySelector('.tema-icon');
if (icon) icon.innerHTML = ICONS[s];
// US-011: iconita e fixa (nu se schimba per tema); actualizam doar eticheta.
var label = document.getElementById('tema-label');
if (label) label.textContent = LABELS[s];
btn.setAttribute('aria-label', 'Tema: ' + LABELS[s] + ', apasa pentru ' + NEXT[s]);

View File

@@ -17,6 +17,10 @@
body[data-theme="cobalt"]{--bg:#080d1c;--card:#111a33;--card2:#0b1226;--text:#e9ecfb;--sub:#8a93b8;--line:#1d2747;--line2:#161f3a;--accent:#4068FF;--hbg:rgba(8,13,28,.9);--okt:#2fd0a6;--infot:#8aa0ff;--errt:#f06a7a;--mut:#5a6390}
body[data-theme="cupru"]{--bg:#15110b;--card:#211a12;--card2:#15110b;--text:#efe6d6;--sub:#a89a85;--line:#36291c;--line2:#281e14;--accent:#D98A3D;--hbg:rgba(21,17,11,.9);--okt:#67b98c;--infot:#dfa45c;--errt:#e2685a;--mut:#6d5f4c}
body[data-theme="hartie"]{--bg:#f3efe6;--card:#fffdf7;--card2:#f3efe6;--text:#1e1a13;--sub:#6a6052;--line:#e2dccc;--line2:#ece6d9;--accent:#1F5FBF;--hbg:rgba(255,253,247,.92);--okt:#1c7d5d;--infot:#1F5FBF;--errt:#bd463c;--mut:#9a8f7d}
/* Teme aliniate cu aplicatia (base.html) — acelasi set de 8; 'auto' se rezolva la light/dark. */
body[data-theme="light"]{--bg:#f5f7fa;--card:#ffffff;--card2:#f5f7fa;--text:#1a1d24;--sub:#5c6473;--line:#e2e5ea;--line2:#eaedf2;--accent:#1F66C9;--hbg:rgba(245,247,250,.9);--okt:#15803d;--infot:#1F66C9;--errt:#dc2626;--mut:#8a92a0}
body[data-theme="dark"]{--bg:#0f1218;--card:#181c24;--card2:#0f1218;--text:#e6e9ef;--sub:#8b93a7;--line:#262b36;--line2:#1f2530;--accent:#2E74D6;--hbg:rgba(15,18,24,.88);--okt:#2FBF8F;--infot:#6ea2ec;--errt:#E05D5D;--mut:#5c6473}
body[data-theme="petrol"]{--bg:#0e1416;--card:#161e20;--card2:#0e1416;--text:#e6e9ef;--sub:#8b93a7;--line:#232c2e;--line2:#1c2426;--accent:#0E7C7B;--hbg:rgba(14,20,22,.9);--okt:#2FBF8F;--infot:#3fb9b6;--errt:#E05D5D;--mut:#5c6473}
.page{width:100%;max-width:1280px;margin:0 auto;background:var(--bg,#0f1218);color:var(--text,#e6e9ef);overflow:hidden;}
a{text-decoration:none;}
input[type=range]{-webkit-appearance:none;appearance:none;background:transparent;}
@@ -53,7 +57,7 @@
</style>
</head>
<body data-theme="grafit">
<script>try{var _t=localStorage.getItem('lp-theme');if(_t&&['grafit','cobalt','cupru','hartie'].indexOf(_t)>=0)document.body.setAttribute('data-theme',_t);}catch(e){}</script>
<script>try{var _t=localStorage.getItem('theme');var _V={light:1,dark:1,petrol:1,grafit:1,cobalt:1,cupru:1,hartie:1,auto:1};if(_t&&_V[_t]){var _r=_t==='auto'?(window.matchMedia('(prefers-color-scheme: light)').matches?'light':'dark'):_t;document.body.setAttribute('data-theme',_r);}}catch(e){}</script>
<main class="page">
<!-- HEADER -->
<div class="lp-header" style="position:sticky;top:0;display:flex;align-items:center;justify-content:space-between;padding:0 40px;height:68px;background:var(--hbg,rgba(15,18,24,.88));backdrop-filter:blur(8px);border-bottom:1px solid var(--line,#262b36);z-index:5;">
@@ -406,11 +410,21 @@
</main>
<script>
(function(){
var THEMES=[['grafit','Grafit'],['cobalt','Cobalt'],['cupru','Cupru'],['hartie','Hârtie']];
// Acelasi set de 8 teme, aceeasi ordine si aceeasi cheie 'theme' ca aplicatia
// (base.html), ca preferinta sa se pastreze intre landing si aplicatie.
// 'auto' urmeaza sistemul (prefers-color-scheme).
var THEMES=[['light','Light'],['dark','Dark'],['petrol','Petrol'],['grafit','Grafit'],['cobalt','Cobalt'],['cupru','Cupru'],['hartie','Hârtie'],['auto','Auto']];
var VALID=THEMES.reduce(function(a,t){a[t[0]]=1;return a;},{});
var body=document.body;
function curIndex(){var t=body.getAttribute('data-theme');for(var i=0;i<THEMES.length;i++){if(THEMES[i][0]===t)return i;}return 0;}
function applyTheme(i){i=((i%THEMES.length)+THEMES.length)%THEMES.length;body.setAttribute('data-theme',THEMES[i][0]);var l=document.getElementById('theme-label');if(l)l.textContent=THEMES[i][1];try{localStorage.setItem('lp-theme',THEMES[i][0]);}catch(e){}}
applyTheme(curIndex());
function resolve(id){return id==='auto'?(window.matchMedia('(prefers-color-scheme: light)').matches?'light':'dark'):id;}
function storedId(){try{var v=localStorage.getItem('theme');return (v&&VALID[v])?v:null;}catch(e){return null;}}
function curId(){return storedId()||body.getAttribute('data-theme')||'grafit';}
function curIndex(){var t=curId();for(var i=0;i<THEMES.length;i++){if(THEMES[i][0]===t)return i;}return 3;}
function label(i){var l=document.getElementById('theme-label');if(l)l.textContent=THEMES[i][1];}
function applyTheme(i){i=((i%THEMES.length)+THEMES.length)%THEMES.length;var id=THEMES[i][0];body.setAttribute('data-theme',resolve(id));label(i);try{localStorage.setItem('theme',id);}catch(e){}}
// Init: sincronizeaza eticheta + data-theme din starea stocata, FARA a scrie in localStorage
// (altfel simpla vizitare a landing-ului ar suprascrie alegerea facuta in aplicatie).
(function(){var i=curIndex();body.setAttribute('data-theme',resolve(THEMES[i][0]));label(i);})();
// style-hover: framework-ul de design folosea atributul style-hover; il aplicam la hover.
function parseStyle(str){var o={};str.split(';').forEach(function(p){var idx=p.indexOf(':');if(idx>0)o[p.slice(0,idx).trim()]=p.slice(idx+1).trim();});return o;}