feat: Update capture page layout for improved responsiveness and organization across multiple screens
All checks were successful
Deploy Development / deploy (push) Successful in 46s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s

This commit is contained in:
Lars 2026-04-05 10:14:07 +02:00
parent 630a3de88a
commit a639d08037
14 changed files with 45 additions and 18 deletions

View File

@ -3,7 +3,7 @@
> **Gitea:** [#30 Responsive UI](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues/30) > **Gitea:** [#30 Responsive UI](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues/30)
> **Spec:** `.claude/docs/functional/RESPONSIVE_UI.md` > **Spec:** `.claude/docs/functional/RESPONSIVE_UI.md`
> **Breakpoint:** `<1024px` = Mobile (Bottom-Nav, bestehendes Verhalten), `≥1024px` = Desktop (Sidebar 220px) > **Breakpoint:** `<1024px` = Mobile (Bottom-Nav, bestehendes Verhalten), `≥1024px` = Desktop (Sidebar 220px)
> **Letzte Plan-Aktualisierung:** 2026-04-04 (P5) > **Letzte Plan-Aktualisierung:** 2026-04-04 (P6; P7 Admin bewusst offen)
--- ---
@ -17,8 +17,8 @@
| P3 | Dashboard (Desktop-Grid) | ☑ erledigt | 4-spaltige Kennzahlen; Begrüßung; Ernährung/Aktivität 2-spaltig | | P3 | Dashboard (Desktop-Grid) | ☑ erledigt | 4-spaltige Kennzahlen; Begrüßung; Ernährung/Aktivität 2-spaltig |
| P4 | Verlauf (Tabs links / Content rechts) | ☑ erledigt | `History.jsx` + `.history-*` in `app.css`; Tab-State bei `location.state.tab` | | P4 | Verlauf (Tabs links / Content rechts) | ☑ erledigt | `History.jsx` + `.history-*` in `app.css`; Tab-State bei `location.state.tab` |
| P5 | Analyse (Prompts links / Ergebnis rechts) | ☑ erledigt | `Analysis.jsx` + `.analysis-split*` in `app.css` | | P5 | Analyse (Prompts links / Ergebnis rechts) | ☑ erledigt | `Analysis.jsx` + `.analysis-split*` in `app.css` |
| P6 | Erfassung / Capture & Formularseiten | ☐ pending | | | P6 | Erfassung / Capture & Formularseiten | ☑ erledigt | `.capture-page` / `.capture-page--wide` in `app.css`; CaptureHub, Wizard, GewichtZiele, Guide, Ernährung/Aktivität/Vital/Schlaf breiter |
| P7 | Admin & restliche Vollbreiten-Seiten | ☐ pending | | | P7 | Admin & restliche Vollbreiten-Seiten | ⏸ Konzeption | Layout nach Abstimmung; nicht mit P6 mitgezogen |
| P8 | Abschluss, Regression, Spec-Pflege | ☐ pending | | | P8 | Abschluss, Regression, Spec-Pflege | ☐ pending | |
**Status-Legende:** `☐ pending` · `◐ in Arbeit` · `☑ erledigt` · `⏸ blockiert` **Status-Legende:** `☐ pending` · `◐ in Arbeit` · `☑ erledigt` · `⏸ blockiert`

View File

@ -344,6 +344,25 @@ body { font-family: var(--font); background: var(--bg); color: var(--text1); -we
} }
} }
/* P6 / RESPONSIVE_UI §5.4 Erfassung: Desktop zentriert; data-lastige Seiten etwas breiter */
.capture-page {
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
@media (min-width: 1024px) {
.capture-page {
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.capture-page--wide {
max-width: 900px;
}
}
.muted { color: var(--text3); font-size: 13px; } .muted { color: var(--text3); font-size: 13px; }
.empty-state { text-align: center; padding: 48px 16px; color: var(--text3); } .empty-state { text-align: center; padding: 48px 16px; color: var(--text3); }
.empty-state h3 { font-size: 16px; color: var(--text2); margin-bottom: 6px; } .empty-state h3 { font-size: 16px; color: var(--text2); margin-bottom: 6px; }

View File

@ -254,7 +254,7 @@ export default function ActivityPage() {
} }
return ( return (
<div> <div className="capture-page capture-page--wide">
<h1 className="page-title">Aktivität</h1> <h1 className="page-title">Aktivität</h1>
<div className="tabs" style={{overflowX:'auto',flexWrap:'nowrap'}}> <div className="tabs" style={{overflowX:'auto',flexWrap:'nowrap'}}>

View File

@ -160,7 +160,7 @@ export default function CaliperScreen() {
} }
return ( return (
<div> <div className="capture-page">
<div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:16}}> <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:16}}>
<h1 className="page-title" style={{margin:0}}>Caliper</h1> <h1 className="page-title" style={{margin:0}}>Caliper</h1>
<button className="btn btn-secondary" style={{fontSize:12,padding:'6px 10px'}} onClick={()=>nav('/guide')}> <button className="btn btn-secondary" style={{fontSize:12,padding:'6px 10px'}} onClick={()=>nav('/guide')}>

View File

