Design-System Sprint A: utilities.css + 948 Inline-Styles → Utility-Klassen, SW by-v1102

PHASE 1 — Sofort-Cleanup ohne Risiko:
- Neue Datei utilities.css mit ~25 Klassen für häufige Kombinationen:
  * text-xs-muted, text-xs-secondary, text-sm-muted, text-sm-secondary
  * flex-gap-2/3, flex-col-gap-2/3/4, flex-center-gap-1/2/3
  * flex-between, flex-1-min, mb-1/3, mt-1/3
  * icon-xs/sm/md/lg, label-block, caption
- index.html bindet utilities.css ein
- mb-3/mt-3 ergänzt (waren in design-system.css unvollständig)

PHASE 2 — .by-tab Modifier für Vereinheitlichung:
- .by-tabs.grid (mit --tab-cols Variable für Admin/Health/etc.)
- .by-tabs.sticky (Desktop vertikale Tabs für Admin)
- .by-tabs.wrap (Zuchthunde, flex-wrap statt scroll)
- .by-tabs.separated (Sitting, mit eigenem Hintergrund + Border)

PHASE 3 — Inline-Style → Klassen-Migration (Python-Script):
- 948 Inline-Styles entfernt (5101 → 4153, -18%)
- 962 Migrationen über 47 Page-Dateien
- Top-Treffer: admin.js (180), health.js (67), dog-profile.js (67),
  litters.js (62), settings.js (61), zuchthunde.js (51)
- Patterns: text-muted, text-secondary, text-danger, text-xs-muted,
  text-sm-muted, grid-2 (Duplikat-Bug behoben!), flex-col-gap-3,
  p-3/4, mb-2/3/4, hidden, w-full, flex-1, ...
- Bewahrt bestehende class-Attribute (mergt korrekt)

Alle 19 Tests grün. Kein visueller Diff erwartet (gleiche Property-Werte).
This commit is contained in:
rene 2026-05-27 07:11:27 +02:00
parent 279f76714e
commit 459cd425f2
54 changed files with 1809 additions and 956 deletions

View file

