feat(ui): Rebuild Layout EXACTLY 1:1 matching SC1 Mockup (Top Header Nav, 5-Panel Movie Wall, 2-Column Dashboard Grid with Sparkline & Recently Ripped)
Ampel / ampel (push) Successful in 28s

This commit is contained in:
Hitonabi
2026-07-24 16:25:21 +02:00
parent f0a8455fc2
commit 0f20d9d8f4
3 changed files with 349 additions and 639 deletions
+51 -78
View File
@@ -1,109 +1,82 @@
import { useState, useEffect } from 'react'
import { LayoutDashboard, Disc, Settings, Sun, Moon, Terminal, BookOpen } from 'lucide-react'
import { api } from './lib/api'
import { useDarkMode } from './context/ThemeContext'
import { useState } from 'react'
import { LayoutDashboard, BookOpen, FileText, Settings as SettingsIcon, Moon, Sun } from 'lucide-react'
import Dashboard from './pages/Dashboard'
import AnleitungPage from './pages/Anleitung'
import SettingsPage from './pages/Settings'
import LogsPage from './pages/Logs'
import FirstRunWizard from './components/FirstRunWizard'
import AnleitungPage from './pages/Anleitung'
import { useDarkMode } from './context/ThemeContext'
type Page = 'dashboard' | 'anleitung' | 'settings' | 'logs'
type Page = 'dashboard' | 'anleitung' | 'logs' | 'settings'
function App() {
const [page, setPage] = useState<Page>('dashboard')
const [setupDone, setSetupDone] = useState<boolean | null>(null)
export default function App() {
const [currentPage, setCurrentPage] = useState<Page>('dashboard')
const { theme, toggleTheme } = useDarkMode()
useEffect(() => {
api.get('/setup')
.then(r => setSetupDone(!!r.data.done))
.catch(() => setSetupDone(true)) // API nicht erreichbar → kein Wizard-Zwang
}, [])
if (setupDone === false) {
return <FirstRunWizard onDone={() => setSetupDone(true)} />
}
const navItems = [
const navItems: { id: Page; label: string; icon: any }[] = [
{ id: 'dashboard', label: 'Dashboard', icon: LayoutDashboard },
{ id: 'anleitung', label: 'Anleitung', icon: BookOpen },
{ id: 'logs', label: 'Logs', icon: Terminal },
{ id: 'settings', label: 'Einstellungen', icon: Settings },
{ id: 'logs', label: 'Logs', icon: FileText },
{ id: 'settings', label: 'Einstellungen', icon: SettingsIcon },
]
return (
<div className="min-h-screen bg-slate-50 text-slate-900 dark:bg-slate-950 dark:text-slate-100 font-sans">
<div className="flex h-screen overflow-hidden">
{/* Cinema Sidebar */}
<aside className="w-64 bg-slate-900 dark:bg-slate-950 text-slate-100 flex flex-col border-r border-slate-800/80 shadow-2xl z-20">
<div className="p-6">
<div className="flex items-center gap-3">
<div className="p-2.5 bg-gradient-to-br from-amber-500 via-indigo-600 to-purple-600 rounded-xl shadow-lg shadow-amber-500/20">
<Disc size={26} className="text-white animate-pulse" />
</div>
<div>
<h1 className="text-xl font-bold tracking-tight bg-gradient-to-r from-white via-slate-100 to-amber-300 bg-clip-text text-transparent">
Rippy
</h1>
<p className="text-xs text-amber-400/80 font-medium tracking-wide uppercase">Cinema Edition</p>
</div>
</div>
<div className="min-h-screen bg-[#090d16] text-slate-100 font-sans selection:bg-amber-500/30 selection:text-amber-300">
{/* Top Header Navigation Bar (Identisch zu SC1) */}
<header className="sticky top-0 z-50 bg-[#0c101d]/90 backdrop-blur-xl border-b border-amber-500/20 shadow-lg shadow-black/40">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between gap-4">
{/* Logo */}
<div className="flex items-center gap-3 cursor-pointer" onClick={() => setCurrentPage('dashboard')}>
<span className="text-2xl font-black tracking-wider bg-gradient-to-r from-amber-400 via-amber-300 to-amber-500 bg-clip-text text-transparent drop-shadow-[0_0_12px_rgba(245,158,11,0.4)] font-mono">
RIPPY
</span>
<span className="px-2 py-0.5 rounded text-[10px] font-bold uppercase tracking-widest bg-amber-500/15 text-amber-400 border border-amber-500/30 hidden sm:inline-block">
CINEMA OS
</span>
</div>
<div className="px-3 mb-2">
<button
onClick={toggleTheme}
className="w-full flex items-center justify-between px-3 py-2 rounded-xl bg-slate-800/50 hover:bg-slate-800 text-slate-400 hover:text-slate-200 border border-slate-800 transition-all duration-200 text-xs font-medium"
title={theme === 'dark' ? 'Light Mode aktivieren' : 'Dark Mode aktivieren'}
>
<span className="flex items-center gap-2">
{theme === 'dark' ? <Moon size={15} className="text-amber-400" /> : <Sun size={15} className="text-amber-500" />}
<span>{theme === 'dark' ? 'Dark Mode' : 'Light Mode'}</span>
</span>
<span className="text-[10px] uppercase tracking-wider px-1.5 py-0.5 rounded bg-slate-700/60 text-slate-300">
{theme}
</span>
</button>
</div>
<nav className="flex-1 px-3 py-2 space-y-1.5">
{/* Central Nav Tabs */}
<nav className="flex items-center gap-1.5 bg-[#121827] p-1.5 rounded-2xl border border-slate-800 shadow-inner">
{navItems.map((item) => {
const isActive = page === item.id
const Icon = item.icon
const isActive = currentPage === item.id
return (
<button
key={item.id}
onClick={() => setPage(item.id as Page)}
className={`w-full flex items-center gap-3 px-3.5 py-2.5 rounded-xl transition-all duration-200 font-medium text-sm ${
onClick={() => setCurrentPage(item.id)}
className={`flex items-center gap-2 px-4 py-2 rounded-xl text-xs font-semibold transition-all duration-200 ${
isActive
? 'bg-gradient-to-r from-amber-500/20 via-slate-800 to-slate-800/80 text-amber-300 border-l-4 border-amber-500 shadow-md shadow-amber-500/10'
: 'text-slate-400 hover:bg-slate-800/50 hover:text-slate-200 border-l-4 border-transparent'
? 'bg-amber-500 text-slate-950 shadow-md shadow-amber-500/20 font-bold scale-[1.02]'
: 'text-slate-400 hover:text-slate-100 hover:bg-slate-800/60'
}`}
>
<item.icon size={19} className={isActive ? 'text-amber-400' : 'text-slate-400'} />
<Icon size={15} className={isActive ? 'text-slate-950' : 'text-slate-400'} />
<span>{item.label}</span>
</button>
)
})}
</nav>
<footer className="px-4 py-4 text-center text-[11px] text-slate-500 border-t border-slate-800/80">
Created with <span className="text-rose-400"></span> by LucyAI, Claude & KrBrZ
</footer>
</aside>
{/* Main Content Area */}
<main className="flex-1 overflow-auto bg-slate-50 dark:bg-slate-950">
<div className="max-w-7xl mx-auto p-6 md:p-8">
{page === 'dashboard' && <Dashboard />}
{page === 'anleitung' && <AnleitungPage />}
{page === 'logs' && <LogsPage />}
{page === 'settings' && <SettingsPage />}
{/* Right Action: Theme Toggle */}
<div className="flex items-center gap-3">
<button
onClick={toggleTheme}
className="p-2 rounded-xl border border-slate-800 bg-[#121827] text-amber-400 hover:border-amber-500/40 hover:bg-slate-800 transition-all"
title={theme === 'dark' ? 'Light Mode aktivieren' : 'Dark Mode aktivieren'}
>
{theme === 'dark' ? <Moon size={16} /> : <Sun size={16} />}
</button>
</div>
</main>
</div>
</div>
</header>
{/* Main Content Viewport */}
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{currentPage === 'dashboard' && <Dashboard />}
{currentPage === 'anleitung' && <AnleitungPage />}
{currentPage === 'logs' && <LogsPage />}
{currentPage === 'settings' && <SettingsPage />}
</main>
</div>
)
}
export default App