feat(5.15+5.14): CLOSE — fix-uri code-review + embeddings functional
5.15 (propagare design + dashboard editare) si 5.14 (mapare LLM distilata) inchise dupa /code-review high. 8 buguri reparate TDD: - HIGH modal nu se deschidea pe randul slim (base.html: trimitere-slim) - HIGH /repune trunchia prestatii (declaratie incompleta la RAR) -> iterare peste existing, codes pozitional - HIGH embeddings incarca model ~230MB degeaba pe corpus gol -> poarta has_corpus() - HIGH picker chips gol pe re-render eroare -> conn/account_id pe toate ramurile - MED obs re-derivat dupa stergere explicita -> _merge_override pastreaza obs='' - MED mapare salvata fara denumire poluă GOLD -> _record_gold_validation guard - MED typo nome_prestatie -> nume_prestatie in select /repune - MED bucketare timp +3h gresita iarna -> SQLite localtime + TZ=Europe/Bucharest Embeddings WIRE-uit functional (PRD #15, decizie user): ensure_embeddings_corpus construieste corpus din nomenclator, gated pe AUTOPASS_EMBEDDINGS_ENABLED (default off). Marime model corectata ~50MB->~230MB (estimare PRD gresita). Cleanup: hoist load_* din bucla bulk-fix; import re la top. Regresie: 1256 passed, 1 deselected (live), 0 failed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -16,13 +16,16 @@
|
||||
<script>
|
||||
// Anti-FOUC: citeste preferinta tema din localStorage inainte de primul
|
||||
// paint; seteaza data-theme pe <html> sincron, fara blink.
|
||||
// Cunoaste toate cele 4 teme: light/dark/petrol/auto. Valoare legacy/necunoscuta -> auto.
|
||||
// 'auto' se rezolva la 'light' sau 'dark' dupa prefers-color-scheme (fara blink).
|
||||
// Cunoaste TOATE cele 7+1 teme: light/dark/petrol/grafit/cobalt/cupru/hartie + auto.
|
||||
// Valori legacy (light/dark/petrol) raman valide — fara migrare fortata.
|
||||
// Valoare lipsa/necunoscuta -> auto (fallback sigur, fara blink).
|
||||
// 'auto' se rezolva la 'light' sau 'dark' dupa prefers-color-scheme (fara blink):
|
||||
// auto + dark OS -> 'dark' | auto + light OS -> 'light' (comportament existent pastrat).
|
||||
(function() {
|
||||
var VALID = {light:1, dark:1, petrol:1, auto:1};
|
||||
var VALID = {light:1, dark:1, petrol:1, grafit:1, cobalt:1, cupru:1, hartie:1, auto:1};
|
||||
try {
|
||||
var t = localStorage.getItem('theme');
|
||||
if (!t || !VALID[t]) t = 'auto'; // fallback: valoare lipsa sau legacy -> auto
|
||||
if (!t || !VALID[t]) t = 'auto'; // fallback: valoare lipsa sau necunoscuta -> auto
|
||||
if (t === 'auto') {
|
||||
t = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
||||
}
|
||||
@@ -100,16 +103,32 @@
|
||||
src: url("/static/fonts/IBMPlexMono-Regular-latin.woff2") format("woff2");
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+20AC, U+2122, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* Paleta dark (default) — accent azur ROMFAST */
|
||||
:root { --bg:#0f1218; --card:#181c24; --ink:#e6e9ef; --muted:#8b93a7; --line:#262b36;
|
||||
/* Paleta dark (default) — accent azur ROMFAST.
|
||||
--card2: fundal input/contor (= --bg, nivelul cel mai adanc).
|
||||
--line2: separator subtire (intre --bg si --line). */
|
||||
:root { --bg:#0f1218; --card:#181c24; --card2:#0f1218; --ink:#e6e9ef; --muted:#8b93a7; --line:#262b36; --line2:#1f2530;
|
||||
--ok:#2FBF8F; --warn:#E0A93B; --err:#E05D5D; --accent:#2E74D6; }
|
||||
/* Paleta light — accent azur inchis pentru contrast AA pe alb (#1F66C9: 5.51:1 pe alb) */
|
||||
[data-theme="light"] { --bg:#f5f7fa; --card:#ffffff; --ink:#1a1d24; --muted:#5c6473; --line:#e2e5ea;
|
||||
[data-theme="light"] { --bg:#f5f7fa; --card:#ffffff; --card2:#f5f7fa; --ink:#1a1d24; --muted:#5c6473; --line:#e2e5ea; --line2:#eaedf2;
|
||||
--ok:#15803d; --warn:#b45309; --err:#dc2626; --accent:#1F66C9; }
|
||||
/* Paleta Petrol — tema intunecata alternativa, accent teal #0E7C7B.
|
||||
Wordmark-ul FAST #2E74D6 coexista armonios: ambele sunt reci/saturate, contrast AA pe --card #161e20. */
|
||||
[data-theme="petrol"] { --bg:#0e1416; --card:#161e20; --ink:#e6e9ef; --muted:#8b93a7; --line:#232c2e;
|
||||
[data-theme="petrol"] { --bg:#0e1416; --card:#161e20; --card2:#0e1416; --ink:#e6e9ef; --muted:#8b93a7; --line:#232c2e; --line2:#1c2426;
|
||||
--ok:#2FBF8F; --warn:#E0A93B; --err:#E05D5D; --accent:#0E7C7B; }
|
||||
/* Paleta Grafit — similara cu dark, accent azur deschis (#6ea2ec = landing --infot).
|
||||
Distinta de dark la cererea userului (D2 PRD 5.15). */
|
||||
[data-theme="grafit"] { --bg:#0f1218; --card:#181c24; --card2:#0f1218; --ink:#e6e9ef; --muted:#8b93a7; --line:#262b36; --line2:#1f2530;
|
||||
--ok:#2FBF8F; --warn:#E0A93B; --err:#E05D5D; --accent:#6ea2ec; }
|
||||
/* Paleta Cobalt — fundal bleumarin adanc, accent albastru viu (#8aa0ff = landing --infot). */
|
||||
[data-theme="cobalt"] { --bg:#080d1c; --card:#111a33; --card2:#0b1226; --ink:#e9ecfb; --muted:#8a93b8; --line:#1d2747; --line2:#161f3a;
|
||||
--ok:#2fd0a6; --warn:#E0A93B; --err:#f06a7a; --accent:#8aa0ff; }
|
||||
/* Paleta Cupru — fundal cald ciocolata, accent chihlimbar (#dfa45c = landing --infot). */
|
||||
[data-theme="cupru"] { --bg:#15110b; --card:#211a12; --card2:#15110b; --ink:#efe6d6; --muted:#a89a85; --line:#36291c; --line2:#281e14;
|
||||
--ok:#67b98c; --warn:#c97d2e; --err:#e2685a; --accent:#dfa45c; }
|
||||
/* Paleta Hartie — fundal crem cald, accent albastru clasic (#1F5FBF = landing --infot = --accent).
|
||||
Similara cu light, distinta la cererea userului (D2 PRD 5.15). */
|
||||
[data-theme="hartie"] { --bg:#f3efe6; --card:#fffdf7; --card2:#f3efe6; --ink:#1e1a13; --muted:#6a6052; --line:#e2dccc; --line2:#ece6d9;
|
||||
--ok:#1c7d5d; --warn:#b45309; --err:#bd463c; --accent:#1F5FBF; }
|
||||
* { box-sizing:border-box; }
|
||||
/* CONVENTIE BREAKPOINT: un singur prag mobil la 768px.
|
||||
CSS custom properties NU functioneaza in `@media`, deci pragul nu poate fi o
|
||||
@@ -675,6 +694,62 @@
|
||||
.sticky-bar { padding:10px 12px; gap:10px; }
|
||||
.sticky-bar button { width:100%; min-height:44px; }
|
||||
}
|
||||
/* === SENTINEL-COMPONENTE-SLIM: inceput componente slim US-002 (PRD 5.15).
|
||||
Testele ancoreaza pe acest marker. Nu muta/sterge. === */
|
||||
/* .contor-card — card cifra contor: fundal --card2, bordura --line, radius 8px, padding 10-12px.
|
||||
Variante de culoare a cifrei prin clasele .s-* existente (verde/accent/rosu). */
|
||||
.contor-card { background:var(--card2); border:1px solid var(--line); border-radius:8px; padding:10px 12px; }
|
||||
.contor-cifra { font-size:22px; font-weight:700; line-height:1; }
|
||||
.contor-label { font-size:11px; color:var(--muted); margin-top:5px; }
|
||||
.contor-sub { font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:10px; color:var(--muted); margin-top:3px; }
|
||||
/* .lista-trimiteri-slim + .trimitere-slim — lista compacta cu separator --line2.
|
||||
Randul e clickabil (rol button), tinta min-height:44px pe mobil. */
|
||||
.lista-trimiteri-slim { list-style:none; margin:0; padding:0; }
|
||||
.trimitere-slim { display:flex; align-items:center; justify-content:space-between; gap:12px;
|
||||
padding:11px 14px; border-bottom:1px solid var(--line2); min-height:44px; cursor:pointer; }
|
||||
.trimitere-slim:last-child { border-bottom:none; }
|
||||
.trimitere-slim:hover { background:color-mix(in srgb, var(--accent) 6%, transparent); }
|
||||
.trimitere-slim:focus, .trimitere-slim:focus-visible { outline:2px solid var(--accent); outline-offset:-2px; }
|
||||
.slim-vin { font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:13px; font-weight:500; color:var(--ink); }
|
||||
.slim-meta { font-size:11px; color:var(--muted); margin-top:3px; }
|
||||
/* .camp-slim — varianta compacta camp formular: label 11px muted deasupra, input ~30px, fundal --card2.
|
||||
Mono pentru campuri VIN/odometru/nr: adauga clasa .camp-mono pe input. */
|
||||
.camp-slim { margin-bottom:8px; }
|
||||
.camp-slim label { font-size:11px; color:var(--muted); display:block; margin-bottom:4px; }
|
||||
.camp-slim input, .camp-slim textarea, .camp-slim select { background:var(--card2); height:30px; width:100%;
|
||||
padding:0 10px; border:1px solid var(--line); border-radius:6px; font:inherit; color:var(--ink); }
|
||||
.camp-slim textarea { height:auto; min-height:48px; padding:8px 10px; resize:vertical; }
|
||||
.camp-slim .camp-mono { font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:12px; }
|
||||
/* .chips + .chip — prestatii multi-select cu buton de stergere accesibil (.chip-del).
|
||||
Fundal accent 18%, font IBM Plex Mono 11px. */
|
||||
.chips { min-height:30px; display:flex; align-items:center; gap:6px; flex-wrap:wrap;
|
||||
padding:4px 8px; border:1px solid var(--line); border-radius:6px; background:var(--card2); }
|
||||
.chip { display:inline-flex; align-items:center; gap:5px; padding:3px 8px; border-radius:5px;
|
||||
background:color-mix(in srgb, var(--accent) 18%, transparent); color:var(--accent);
|
||||
font-family:"IBM Plex Mono",ui-monospace,monospace; font-size:11px; font-weight:600; }
|
||||
.chip .chip-del { background:transparent; border:none; color:inherit; opacity:.7; cursor:pointer;
|
||||
padding:0; font-size:13px; line-height:1; display:inline-flex;
|
||||
align-items:center; justify-content:center; min-width:16px; min-height:16px; }
|
||||
.chip .chip-del:hover, .chip .chip-del:focus-visible { opacity:1; }
|
||||
.chip .chip-del:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }
|
||||
/* Varianta chip warn (ex. R-ODO necesita odometruInitial) */
|
||||
.chip-warn { background:color-mix(in srgb, var(--warn) 22%, transparent); color:var(--warn); }
|
||||
/* .add-code — buton dashed pentru adaugare cod in chipbox */
|
||||
.add-code { display:inline-flex; align-items:center; height:22px; padding:0 7px; background:transparent;
|
||||
border:1px dashed color-mix(in srgb, var(--accent) 55%, var(--line));
|
||||
border-radius:5px; color:var(--accent); font:500 10px inherit; cursor:pointer; }
|
||||
.add-code:hover, .add-code:focus-visible { border-style:solid; }
|
||||
/* .op-row — rand operatie cu picker op<->cod (E4): operatie + chip cod + picker */
|
||||
.op-row { display:flex; align-items:center; justify-content:space-between; gap:10px;
|
||||
padding:8px 10px; border:1px solid var(--line); border-radius:6px;
|
||||
background:var(--card2); margin-bottom:8px; }
|
||||
.op-row-name { font-size:12px; font-weight:500; color:var(--ink); }
|
||||
.op-row-warn { border-color:color-mix(in srgb, var(--warn) 45%, var(--line)); }
|
||||
/* Mobil: tinta touch pentru trimitere-slim (deja garantata prin min-height:44px in regula de baza) */
|
||||
@media (max-width:767px) {
|
||||
.trimitere-slim { padding:12px 14px; }
|
||||
}
|
||||
/* === SENTINEL-COMPONENTE-SLIM: sfarsit componente slim US-002 === */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -749,18 +824,36 @@
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Comutator tema ciclic: click cicleaza Light->Dark->Petrol->Auto.
|
||||
// Separare init (sincronizare iconita/label) de persistenta (doar la click explicit).
|
||||
// 'auto' se rezolva la paint prin anti-FOUC; aici setam data-theme rezolvat.
|
||||
// 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.
|
||||
// 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').
|
||||
(function() {
|
||||
var btn = document.getElementById('tema-toggle');
|
||||
if (!btn) return;
|
||||
var CYCLE = ['light', 'dark', 'petrol', 'auto'];
|
||||
var VALID = {light:1, dark:1, petrol:1, auto:1};
|
||||
// Iconite per tema: ☀ Light, ☾ Dark, ◐ Petrol, ◉ Auto
|
||||
var ICONS = {light:'☀', dark:'☾', petrol:'◐', auto:'◙'};
|
||||
var LABELS = {light:'Light', dark:'Dark', petrol:'Petrol', auto:'Auto'};
|
||||
var NEXT = {light:'Dark', dark:'Petrol', petrol:'Auto', auto:'Light'};
|
||||
// SURSA DE ADEVAR UNICA: adaugarea unei teme = o singura intrare aici.
|
||||
// Iconite: ☀ Light | ☾ Dark | ◐ Petrol | ◑ Grafit | ◆ Cobalt | ◇ Cupru | ○ Hartie | ◉ Auto
|
||||
var THEMES = [
|
||||
{id:'light', label:'Light', icon:'☀'},
|
||||
{id:'dark', label:'Dark', icon:'☾'},
|
||||
{id:'petrol', label:'Petrol', icon:'◐'},
|
||||
{id:'grafit', label:'Grafit', icon:'◑'},
|
||||
{id:'cobalt', label:'Cobalt', icon:'◆'},
|
||||
{id:'cupru', label:'Cupru', icon:'◇'},
|
||||
{id:'hartie', label:'Hartie', icon:'○'},
|
||||
{id:'auto', label:'Auto', icon:'◙'},
|
||||
];
|
||||
// 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 = {};
|
||||
THEMES.forEach(function(t, i) { n[t.id] = THEMES[(i + 1) % THEMES.length].label; });
|
||||
return n;
|
||||
})();
|
||||
function _stored() {
|
||||
try { var v = localStorage.getItem('theme'); return (v && VALID[v]) ? v : 'auto'; } catch(e) { return 'auto'; }
|
||||
}
|
||||
@@ -1049,7 +1142,7 @@
|
||||
document.body.addEventListener('htmx:beforeRequest', function(evt) {
|
||||
var elt = evt.detail && evt.detail.elt;
|
||||
if (!elt || !elt.classList) return;
|
||||
if (elt.classList.contains('trimitere-row') || elt.classList.contains('btn-editeaza')) open(elt);
|
||||
if (elt.classList.contains('trimitere-row') || elt.classList.contains('trimitere-slim') || elt.classList.contains('btn-editeaza')) open(elt);
|
||||
});
|
||||
// Dupa swap-ul fragmentului (sau re-render corectie/mapare): muta focusul in modal.
|
||||
body.addEventListener('htmx:afterSettle', function() {
|
||||
@@ -1083,7 +1176,7 @@
|
||||
// Tastatura pe rand (role=button): Enter/Space deschid modalul.
|
||||
document.body.addEventListener('keydown', function(evt) {
|
||||
var t = evt.target;
|
||||
if (!(t && t.classList && t.classList.contains('trimitere-row'))) return;
|
||||
if (!(t && t.classList && (t.classList.contains('trimitere-row') || t.classList.contains('trimitere-slim')))) return;
|
||||
if (evt.key === 'Enter' || evt.key === ' ' || evt.key === 'Spacebar') {
|
||||
evt.preventDefault();
|
||||
t.click();
|
||||
|
||||
Reference in New Issue
Block a user