feat: Enhance Dashboard layout with responsive greeting and metrics display
All checks were successful
Deploy Development / deploy (push) Successful in 50s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 15s

This commit is contained in:
Lars 2026-04-05 08:03:53 +02:00
parent 7e8422cbd7
commit c2b2c71ccd
3 changed files with 90 additions and 13 deletions

View File

@ -3,7 +3,7 @@
> **Gitea:** [#30 Responsive UI](http://192.168.2.144:3000/Lars/mitai-jinkendo/issues/30)
> **Spec:** `.claude/docs/functional/RESPONSIVE_UI.md`
> **Breakpoint:** `<1024px` = Mobile (Bottom-Nav, bestehendes Verhalten), `≥1024px` = Desktop (Sidebar 220px)
> **Letzte Plan-Aktualisierung:** 2026-04-05
> **Letzte Plan-Aktualisierung:** 2026-04-06
---
@ -14,7 +14,7 @@
| P0 | Vorbereitung & Baseline | ☑ erledigt | Spec `RESPONSIVE_UI.md` bereinigt |
| P1 | App-Shell: Sidebar + Breakpoint + gemeinsame Navigation | ☑ erledigt | `DesktopSidebar`, `config/appNav.js`, Admin `/admin/*`-Highlight |
| P2 | Globales Layout & Content-Bereich (CSS) | ☑ erledigt | Desktop: Header aus, Content max 1200px; Mobile unverändert Bottom-Nav |
| P3 | Dashboard (Desktop-Grid) | ☐ pending | |
| P3 | Dashboard (Desktop-Grid) | ☑ erledigt | 4-spaltige Kennzahlen; Begrüßung; Ernährung/Aktivität 2-spaltig |
| P4 | Verlauf (Tabs links / Content rechts) | ☐ pending | |
| P5 | Analyse (Prompts links / Ergebnis rechts) | ☐ pending | |
| P6 | Erfassung / Capture & Formularseiten | ☐ pending | |

View File

@ -344,4 +344,82 @@ body { font-family: var(--font); background: var(--bg); color: var(--text1); -we
width: 100%;
box-sizing: border-box;
}
/* Dashboard (P3): Begrüßung + Kennzahlen-Zeile */
.dashboard-greeting {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 16px;
}
.dashboard-greeting__meta {
margin-top: 0 !important;
text-align: right;
}
}
/* ── Dashboard layout (Mobile baseline + Desktop im Block oben teilweise) ─ */
.dashboard-page {
width: 100%;
}
.dashboard-greeting {
margin-bottom: 16px;
}
.dashboard-stat-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
}
.dashboard-stat-card {
background: var(--surface);
border-radius: 12px;
padding: 12px 10px;
border: 1px solid var(--border);
transition: border-color 0.15s;
flex: 1 1 140px;
min-width: 80px;
box-sizing: border-box;
}
.dashboard-summary-row {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
.dashboard-summary-row > .card {
flex: 1;
min-width: 0;
}
@media (min-width: 1024px) {
.dashboard-stat-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 10px;
}
.dashboard-stat-grid .dashboard-stat-card {
flex: unset;
min-width: 0;
width: 100%;
}
.dashboard-summary-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.dashboard-summary-row > .card {
flex: unset;
}
}

View File

@ -148,11 +148,10 @@ function StatCard({ icon, label, value, unit, delta, deltaGoodWhenNeg=false, sub
const deltaColor = delta==null ? null
: (deltaGoodWhenNeg ? delta<0 : delta>0) ? 'var(--accent)' : 'var(--warn)'
return (
<div onClick={onClick} style={{
flex:1, minWidth:80, background:'var(--surface)', borderRadius:12,
padding:'12px 10px', cursor:onClick?'pointer':'default',
border:'1px solid var(--border)', transition:'border-color 0.15s',
}}
<div
className="dashboard-stat-card"
onClick={onClick}
style={{ cursor: onClick ? 'pointer' : 'default' }}
onMouseEnter={e=>onClick&&(e.currentTarget.style.borderColor='var(--accent)')}
onMouseLeave={e=>onClick&&(e.currentTarget.style.borderColor='var(--border)')}>
<div style={{fontSize:18,marginBottom:4}}>{icon}</div>
@ -321,13 +320,13 @@ export default function Dashboard() {
console.log('[Dashboard] hasAnyData=', hasAnyData, 'latestW=', !!latestW, 'latestCal=', !!latestCal, 'nutrition.length=', nutrition.length)
return (
<div>
<div className="dashboard-page">
{/* Header greeting */}
<div style={{marginBottom:16}}>
<div className="dashboard-greeting">
<h1 style={{fontSize:22,fontWeight:800,margin:0,color:'var(--text1)'}}>
Hallo, {activeProfile?.name||'Nutzer'} 👋
</h1>
<div style={{fontSize:12,color:'var(--text3)',marginTop:2}}>
<div className="dashboard-greeting__meta" style={{fontSize:12,color:'var(--text3)',marginTop:2}}>
{dayjs().format('dddd, DD. MMMM YYYY')}
{latestW && ` · Letztes Update ${dayjs(latestW.date).format('DD.MM.')}`}
</div>
@ -362,8 +361,8 @@ export default function Dashboard() {
<QuickWeight onSaved={load}/>
</div>
{/* Key metrics */}
<div style={{display:'flex',gap:8,marginBottom:16,flexWrap:'wrap'}}>
{/* Key metrics — Mobile: flex-wrap; Desktop: 4-spaltig (RESPONSIVE_UI P3) */}
<div className="dashboard-stat-grid">
<StatCard icon="⚖️" label="Gewicht" value={latestW?.weight??''} unit="kg"
delta={wDelta} deltaGoodWhenNeg={true}
sub={latestW ? dayjs(latestW.date).format('DD.MM.') : ''}
@ -451,7 +450,7 @@ export default function Dashboard() {
)}
{/* Activity + Nutrition summary row */}
<div style={{display:'flex',gap:8,marginBottom:16}}>
<div className="dashboard-summary-row">
{(avgKcal||avgProtein) && (
<div className="card" style={{flex:1,cursor:'pointer'}} onClick={()=>nav('/history',{state:{tab:'nutrition'}})}>
<div style={{fontWeight:600,fontSize:12,marginBottom:8,color:'var(--text3)'}}>🍽 ERNÄHRUNG (Ø 7T)</div>