refactor: Standardisiere Formular-Layout (Label oben, volle Breite, linksbündig)
CSS (frontend/src/app.css): - .form-row: flex-direction column, volle Breite, margin-bottom 16px - .form-label: display block, font-weight 600, linksbündig - .form-input: width 100%, text-align left (statt right 90px), padding 10px 12px - textarea.form-input: resize vertical, min-height 80px - select.form-input: cursor pointer - .form-row--inline: Neue Variante für Ausnahmen (kurze Werte + Einheit) Dokumentation (.claude/rules/CODING_RULES.md): - Neue Regel Frontend §6: Formular-Standard (VERBINDLICH ab 2026-04-22) - Code-Beispiele für Standard-Layout (input, textarea, select) - Klare Regeln: Label = <label>, Pflichtfelder mit *, volle Breite, linksbündig - Inline-Variante nur für Ausnahmen (Zahlen mit Einheit) WICHTIG: Bestehende Formulare (Exercises, Clubs, Skills, TrainingPlanning) nutzen bereits größtenteils diese Struktur und profitieren automatisch von den CSS-Änderungen. Vorteile: - Konsistente UX über alle Formulare - Mobile-friendly (volle Breite, kein horizontal scrolling) - Bessere Lesbarkeit (Label als Überschrift) - Einfacher wartbar (ein Standard für alle) Nächster Schritt: Bestehende Formulare testen, ggf. kleine Anpassungen
This commit is contained in:
parent
7f156ba085
commit
cbb783222c
|
|
@ -78,6 +78,62 @@ style={{color: 'var(--accent)'}}
|
|||
style={{color: '#1D9E75'}}
|
||||
```
|
||||
|
||||
### 6. Formular-Standard (VERBINDLICH ab 2026-04-22)
|
||||
**Alle neuen Formulare verwenden den Standard-Stil:**
|
||||
|
||||
```jsx
|
||||
// ✅ Standard: Label oben, volle Breite, linksbündig
|
||||
<div className="form-row">
|
||||
<label className="form-label">Feldname *</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-input"
|
||||
value={formData.field}
|
||||
onChange={(e) => updateFormField('field', e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
// ✅ Textarea
|
||||
<div className="form-row">
|
||||
<label className="form-label">Beschreibung</label>
|
||||
<textarea
|
||||
className="form-input"
|
||||
rows={3}
|
||||
value={formData.description}
|
||||
onChange={(e) => updateFormField('description', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
// ✅ Select
|
||||
<div className="form-row">
|
||||
<label className="form-label">Status</label>
|
||||
<select
|
||||
className="form-input"
|
||||
value={formData.status}
|
||||
onChange={(e) => updateFormField('status', e.target.value)}
|
||||
>
|
||||
<option value="active">Aktiv</option>
|
||||
<option value="inactive">Inaktiv</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
// ❌ NICHT: Inline-Layout mit Label links
|
||||
// Nur für Ausnahmen (kurze Werte mit Einheit) nutzen:
|
||||
<div className="form-row--inline">
|
||||
<label className="form-label">Dauer</label>
|
||||
<input type="number" className="form-input" value={duration} />
|
||||
<span className="form-unit">min</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Regeln:**
|
||||
- Label ist `<label>` mit Klasse `.form-label` (nicht `<div>`)
|
||||
- Input/Textarea/Select nutzen `.form-input`
|
||||
- Volle Breite (100%), linksbündig
|
||||
- Pflichtfelder mit `*` im Label kennzeichnen
|
||||
- Inline-Variante (`.form-row--inline`) nur für Ausnahmen (Zahlen mit Einheit)
|
||||
|
||||
## Git & Deployment
|
||||
|
||||
### 1. Nie direkt auf main pushen
|
||||
|
|
|
|||
|
|
@ -113,25 +113,93 @@ body { font-family: var(--font); background: var(--bg); color: var(--text1); -we
|
|||
.delta-pos { color: var(--accent); }
|
||||
.delta-neg { color: var(--danger); }
|
||||
|
||||
/* Form */
|
||||
/* Form - STANDARD: Label oben, volle Breite, linksbündig */
|
||||
.form-section { margin-bottom: 20px; }
|
||||
.form-section-title {
|
||||
font-size: 13px; font-weight: 600; color: var(--text3);
|
||||
text-transform: uppercase; letter-spacing: 0.05em;
|
||||
margin-bottom: 10px; padding-bottom: 6px; border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.form-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--border); }
|
||||
.form-row:last-child { border-bottom: none; }
|
||||
.form-label { flex: 1; font-size: 14px; color: var(--text1); }
|
||||
.form-sub { font-size: 11px; color: var(--text3); display: block; margin-top: 1px; }
|
||||
.form-input {
|
||||
width: 90px; padding: 7px 10px; text-align: right;
|
||||
font-family: var(--font); font-size: 15px; font-weight: 500; color: var(--text1);
|
||||
background: var(--surface2); border: 1.5px solid var(--border2);
|
||||
border-radius: 8px; transition: border-color 0.15s;
|
||||
|
||||
/* Standard Form Row: Label oben, Input darunter, volle Breite */
|
||||
.form-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 8px;
|
||||
padding: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text1);
|
||||
text-align: left;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.form-sub {
|
||||
font-size: 11px;
|
||||
color: var(--text3);
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
text-align: left;
|
||||
font-family: var(--font);
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: var(--text1);
|
||||
background: var(--surface2);
|
||||
border: 1.5px solid var(--border2);
|
||||
border-radius: 8px;
|
||||
transition: border-color 0.15s;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
/* Textarea spezifisch */
|
||||
textarea.form-input {
|
||||
resize: vertical;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
/* Select spezifisch */
|
||||
select.form-input {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Inline-Variante für Ausnahmen (z.B. kurze Werte mit Einheit) */
|
||||
.form-row--inline {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.form-row--inline .form-label {
|
||||
flex: 1;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-row--inline .form-input {
|
||||
width: 90px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.form-unit {
|
||||
font-size: 12px;
|
||||
color: var(--text3);
|
||||
width: 24px;
|
||||
}
|
||||
.form-input:focus { outline: none; border-color: var(--accent); }
|
||||
.form-unit { font-size: 12px; color: var(--text3); width: 24px; }
|
||||
|
||||
/* Einstellungen Profil: Label als Überschrift oben, volle Breite, linksbündig */
|
||||
.settings-page__field {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user