diff --git a/packages/frontend/src/components/AnalogClock.module.css b/packages/frontend/src/components/AnalogClock.module.css new file mode 100644 index 0000000..390f3f6 --- /dev/null +++ b/packages/frontend/src/components/AnalogClock.module.css @@ -0,0 +1,80 @@ +/* ============================================================ + AnalogClock – SVG-Analoguhr + ============================================================ */ + +.root { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.3125rem; +} + +.svg { + width: 148px; + height: 148px; + overflow: visible; + filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.08)); +} + +/* Ziffernblatt */ +.face { + fill: var(--color-bg-card); +} + +.border { + stroke: var(--color-border); + stroke-width: 1.5; +} + +/* Stundenmarkierungen */ +.tickMajor { + stroke: var(--color-text); + stroke-width: 1.75; + stroke-linecap: round; +} + +.tickMinor { + stroke: var(--color-text-muted); + stroke-width: 0.85; + stroke-linecap: round; +} + +/* Zeiger */ +.hourHand { + stroke: var(--color-text); + stroke-width: 3.75; + stroke-linecap: round; +} + +.minuteHand { + stroke: var(--color-text); + stroke-width: 2.5; + stroke-linecap: round; +} + +.secondHand { + stroke: #ef4444; + stroke-width: 1.5; + stroke-linecap: round; +} + +/* Mittelpunkt */ +.centerDot { + fill: #ef4444; +} + +/* Digitale Zeit darunter */ +.timeDigital { + font-size: 1.25rem; + font-weight: 700; + letter-spacing: 0.06em; + font-variant-numeric: tabular-nums; + color: var(--color-text); +} + +.dateText { + font-size: 0.75rem; + color: var(--color-text-muted); + text-transform: capitalize; + letter-spacing: 0.01em; +} diff --git a/packages/frontend/src/components/AnalogClock.tsx b/packages/frontend/src/components/AnalogClock.tsx new file mode 100644 index 0000000..54a6b7a --- /dev/null +++ b/packages/frontend/src/components/AnalogClock.tsx @@ -0,0 +1,117 @@ +import { useEffect, useState } from 'react'; +import styles from './AnalogClock.module.css'; + +// ── SVG-Konstanten ──────────────────────────────────────────────────────────── + +const CX = 50; +const CY = 50; +const R = 43; + +/** Berechnet die Spitzenkoordinaten eines Uhrzeigers. */ +function handTip( + cx: number, + cy: number, + deg: number, + length: number, +): { x: number; y: number } { + // 0° = 12 Uhr, im Uhrzeigersinn + const rad = ((deg - 90) * Math.PI) / 180; + return { + x: cx + length * Math.cos(rad), + y: cy + length * Math.sin(rad), + }; +} + +// ── Komponente ──────────────────────────────────────────────────────────────── + +export function AnalogClock() { + const [now, setNow] = useState(() => new Date()); + + useEffect(() => { + const id = setInterval(() => setNow(new Date()), 1000); + return () => clearInterval(id); + }, []); + + const h = now.getHours() % 12; + const m = now.getMinutes(); + const s = now.getSeconds(); + + const hourDeg = h * 30 + m * 0.5; // 360° / 12h + const minuteDeg = m * 6 + s * 0.1; // 360° / 60min + const secondDeg = s * 6; // 360° / 60s + + const hTip = handTip(CX, CY, hourDeg, 26); + const mTip = handTip(CX, CY, minuteDeg, 34); + const sTip = handTip(CX, CY, secondDeg, 37); + const sBase = handTip(CX, CY, secondDeg + 180, 10); // Gegengewicht + + const timeStr = now.toLocaleTimeString('de-DE', { + hour: '2-digit', + minute: '2-digit', + }); + const dateStr = now.toLocaleDateString('de-DE', { + weekday: 'short', + day: '2-digit', + month: 'short', + }); + + return ( +
Lädt…
+ )} + + {!isLoading && visible.length === 0 && ( +✅ Keine offenen Aufgaben
+ )} + + {!isLoading && visible.length > 0 && ( +Lädt…
} + + {!isLoading && emails.length === 0 && ( +Keine E-Mails in den letzten 3 Tagen
+ )} + + {!isLoading && emails.length > 0 && ( +@@ -223,33 +600,53 @@ function HomeSidebar() { ); } -// ── Tab-Inhalte ─────────────────────────────────────────────────────────────── +// ── Tab-Definitionen ────────────────────────────────────────────────────────── -function HomeTab({ firstName, lastName, city, role }: { +type DashboardTab = 'home' | 'emails' | 'calendar' | 'tasks' | 'contacts'; + +const TABS: { id: DashboardTab; label: string }[] = [ + { id: 'home', label: 'Home' }, + { id: 'emails', label: 'E-Mail' }, + { id: 'calendar', label: 'Kalender' }, + { id: 'tasks', label: 'Aufgaben' }, + { id: 'contacts', label: 'Kontakte' }, +]; + +// ── HomeTab ─────────────────────────────────────────────────────────────────── + +function HomeTab({ + firstName, + lastName, + city, + onSwitchTab, +}: { firstName?: string; lastName?: string; city?: string | null; - role?: string; + onSwitchTab: (tab: DashboardTab) => void; }) { return ( <> + {/* Header: Name links, Spruch rechts */}
- INSIGHT Platform - Sprint 1 Alpha -
-- Rolle: {role} -
-