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

@ -49,7 +49,7 @@ window.Page_social = (() => {
margin-bottom:var(--space-4)">
<div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-3)">
<span style="font-size:1.6em">📱</span>
<div style="flex:1;min-width:0">
<div class="flex-1-min">
<div style="font-size:var(--text-base);font-weight:700">Social Media</div>
<div style="font-size:11px;color:var(--c-text-muted)">Luna ist dein KI-Coach</div>
</div>
@ -92,7 +92,7 @@ window.Page_social = (() => {
<div style="display:flex;justify-content:space-between;font-size:12px;
color:var(--c-text);margin-bottom:6px;font-weight:500">
<span>${s.level}</span>
${s.next_level ? `<span style="color:var(--c-text-secondary)">${s.xp_next - s.xp} XP bis ${s.next_level}</span>` : ''}
${s.next_level ? `<span class="text-secondary">${s.xp_next - s.xp} XP bis ${s.next_level}</span>` : ''}
</div>
<div style="background:var(--c-surface-2);border-radius:var(--radius-full);height:8px;overflow:hidden">
<div style="height:100%;background:linear-gradient(90deg,var(--c-primary),var(--c-primary-light));
@ -171,9 +171,9 @@ window.Page_social = (() => {
<div style="background:var(--c-surface);border-radius:var(--radius-lg);
box-shadow:var(--shadow-sm);padding:var(--space-4)">
<!-- Plattform -->
<div style="margin-bottom:var(--space-4)">
<div class="mb-4">
<div class="sm-label">Plattform</div>
<div style="display:flex;gap:var(--space-2)">
<div class="flex-gap-2">
${['both','instagram','tiktok'].map((p,i) => `
<button class="btn btn-sm sm-plat ${i===0?'btn-primary':'btn-secondary'}"
data-p="${p}" style="flex:1;min-height:36px;font-size:12px;padding:4px 8px;
@ -182,7 +182,7 @@ window.Page_social = (() => {
</div>
</div>
<!-- Format -->
<div style="margin-bottom:var(--space-4)">
<div class="mb-4">
<div class="sm-label">Format</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-2)">
${['post','reel','story','carousel'].map((f,i) => `
@ -193,7 +193,7 @@ window.Page_social = (() => {
</div>
</div>
<!-- Thema -->
<div style="margin-bottom:var(--space-4)">
<div class="mb-4">
<div class="sm-label">Thema</div>
<textarea id="sm-topic" rows="3"
placeholder="z.B. Mein Hund beim ersten Schnee 🐾"
@ -211,12 +211,12 @@ window.Page_social = (() => {
<svg class="ph-icon" aria-hidden="true" style="width:14px;height:14px"><use href="/icons/phosphor.svg#check"></use></svg> Idee übernommen prüf die Einstellungen und tippe auf <strong>Los geht's!</strong> 👇
</div>
<!-- Medien-Upload -->
<div style="margin-bottom:var(--space-4)">
<div class="mb-4">
<div class="sm-label">Foto / Video (optional)</div>
<div style="display:flex;gap:var(--space-2);flex-wrap:wrap">
<label style="cursor:pointer;flex:1">
<input type="file" id="sm-media-file" accept="image/*,video/*"
capture="environment" style="display:none">
capture="environment" class="hidden">
<span class="btn btn-secondary btn-sm"
style="min-height:40px;display:flex;align-items:center;justify-content:center;
gap:6px;font-size:12px;width:100%;border-radius:var(--radius-full)">
@ -224,7 +224,7 @@ window.Page_social = (() => {
</label>
<label style="cursor:pointer;flex:1">
<input type="file" id="sm-media-file2" accept="image/*,video/*"
style="display:none">
class="hidden">
<span class="btn btn-secondary btn-sm"
style="min-height:40px;display:flex;align-items:center;justify-content:center;
gap:6px;font-size:12px;width:100%;border-radius:var(--radius-full)">
@ -235,7 +235,7 @@ window.Page_social = (() => {
max-width:100px;max-height:100px;border-radius:var(--radius-md);overflow:hidden"></div>
</div>
<!-- Rasse Luna-Vorschlag + Suche -->
<div style="margin-bottom:var(--space-4)">
<div class="mb-4">
<div class="sm-label">Rasse (optional)</div>
${_unusedBreeds.length ? `
<div style="font-size:11px;color:var(--c-text-muted);margin-bottom:8px">
@ -265,7 +265,7 @@ window.Page_social = (() => {
</div>
<!-- Generier-Buttons als Cards -->
<div class="sm-label" style="margin-bottom:var(--space-3)">Schnell generieren</div>
<div class="sm-label mb-3">Schnell generieren</div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:var(--space-2);
margin-bottom:var(--space-3)">
<button id="sm-breed-day"
@ -319,7 +319,7 @@ window.Page_social = (() => {
border-radius:var(--radius-lg);box-shadow:var(--shadow-md)">
<svg class="ph-icon" aria-hidden="true" style="width:16px;height:16px"><use href="/icons/phosphor.svg#sparkle"></use></svg> Los geht's!
</button>
<div id="sm-gen-result" style="margin-top:var(--space-4)"></div>
<div id="sm-gen-result" class="mt-4"></div>
</div>`;
// Platform toggle
@ -405,14 +405,14 @@ window.Page_social = (() => {
try {
const ideas = await API.get('/social/suggestions');
clearInterval(sgInt);
if (!ideas?.length) { box.innerHTML = '<div style="color:var(--c-text-muted);font-size:var(--text-sm)">Keine Ideen erhalten.</div>'; return; }
if (!ideas?.length) { box.innerHTML = '<div class="text-sm-muted">Keine Ideen erhalten.</div>'; return; }
box.innerHTML = ideas.map((idea, i) => `
<div class="card sm-idea" style="padding:12px;margin-bottom:8px;cursor:pointer;
border:2px solid transparent;transition:border-color .15s;
-webkit-tap-highlight-color:transparent" data-i="${i}">
<div style="display:flex;align-items:flex-start;gap:10px">
<span style="font-size:1.4em;flex-shrink:0;line-height:1.2">${idea.emoji||'💡'}</span>
<div style="flex:1;min-width:0">
<div class="flex-1-min">
<div style="font-weight:600;font-size:var(--text-sm);margin-bottom:4px;
line-height:1.3">${_esc(idea.thema)}</div>
<div style="font-size:11px;color:var(--c-text-secondary);margin-bottom:6px;
@ -520,7 +520,7 @@ window.Page_social = (() => {
${exercises.filter(e=>e.kategorie===cat).map(e => `
<div style="background:var(--c-surface);border-radius:8px;padding:10px;
margin-bottom:6px;display:flex;align-items:center;gap:10px">
<div style="flex:1;min-width:0">
<div class="flex-1-min">
<div style="font-size:var(--text-sm);font-weight:600;color:var(--c-text)">
${_esc(e.name)}</div>
<div style="font-size:10px;color:var(--c-text-muted)">
@ -733,7 +733,7 @@ window.Page_social = (() => {
function _lunaThinking(msg = 'Denkt nach…') {
return `<div style="text-align:center;padding:var(--space-4);color:var(--c-text-muted)">
<div style="font-size:1.8em;margin-bottom:8px;animation:luna-pulse 1.5s infinite">🌙</div>
<div style="font-size:var(--text-sm)">${msg}</div>
<div class="text-sm">${msg}</div>
</div>`;
}
@ -811,7 +811,7 @@ window.Page_social = (() => {
<div style="background:var(--c-primary-subtle);
border-radius:var(--radius-lg);padding:var(--space-4);margin-bottom:var(--space-3);
border-left:4px solid var(--c-primary)">
<div style="display:flex;gap:var(--space-3)">
<div class="flex-gap-3">
<span style="font-size:1.3em;flex-shrink:0">🌙</span>
<div>
<div style="font-size:11px;font-weight:700;color:var(--c-primary);margin-bottom:4px;
@ -830,7 +830,7 @@ window.Page_social = (() => {
</div>
<!-- Aktions-Buttons: Primär volle Breite, Sekundär nebeneinander -->
<div style="margin-bottom:var(--space-4)">
<div class="mb-4">
<button class="btn btn-primary sm-posted-btn"
data-id="${data.id}"
style="width:100%;min-height:48px;font-size:var(--text-sm);
@ -838,7 +838,7 @@ window.Page_social = (() => {
background:#10b981;border-color:#10b981;box-shadow:var(--shadow-sm)">
📤 Habe ich gepostet!
</button>
<div style="display:flex;gap:var(--space-2)">
<div class="flex-gap-2">
<button class="btn btn-sm btn-secondary sm-preview-btn"
data-id="${data.id}"
style="flex:1;font-size:12px;padding:6px 10px;min-height:36px;
@ -1146,7 +1146,7 @@ window.Page_social = (() => {
: items.map(c => `
<div class="card" style="padding:12px;margin-bottom:10px">
<div style="display:flex;align-items:flex-start;gap:10px">
<div style="flex:1;min-width:0">
<div class="flex-1-min">
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:4px;
align-items:center">
<span style="font-size:11px;padding:2px 6px;border-radius:4px;
@ -1230,7 +1230,7 @@ window.Page_social = (() => {
value="${new Date().toISOString().slice(0,10)}">
</div>
<div class="form-group">
<label class="form-label">Post-Link <span style="color:var(--c-text-muted)">(optional)</span></label>
<label class="form-label">Post-Link <span class="text-muted">(optional)</span></label>
<input class="form-control" type="url" id="qp-url-${id}"
placeholder="https://www.instagram.com/p/…">
</div>`,
@ -1341,7 +1341,7 @@ window.Page_social = (() => {
box-shadow:var(--shadow-md)">
🔍 Luna, schau mal drüber!
</button>
<div id="sm-eval-res" style="margin-top:var(--space-4)"></div>
<div id="sm-eval-res" class="mt-4"></div>
</div>`;
el.querySelectorAll('.sm-ep').forEach(b => b.addEventListener('click', () => {
@ -1369,7 +1369,7 @@ window.Page_social = (() => {
${data.notes ? `<div style="background:var(--c-primary-subtle);
border-radius:var(--radius-lg);padding:var(--space-4);margin-bottom:var(--space-3);
border-left:4px solid var(--c-primary);box-shadow:var(--shadow-xs)">
<div style="display:flex;gap:var(--space-3)">
<div class="flex-gap-3">
<span style="font-size:1.3em;flex-shrink:0">🌙</span>
<div>
<div style="font-size:11px;font-weight:700;color:var(--c-primary);margin-bottom:4px;
@ -1384,7 +1384,7 @@ window.Page_social = (() => {
API.get('/social/stats').then(s => { _stats = s; });
} catch(e) {
clearInterval(interval);
res.innerHTML = `<div style="color:var(--c-danger)">😬 Fehler: ${_esc(e.message||String(e))}</div>`;
res.innerHTML = `<div class="text-danger">😬 Fehler: ${_esc(e.message||String(e))}</div>`;
} finally {
btn.disabled = false;
btn.innerHTML = '🔍 Luna, schau mal drüber!';