fix: move TrainingTypeDistribution to History + improve admin form UX
All checks were successful
Deploy Development / deploy (push) Successful in 43s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s

UX improvements based on user feedback:

1. Move TrainingTypeDistribution from ActivityPage to History page
   - ActivityPage is for data entry, not visualization
   - History (Verlauf) shows personal development/progress
   - Chart now respects period selector (7/30/90/365 days)

2. Improve AdminTrainingTypesPage form styling
   - All input fields now full width (100%)
   - Labels changed from inline to headings above fields
   - Textareas increased from 2 to 4 rows
   - Added resize: vertical for textareas
   - Increased gap between fields from 12px to 16px
   - Follows style guide conventions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-21 16:56:35 +01:00
parent eecc00e824
commit 967d92025c
3 changed files with 40 additions and 35 deletions

View File

@ -5,7 +5,6 @@ import { api } from '../utils/api'
import UsageBadge from '../components/UsageBadge'
import TrainingTypeSelect from '../components/TrainingTypeSelect'
import BulkCategorize from '../components/BulkCategorize'
import TrainingTypeDistribution from '../components/TrainingTypeDistribution'
import dayjs from 'dayjs'
import 'dayjs/locale/de'
dayjs.locale('de')
@ -303,11 +302,6 @@ export default function ActivityPage() {
{tab==='stats' && stats && (
<div>
<div className="card section-gap">
<div className="card-title">🏋 Trainingstyp-Verteilung (30 Tage)</div>
<TrainingTypeDistribution days={30} />
</div>
{chartData.length>=2 && (
<div className="card section-gap">
<div className="card-title">Aktive Kalorien pro Tag</div>

View File

@ -169,13 +169,14 @@ export default function AdminTrainingTypesPage() {
{editingId === 'new' ? ' Neuer Trainingstyp' : '✏️ Trainingstyp bearbeiten'}
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<div>
<label className="form-label">Kategorie *</label>
<div className="form-label">Kategorie *</div>
<select
className="form-input"
value={formData.category}
onChange={e => setFormData({ ...formData, category: e.target.value })}
style={{ width: '100%' }}
>
{Object.keys(categories).map(cat => (
<option key={cat} value={cat}>
@ -186,58 +187,61 @@ export default function AdminTrainingTypesPage() {
</div>
<div>
<label className="form-label">Subkategorie</label>
<div className="form-label">Subkategorie</div>
<input
className="form-input"
value={formData.subcategory}
onChange={e => setFormData({ ...formData, subcategory: e.target.value })}
placeholder="z.B. running, hypertrophy, meditation"
style={{ width: '100%' }}
/>
<div style={{ fontSize: 11, color: 'var(--text3)', marginTop: 4 }}>
Kleingeschrieben, ohne Leerzeichen, eindeutig
</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
<div>
<label className="form-label">Name (Deutsch) *</label>
<input
className="form-input"
value={formData.name_de}
onChange={e => setFormData({ ...formData, name_de: e.target.value })}
placeholder="z.B. Laufen"
/>
</div>
<div>
<label className="form-label">Name (English) *</label>
<input
className="form-input"
value={formData.name_en}
onChange={e => setFormData({ ...formData, name_en: e.target.value })}
placeholder="e.g. Running"
/>
</div>
<div>
<div className="form-label">Name (Deutsch) *</div>
<input
className="form-input"
value={formData.name_de}
onChange={e => setFormData({ ...formData, name_de: e.target.value })}
placeholder="z.B. Laufen"
style={{ width: '100%' }}
/>
</div>
<div>
<label className="form-label">Icon (Emoji)</label>
<div className="form-label">Name (English) *</div>
<input
className="form-input"
value={formData.name_en}
onChange={e => setFormData({ ...formData, name_en: e.target.value })}
placeholder="e.g. Running"
style={{ width: '100%' }}
/>
</div>
<div>
<div className="form-label">Icon (Emoji)</div>
<input
className="form-input"
value={formData.icon}
onChange={e => setFormData({ ...formData, icon: e.target.value })}
placeholder="🏃"
maxLength={10}
style={{ width: '100%' }}
/>
</div>
<div>
<label className="form-label">Sortierung</label>
<div className="form-label">Sortierung</div>
<input
type="number"
className="form-input"
value={formData.sort_order}
onChange={e => setFormData({ ...formData, sort_order: parseInt(e.target.value) })}
style={{ width: '100%' }}
/>
<div style={{ fontSize: 11, color: 'var(--text3)', marginTop: 4 }}>
Niedrigere Zahlen werden zuerst angezeigt
@ -245,24 +249,26 @@ export default function AdminTrainingTypesPage() {
</div>
<div>
<label className="form-label">Beschreibung (Deutsch)</label>
<div className="form-label">Beschreibung (Deutsch)</div>
<textarea
className="form-input"
value={formData.description_de}
onChange={e => setFormData({ ...formData, description_de: e.target.value })}
placeholder="Optional: Beschreibung für KI-Analyse"
rows={2}
rows={4}
style={{ width: '100%', resize: 'vertical' }}
/>
</div>
<div>
<label className="form-label">Beschreibung (English)</label>
<div className="form-label">Beschreibung (English)</div>
<textarea
className="form-input"
value={formData.description_en}
onChange={e => setFormData({ ...formData, description_en: e.target.value })}
placeholder="Optional: Description for AI analysis"
rows={2}
rows={4}
style={{ width: '100%', resize: 'vertical' }}
/>
</div>

View File

@ -10,6 +10,7 @@ import { api } from '../utils/api'
import { getBfCategory } from '../utils/calc'
import { getInterpretation, getStatusColor, getStatusBg } from '../utils/interpret'
import Markdown from '../utils/Markdown'
import TrainingTypeDistribution from '../components/TrainingTypeDistribution'
import dayjs from 'dayjs'
import 'dayjs/locale/de'
dayjs.locale('de')
@ -653,6 +654,10 @@ function ActivitySection({ activities, insights, onRequest, loadingSlug, filterA
</div>
))}
</div>
<div className="card" style={{marginBottom:12}}>
<div style={{fontSize:12,fontWeight:600,color:'var(--text3)',marginBottom:8}}>Trainingstyp-Verteilung</div>
<TrainingTypeDistribution days={period === 9999 ? 365 : period} />
</div>
<div style={{marginBottom:12}}>
<div style={{fontSize:12,fontWeight:600,color:'var(--text3)',marginBottom:8}}>BEWERTUNG</div>
{actRules.map((item,i)=><RuleCard key={i} item={item}/>)}