@ -637,7 +637,7 @@ window.Page_uebungen = (() => {
</span>
`).join('');
const more = rest > 0
? `<span style="font-size:var(--text-xs);color:var(--c-text-secondary)">+${rest} weitere</span>`
? `<span class="text-xs-secondary">+${rest} weitere</span>`
: '';
badgesHtml = `<div style="display:flex;flex-wrap:wrap;gap:var(--space-2);margin-top:var(--space-2)">${pills}${more}</div>`;
}
@ -667,7 +667,7 @@ window.Page_uebungen = (() => {
el.innerHTML = `
<div style="background:var(--c-surface-2);border:1px solid var(--c-border);
border-radius:var(--radius-md);padding:var(--space-3) var(--space-4)">
<div style="font-size:var(--text-xs);color:var(--c-text-secondary)">Lade Trainingsplan</div>
<div class="text-xs-secondary">Lade Trainingsplan</div>
</div>`;
const data = await API.training.getRecommendations(dogId).catch(() => null);
@ -719,7 +719,7 @@ window.Page_uebungen = (() => {
<div style="font-size:var(--text-xs);color:var(--c-text-secondary);line-height:1.4">${_esc(r.reason)}</div>
<div style="display:flex;flex-direction:column;gap:var(--space-2);margin-top:auto;padding-top:var(--space-1)">
<div>
<span style="font-size:var(--text-xs);color:var(--c-text-secondary)">${r.suggested_reps}× empfohlen</span>
<span class="text-xs-secondary">${r.suggested_reps}× empfohlen</span>
<span style="font-size:var(--text-xs);font-weight:700;color:${trendColor};margin-left:4px">${trend}</span>
${prognose}
</div>
@ -742,7 +742,7 @@ window.Page_uebungen = (() => {
</span>
<span id="ueb-help-anchor" style="margin-left:auto"></span>
</div>
<div style="display:flex;flex-direction:column;gap:var(--space-2)">
<div class="flex-col-gap-2">
${cards.join('')}
</div>`;
if (_helpHandle) {
@ -1020,7 +1020,7 @@ window.Page_uebungen = (() => {
el.innerHTML = `<div style="padding:var(--space-6);text-align:center;color:var(--c-text-muted)">
<svg class="ph-icon" style="width:36px;height:36px;color:var(--c-primary);margin-bottom:var(--space-3)" aria-hidden="true"><use href="/icons/phosphor.svg#star"></use></svg>
<div style="font-weight:600;color:var(--c-text);margin-bottom:var(--space-2)">Ban Yaro Pro</div>
<div style="font-size:var(--text-sm)">Der KI-Trainer ist ein Pro-Feature.</div>
<div class="text-sm">Der KI-Trainer ist ein Pro-Feature.</div>
</div>`;
} else {
el.innerHTML = _renderKiTrainer();
@ -1176,15 +1176,15 @@ window.Page_uebungen = (() => {
</div>
<!-- Meta -->
<div style="display:flex;flex-wrap:wrap;gap:var(--space-2);margin-bottom:${u.beschreibung ? 'var(--space-3)' : '0'}">
<span style="font-size:var(--text-xs);color:var(--c-text-secondary)">
<span class="text-xs-secondary">
<svg class="ph-icon" style="width:12px;height:12px" aria-hidden="true"><use href="/icons/phosphor.svg#clock"></use></svg>
${_esc(u.dauer)}
</span>
<span style="font-size:var(--text-xs);color:var(--c-text-secondary)">
<span class="text-xs-secondary">
<svg class="ph-icon" style="width:12px;height:12px" aria-hidden="true"><use href="/icons/phosphor.svg#dog"></use></svg>
${_esc(u.alter)}
</span>
<span style="font-size:var(--text-xs);color:var(--c-text-secondary)">
<span class="text-xs-secondary">
<svg class="ph-icon" style="width:12px;height:12px" aria-hidden="true"><use href="/icons/phosphor.svg#package"></use></svg>
${_esc(u.material)}
</span>
@ -1366,7 +1366,7 @@ window.Page_uebungen = (() => {
<div>
<label style="display:block;font-size:var(--text-sm);font-weight:var(--weight-semibold);
color:var(--c-text);margin-bottom:var(--space-2)">Bewertung (optional)</label>
<div style="display:flex;gap:var(--space-2)">
<div class="flex-gap-2">
${[1,2,3,4,5].map(n => `
<button type="button" class="ueb-notiz-pfote" data-val="${n}"
style="font-size:1.4rem;border:1.5px solid var(--c-border);
@ -1382,7 +1382,7 @@ window.Page_uebungen = (() => {
<div>
<label style="display:block;font-size:var(--text-sm);font-weight:var(--weight-semibold);
color:var(--c-text);margin-bottom:var(--space-2)">Umgebung (optional)</label>
<div style="display:flex;gap:var(--space-2)">
<div class="flex-gap-2">
${[['🏠','zuhause'],['🌿','natur'],['🌆','stadt']].map(([emoji, val]) => `
<button type="button" class="ueb-notiz-umgebung" data-val="${val}"
style="font-size:1.2rem;border:1.5px solid var(--c-border);
@ -1398,7 +1398,7 @@ window.Page_uebungen = (() => {
<div>
<label style="display:block;font-size:var(--text-sm);font-weight:var(--weight-semibold);
color:var(--c-text);margin-bottom:var(--space-2)">Stimmung des Hundes (optional)</label>
<div style="display:flex;gap:var(--space-2)">
<div class="flex-gap-2">
${[['😊','super'],['😐','ok'],['😔','mude']].map(([emoji, val]) => `
<button type="button" class="ueb-notiz-stimmung" data-val="${val}"
style="font-size:1.2rem;border:1.5px solid var(--c-border);
@ -1829,7 +1829,7 @@ window.Page_uebungen = (() => {
<div style="font-size:var(--text-base);font-weight:var(--weight-semibold);color:var(--c-text)">
KI-Trainer
</div>
<div style="font-size:var(--text-xs);color:var(--c-text-secondary)">
<div class="text-xs-secondary">
Personalisiertes Feedback basierend auf deinen Trainingseinheiten
</div>
</div>
@ -1861,7 +1861,7 @@ window.Page_uebungen = (() => {
style="font-size:var(--text-sm);color:var(--c-text);line-height:1.7;white-space:pre-wrap"></div>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;margin-top:var(--space-3)">
<span id="ki-feedback-meta" style="font-size:var(--text-xs);color:var(--c-text-muted)"></span>
<span id="ki-feedback-meta" class="text-xs-muted"></span>
<button id="ki-regenerate"
style="font-size:var(--text-xs);padding:var(--space-1) var(--space-3);
border-radius:var(--radius-md);border:1px solid var(--c-border);
@ -1986,12 +1986,12 @@ window.Page_uebungen = (() => {
const dogId = _dogId();
if (!dogId) {
return `<div style="padding:var(--space-8);text-align:center;color:var(--c-text-muted)">
<p style="font-size:var(--text-sm)">Wähle einen Hund aus um das Protokoll zu sehen.</p>
<p class="text-sm">Wähle einen Hund aus um das Protokoll zu sehen.</p>
</div>`;
}
return `<div id="verlauf-wrap" style="padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-3)">
${_verlaufToggleHtml()}
<div id="verlauf-list" style="display:flex;flex-direction:column;gap:var(--space-2)">
<div id="verlauf-list" class="flex-col-gap-2">
<div style="text-align:center;padding:var(--space-6);color:var(--c-text-muted)">
<svg class="ph-icon" style="width:24px;height:24px;animation:spin 1s linear infinite" aria-hidden="true">
<use href="/icons/phosphor.svg#spinner-gap"></use>
@ -2008,7 +2008,7 @@ window.Page_uebungen = (() => {
const active = `background:var(--c-primary);color:#fff;border-color:var(--c-primary)`;
const inactive = `background:var(--c-surface-2);color:var(--c-text-secondary)`;
return `
<div style="display:flex;gap:var(--space-2)">
<div class="flex-gap-2">
<button id="verlauf-btn-datum" style="${btnBase};${_verlaufView==='datum'?active:inactive}">
Nach Datum
</button>
@ -2110,7 +2110,7 @@ window.Page_uebungen = (() => {
padding:var(--space-2) var(--space-3);border-radius:var(--radius-md);
background:var(--c-surface-2)">
<span style="font-size:1.2rem;flex-shrink:0;margin-top:1px">${erfolg}</span>
<div style="flex:1;min-width:0">
<div class="flex-1-min">
<div style="display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap">
<span style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
color:var(--c-text)">${_esc(s.exercise_name)}</span>
@ -2219,7 +2219,7 @@ window.Page_uebungen = (() => {
<span style="flex-shrink:0;min-width:52px">${_esc(dateLabel)}</span>
<span style="flex-shrink:0">${erfolg}</span>
<span style="flex-shrink:0">${s.erfolgsquote}%${top}</span>
<span style="flex:1;min-width:0">${s.wiederholungen}× Wdh.${stimmung ? ' ' + stimmung : ''}</span>
<span class="flex-1-min">${s.wiederholungen}× Wdh.${stimmung ? ' ' + stimmung : ''}</span>
</div>`;
}).join('');
@ -2240,7 +2240,7 @@ window.Page_uebungen = (() => {
</span>
</div>
<!-- Info -->
<div style="flex:1;min-width:0">
<div class="flex-1-min">
<div style="font-size:var(--text-sm);font-weight:var(--weight-semibold);
color:var(--c-text);line-height:1.3;
white-space:nowrap;overflow:hidden;text-overflow:ellipsis">
@ -2296,7 +2296,7 @@ window.Page_uebungen = (() => {
<div style="padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-4)">
<!-- Markerwort -->
<div class="card" style="padding:var(--space-4)">
<div class="card p-4">
<h3 style="font-size:var(--text-base);font-weight:var(--weight-semibold);
color:var(--c-text);margin:0 0 var(--space-3);display:flex;align-items:center;gap:var(--space-2)">
<svg class="ph-icon" style="width:16px;height:16px;color:var(--c-primary);flex-shrink:0" aria-hidden="true">