diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 24c0df2..ecd68eb 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3,95 +3,125 @@ import { useAppStore } from './store/useAppStore'; import FloorPlan from './components/FloorPlan'; import Timeline from './components/Timeline'; import ReservationList from './components/ReservationList'; -import BookingModal from './components/BookingModal'; +import ReservationModal from './components/BookingModal'; import { ViewMode } from './types'; -const NAV_ITEMS: { id: ViewMode; label: string; icon: string }[] = [ - { id: 'floor', label: '2D Tischplan', icon: '⬛' }, - { id: 'timeline', label: 'Timeline', icon: 'πŸ“Š' }, - { id: 'list', label: 'Reservierungen', icon: 'πŸ“‹' }, +const NAV = [ + { id: 'floor' as ViewMode, label: 'Tischplan' }, + { id: 'timeline' as ViewMode, label: 'Timeline' }, + { id: 'list' as ViewMode, label: 'Reservierungen' }, ]; -function App() { +export default function App() { const [view, setView] = useState('floor'); const { tables, reservations, showBookingModal, openBookingModal } = useAppStore(); - const activeCount = reservations.filter((r) => ['PENDING', 'CONFIRMED', 'ARRIVED'].includes(r.status)).length; const freeCount = tables.filter((t) => t.status === 'FREE').length; + const activeCount = reservations.filter((r) => ['PENDING', 'CONFIRMED', 'ARRIVED'].includes(r.status)).length; return ( -
- {/* Header */} -
-
- {/* Brand */} -
-
- PL +
+ {/* ── Header ── */} +
+ {/* Brand */} +
+
PL
+
+
+ Pizzeria Luigi
-
-

Pizzeria Luigi

-

- - Live Β· {new Date().toLocaleDateString('de-DE', { weekday: 'long', day: '2-digit', month: 'long' })} -

+
+ + {new Date().toLocaleDateString('de-DE', { weekday: 'long', day: '2-digit', month: 'short' })}
- - {/* Stats */} -
-
- - Frei: - {freeCount} -
-
- - Aktiv: - {activeCount} -
-
- - {/* Nav */} - - - {/* CTA */} -
+ + {/* Stats */} +
+ + +
+ + {/* Nav */} + + + {/* CTA */} +
- {/* Main */} -
+ {/* ── Content ── */} +
{view === 'floor' && } {view === 'timeline' && } {view === 'list' && }
- {/* Booking Modal */} - {showBookingModal && } + {showBookingModal && }
); } -export default App; +// ─── Shared atoms ──────────────────────────────────────────────────────────── +function Chip({ label, value, color }: { label: string; value: number; color: 'success' | 'accent' }) { + const c = color === 'success' ? 'var(--color-success)' : 'var(--color-accent)'; + return ( +
+ + {label} + {value} +
+ ); +} diff --git a/frontend/src/components/BookingModal.tsx b/frontend/src/components/BookingModal.tsx index 304cfbe..ea0f6b1 100644 --- a/frontend/src/components/BookingModal.tsx +++ b/frontend/src/components/BookingModal.tsx @@ -18,12 +18,12 @@ const DURATION_OPTIONS = [ ]; const EXTRA_TAGS = [ - { id: 'Hochstuhl', icon: 'πŸͺ‘', label: 'Hochstuhl' }, - { id: 'Geburtstag', icon: 'πŸŽ‚', label: 'Geburtstag' }, - { id: 'Fensterplatz', icon: 'πŸͺŸ', label: 'Fensterplatz' }, - { id: 'Hund', icon: 'πŸ•', label: 'Hund' }, - { id: 'Terrasse', icon: 'β˜€οΈ', label: 'Terrasse / Außen' }, - { id: 'Allergie', icon: '⚠️', label: 'Allergie' }, + { id: 'Hochstuhl', label: 'Hochstuhl' }, + { id: 'Geburtstag', label: 'Geburtstag' }, + { id: 'Fensterplatz', label: 'Fensterplatz' }, + { id: 'Hund', label: 'Hund' }, + { id: 'Terrasse', label: 'Terrasse / Außen' }, + { id: 'Allergie', label: 'Allergie' }, ]; // ─── Helpers ──────────────────────────────────────────────────────────────── @@ -230,7 +230,6 @@ export default function ReservationModal() { : 'bg-slate-800/50 border-slate-700 text-slate-400 hover:border-slate-500 hover:text-slate-300' }`} > - {tag.icon} {tag.label} ))} diff --git a/frontend/src/components/FloorPlan.tsx b/frontend/src/components/FloorPlan.tsx index bc27ddd..4d8f323 100644 --- a/frontend/src/components/FloorPlan.tsx +++ b/frontend/src/components/FloorPlan.tsx @@ -62,7 +62,7 @@ export default function FloorPlan({ tables }: Props) { cursor-pointer shadow-lg`} > {t.number} - πŸ‘€ {t.maxCapacity} + {t.maxCapacity} P. {STATUS_LABEL[t.status]} diff --git a/frontend/src/components/ReservationList.tsx b/frontend/src/components/ReservationList.tsx index a7ee0f7..52f73ed 100644 --- a/frontend/src/components/ReservationList.tsx +++ b/frontend/src/components/ReservationList.tsx @@ -27,11 +27,13 @@ const NEXT_STATUS: Partial> = { ARRIVED: 'FINISHED', }; -const TAG_ICONS: Record = { - Hochstuhl: 'πŸͺ‘', - Allergie: '⚠️', - Fensterplatz: 'πŸͺŸ', - Geburtstag: 'πŸŽ‚', +const TAG_LABELS: Record = { + Hochstuhl: 'Hochstuhl', + Allergie: 'Allergie', + Fensterplatz: 'Fensterplatz', + Geburtstag: 'Geburtstag', + Hund: 'Hund', + Terrasse: 'Terrasse', }; export default function ReservationList() { @@ -54,17 +56,17 @@ export default function ReservationList() {
- πŸ‘€ {r.guestCount} Pers. - πŸ• {r.startTime}–{r.endTime} - πŸ“‹ Tisch {getTableNames(r.tableIds)} - {r.guest.phone && πŸ“ž {r.guest.phone}} + {r.guestCount} Pers. + {r.startTime}–{r.endTime} + Tisch {getTableNames(r.tableIds)} + {r.guest.phone && {r.guest.phone}}
{r.tags.length > 0 && (
{r.tags.map((tag) => ( - {TAG_ICONS[tag] ?? '🏷️'} {tag} - + {TAG_LABELS[tag] ?? tag} + ))}
)} diff --git a/frontend/src/index.css b/frontend/src/index.css index f1d8c73..b878e00 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1 +1,49 @@ @import "tailwindcss"; + +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); + +@theme { + --font-sans: 'Inter', system-ui, sans-serif; + + --color-bg: #09090d; + --color-surface: #111116; + --color-surface-2: #1a1a24; + --color-border: #1f1f2e; + --color-border-2: #2a2a3a; + + --color-accent: #6366f1; + --color-accent-hover: #818cf8; + --color-accent-dim: rgba(99,102,241,0.12); + --color-accent-glow: rgba(99,102,241,0.25); + + --color-success: #22c55e; + --color-warning: #f59e0b; + --color-danger: #ef4444; + --color-sky: #38bdf8; + + --color-text: #f4f4f8; + --color-muted: #71717a; + --color-subtle: #3f3f52; +} + +*, *::before, *::after { box-sizing: border-box; } + +html, body, #root { + height: 100%; + margin: 0; + background-color: var(--color-bg); + color: var(--color-text); + font-family: var(--font-sans); + -webkit-font-smoothing: antialiased; +} + +/* Scrollbar */ +::-webkit-scrollbar { width: 6px; height: 6px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { background: var(--color-border-2); border-radius: 3px; } + +/* Selection */ +::selection { background: var(--color-accent-dim); color: var(--color-text); } + +/* Focus ring */ +:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }