feat: Enhance navigation and dashboard with goals integration and UI improvements
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 14s

This commit is contained in:
Lars 2026-04-05 12:07:11 +02:00
parent 952cb90973
commit 6e952f9277
5 changed files with 89 additions and 32 deletions

View File

@ -41,15 +41,46 @@ body { font-family: var(--font); background: var(--bg); color: var(--text1); -we
.bottom-nav {
position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);
width: 100%; max-width: 600px;
height: var(--nav-h); display: flex; align-items: stretch;
background: var(--surface); border-top: 1px solid var(--border);
height: var(--nav-h);
display: flex;
align-items: stretch;
background: var(--surface);
border-top: 1px solid var(--border);
z-index: 20;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
-ms-overflow-style: none;
justify-content: flex-start;
gap: 2px;
padding: 0 6px;
box-sizing: border-box;
}
.bottom-nav::-webkit-scrollbar {
display: none;
}
.nav-item {
flex: 1; display: flex; flex-direction: column; align-items: center;
justify-content: center; gap: 3px; color: var(--text3);
text-decoration: none; font-size: 10px; font-weight: 500;
transition: color 0.15s; padding-bottom: env(safe-area-inset-bottom, 0);
flex: 0 0 auto;
min-width: 56px;
max-width: 96px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 3px;
color: var(--text3);
text-decoration: none;
font-weight: 500;
transition: color 0.15s;
padding: 0 4px calc(4px + env(safe-area-inset-bottom, 0));
box-sizing: border-box;
}
.nav-item span {
font-size: 10px;
line-height: 1.15;
text-align: center;
max-width: 100%;
}
.nav-item.active { color: var(--accent); }
.nav-item svg { flex-shrink: 0; }
@ -256,11 +287,15 @@ body { font-family: var(--font); background: var(--bg); color: var(--text1); -we
.analysis-page__header {
display: flex;
justify-content: space-between;
align-items: center;
align-items: flex-start;
margin-bottom: 16px;
gap: 12px;
flex-wrap: wrap;
}
.analysis-page__header > div:first-child {
flex: 1;
min-width: 0;
}
.analysis-split {
display: flex;
@ -544,14 +579,6 @@ a.analysis-split__nav-item {
}
}
/* 6-item nav - smaller labels */
.nav-item span { font-size: 11px; }
/* 7-item nav scrollable */
.bottom-nav { overflow-x: auto; }
.nav-item span { font-size: 11px; }
.nav-item { min-width: 60px; }
/* Header with profile avatar */
.app-header { display:flex; align-items:center; justify-content:space-between; }
.app-header a { display:flex; }

View File

@ -2,6 +2,7 @@ import {
LayoutDashboard,
PlusSquare,
TrendingUp,
Target,
BarChart2,
Settings,
Shield
@ -18,6 +19,7 @@ function baseItems() {
{ to: '/', label: 'Übersicht', end: true },
{ to: '/capture', label: 'Erfassen' },
{ to: '/history', label: 'Verlauf' },
{ to: '/goals', label: 'Ziele', shortLabel: 'Ziele', end: true },
{ to: '/analysis', label: 'Analyse' },
{ to: '/settings', label: 'Einstellungen', shortLabel: 'Einst.' }
]
@ -29,6 +31,7 @@ export function getMainNavItems(isAdmin) {
LayoutDashboard,
PlusSquare,
TrendingUp,
Target,
BarChart2,
Settings
]

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect, useMemo } from 'react'
import { Brain, Trash2, ChevronDown, ChevronUp, Target } from 'lucide-react'
import { useNavigate } from 'react-router-dom'
import { Brain, Trash2, ChevronDown, ChevronUp } from 'lucide-react'
import { Link } from 'react-router-dom'
import { api } from '../utils/api'
import { useAuth } from '../context/AuthContext'
import Markdown from '../utils/Markdown'
@ -330,7 +330,6 @@ function InsightCard({ ins, onDelete, defaultOpen=false, prompts=[] }) {
export default function Analysis() {
const { canUseAI } = useAuth()
const navigate = useNavigate()
const [prompts, setPrompts] = useState([])
const [allInsights, setAllInsights] = useState([])
const [loading, setLoading] = useState(null)
@ -474,15 +473,14 @@ export default function Analysis() {
return (
<div className="analysis-page">
<div className="analysis-page__header">
<h1 className="page-title" style={{ margin: 0 }}>KI-Analyse</h1>
<button
type="button"
className="btn btn-secondary"
onClick={() => navigate('/goals')}
style={{ fontSize: 13, padding: '6px 12px' }}
>
<Target size={14} /> Ziele
</button>
<div>
<h1 className="page-title" style={{ margin: 0 }}>KI-Analyse</h1>
<p style={{ fontSize: 12, color: 'var(--text3)', margin: '8px 0 0', lineHeight: 1.5, maxWidth: 520 }}>
Ziele und Fokusbereiche steuern den Kontext der Auswertungen {' '}
<Link to="/goals" style={{ color: 'var(--accent)', fontWeight: 600 }}>unter Ziele konfigurieren</Link>
{' '}(auch über die untere Navigation).
</p>
</div>
</div>
<div className="tabs">

View File

@ -256,6 +256,7 @@ export default function Dashboard() {
const { activeProfile } = useProfile()
const [adminDeniedHint, setAdminDeniedHint] = useState(false)
const [goalsCount, setGoalsCount] = useState(null)
const [stats, setStats] = useState(null)
const [weights, setWeights] = useState([])
@ -310,6 +311,13 @@ export default function Dashboard() {
return () => window.clearTimeout(clear)
}, [location.state, nav])
useEffect(() => {
if (!activeProfile?.id) return
api.listGoals()
.then((list) => setGoalsCount(Array.isArray(list) ? list.length : 0))
.catch(() => setGoalsCount(null))
}, [activeProfile?.id])
if (loading) return <div className="empty-state"><div className="spinner"/></div>
const latestCal = calipers[0]
@ -588,18 +596,26 @@ export default function Dashboard() {
<DashboardSection
title="Ziele & Fokus"
description="Trainingsmodus, Schwerpunkte und konkrete Ziele für die KI."
description="Strategische Ziele und Schwerpunkte eigener Menüpunkt „Ziele“, Kontext für KI und Dashboard."
headerRight={
<button type="button" className="btn btn-secondary" style={{ fontSize: 12, padding: '6px 12px' }}
onClick={(e)=>{ e.stopPropagation(); nav('/goals') }}>
Verwalten
Ziele bearbeiten
</button>
}
>
<DashboardTile>
<div className="card section-gap" style={{ cursor: 'pointer' }} onClick={()=>nav('/goals')}>
<div style={{fontSize:12,color:'var(--text2)',padding:'8px 0'}}>
Definiere deine Trainingsmodus und konkrete Ziele für bessere KI-Analysen
{goalsCount != null && (
<div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text1)', marginBottom: 8 }}>
{goalsCount === 0
? 'Noch keine Ziele angelegt.'
: `${goalsCount} ${goalsCount === 1 ? 'Ziel' : 'Ziele'} im System.`}
</div>
)}
<div style={{ fontSize: 12, color: 'var(--text2)', padding: goalsCount != null ? '0 0 8px' : '8px 0' }}>
Hier pflegst du Focus Areas, Meilensteine und Fortschritt unabhängig von der KI-Analyse-Seite.
Tippen zum Öffnen oder unten in der Navigation <strong>Ziele</strong> wählen.
</div>
</div>
</DashboardTile>

View File

@ -1,5 +1,5 @@
import { useState, useEffect } from 'react'
import { Save, Download, Upload, Check, LogOut, Key, BarChart3 } from 'lucide-react'
import { Save, Download, Upload, Check, LogOut, Key, BarChart3, Target } from 'lucide-react'
import { Link } from 'react-router-dom'
import { useProfile } from '../context/ProfileContext'
import { useAuth } from '../context/AuthContext'
@ -428,6 +428,19 @@ export default function SettingsPage() {
</button>
</div>
<div className="card section-gap">
<div className="card-title" style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<Target size={15} color="var(--accent)" /> Strategische Ziele
</div>
<p style={{ fontSize: 13, color: 'var(--text2)', marginBottom: 12, lineHeight: 1.6 }}>
Konkrete Ziele, Focus Areas und Fortschritt eigener Bereich{' '}
<strong>Ziele</strong> in der Navigation (nicht in der KI-Analyse).
</p>
<Link to="/goals" className="btn btn-secondary btn-full" style={{ textAlign: 'center', textDecoration: 'none', boxSizing: 'border-box' }}>
Zu den Zielen
</Link>
</div>
{/* Auth actions */}
<div className="card section-gap">
<div className="card-title">🔐 Konto</div>