@ -85,7 +85,7 @@ const ENTRIES = [
export default function CaptureHub() { export default function CaptureHub() {
const nav = useNavigate() const nav = useNavigate()
return ( return (
<div> <div className="capture-page">
<h1 className="page-title">Erfassen</h1> <h1 className="page-title">Erfassen</h1>
<div style={{display:'flex',flexDirection:'column',gap:10}}> <div style={{display:'flex',flexDirection:'column',gap:10}}>
{ENTRIES.map(e => ( {ENTRIES.map(e => (

View File

@ -85,7 +85,7 @@ export default function CircumScreen() {
} }
return ( return (
<div> <div className="capture-page">
<div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:16}}> <div style={{display:'flex',alignItems:'center',justifyContent:'space-between',marginBottom:16}}>
<h1 className="page-title" style={{margin:0}}>Umfänge</h1> <h1 className="page-title" style={{margin:0}}>Umfänge</h1>
<button className="btn btn-secondary" style={{fontSize:12,padding:'6px 10px'}} onClick={()=>nav('/guide')}> <button className="btn btn-secondary" style={{fontSize:12,padding:'6px 10px'}} onClick={()=>nav('/guide')}>

View File

@ -117,7 +117,7 @@ export default function CustomGoalsPage() {
} }
return ( return (
<div style={{ paddingBottom: 80 }}> <div className="capture-page" style={{ paddingBottom: 80 }}>
{/* Header */} {/* Header */}
<div style={{ <div style={{
background: 'linear-gradient(135deg, var(--accent) 0%, var(--accent-dark) 100%)', background: 'linear-gradient(135deg, var(--accent) 0%, var(--accent-dark) 100%)',

View File

@ -36,7 +36,7 @@ export default function GuidePage() {
const methodPoints = CALIPER_METHODS[caliperMethod]?.points_m || [] const methodPoints = CALIPER_METHODS[caliperMethod]?.points_m || []
return ( return (
<div> <div className="capture-page">
<h1 className="page-title">Messanleitung</h1> <h1 className="page-title">Messanleitung</h1>
<div className="tabs"> <div className="tabs">

View File

@ -344,7 +344,7 @@ export default function MeasureWizard() {
if (done) { if (done) {
return ( return (
<div style={{display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center', <div className="capture-page" style={{display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',
minHeight:'60vh',gap:16,textAlign:'center'}}> minHeight:'60vh',gap:16,textAlign:'center'}}>
<div style={{fontSize:48}}></div> <div style={{fontSize:48}}></div>
<h2 style={{fontSize:20,fontWeight:700}}>Gespeichert!</h2> <h2 style={{fontSize:20,fontWeight:700}}>Gespeichert!</h2>
@ -361,11 +361,19 @@ export default function MeasureWizard() {
) )
} }
if (mode === 'circum') return <CircumWizard onDone={()=>setDone(true)} onCancel={()=>setMode(null)}/> if (mode === 'circum') return (
if (mode === 'caliper') return <CaliperWizard onDone={()=>setDone(true)} onCancel={()=>setMode(null)} profile={profile}/> <div className="capture-page">
<CircumWizard onDone={()=>setDone(true)} onCancel={()=>setMode(null)}/>
</div>
)
if (mode === 'caliper') return (
<div className="capture-page">
<CaliperWizard onDone={()=>setDone(true)} onCancel={()=>setMode(null)} profile={profile}/>
</div>
)
return ( return (
<div> <div className="capture-page">
<h1 className="page-title">Assistent</h1> <h1 className="page-title">Assistent</h1>
<p style={{fontSize:13,color:'var(--text2)',marginBottom:20,lineHeight:1.6}}> <p style={{fontSize:13,color:'var(--text2)',marginBottom:20,lineHeight:1.6}}>
Der Assistent führt dich Schritt für Schritt durch die Messung mit Anleitung für jeden Messpunkt. Der Assistent führt dich Schritt für Schritt durch die Messung mit Anleitung für jeden Messpunkt.

View File

@ -802,7 +802,7 @@ export default function NutritionPage() {
useEffect(() => { load() }, []) useEffect(() => { load() }, [])
return ( return (
<div> <div className="capture-page capture-page--wide">
<h1 className="page-title">Ernährung</h1> <h1 className="page-title">Ernährung</h1>
{/* Input Method Tabs */} {/* Input Method Tabs */}

View File

@ -177,7 +177,7 @@ export default function RestDaysPage() {
} }
return ( return (
<div> <div className="capture-page">
<h1 className="page-title">Ruhetage</h1> <h1 className="page-title">Ruhetage</h1>
{/* Toast Notification */} {/* Toast Notification */}

View File

@ -142,7 +142,7 @@ export default function SleepPage() {
} }
return ( return (
<div style={{ padding: '16px 16px 80px' }}> <div className="capture-page capture-page--wide" style={{ padding: '16px 16px 80px' }}>
{/* Toast Notification */} {/* Toast Notification */}
{toast && ( {toast && (
<div style={{ <div style={{

View File

@ -1064,7 +1064,7 @@ export default function VitalsPage() {
} }
return ( return (
<div> <div className="capture-page capture-page--wide">
<h1 className="page-title">Vitalwerte</h1> <h1 className="page-title">Vitalwerte</h1>
<div className="tabs" style={{ overflowX: 'auto', flexWrap: 'nowrap' }}> <div className="tabs" style={{ overflowX: 'auto', flexWrap: 'nowrap' }}>

View File

@ -78,7 +78,7 @@ export default function WeightScreen() {
const avgAll = weights.length ? Math.round(weights.reduce((a,b)=>a+b,0)/weights.length*10)/10 : null const avgAll = weights.length ? Math.round(weights.reduce((a,b)=>a+b,0)/weights.length*10)/10 : null
return ( return (
<div> <div className="capture-page">
<h1 className="page-title">Gewicht</h1> <h1 className="page-title">Gewicht</h1>
{/* Eingabe */} {/* Eingabe */}