Files
project_vollidioten_website/components/Layout.tsx
Lars Behrends d1b797a320 feat: Initialize project with Vite, React, and TypeScript
Sets up the foundational structure for the Obsidian | RP Plattform. This includes configuring Vite as the build tool, integrating React for the UI, and establishing TypeScript for type safety. Also includes initial styling and placeholder data to define the application's core interfaces.
2025-12-28 02:15:09 +01:00

126 lines
6.2 KiB
TypeScript

import React, { useState } from 'react';
import { Icons } from './IconSet';
interface LayoutProps {
children: React.ReactNode;
activeTab: string;
onNavigate: (tab: string) => void;
}
const NavItem = ({
active,
label,
onClick
}: {
active: boolean;
label: string;
onClick: () => void;
}) => (
<button
onClick={onClick}
className={`text-sm font-medium transition-colors duration-200 px-1 py-4 border-b-2 ${
active
? 'text-textMain border-accentInfo'
: 'text-textMuted border-transparent hover:text-textMain hover:border-border'
}`}
>
{label}
</button>
);
const Layout: React.FC<LayoutProps> = ({ children, activeTab, onNavigate }) => {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
return (
<div className="min-h-screen flex flex-col font-sans">
{/* Top Header - Website Style */}
<header className="sticky top-0 z-40 bg-background/80 backdrop-blur-md border-b border-border">
<div className="max-w-7xl mx-auto px-6 h-16 flex items-center justify-between">
<div className="flex items-center gap-10">
{/* Logo */}
<div
className="flex items-center gap-3 cursor-pointer group"
onClick={() => onNavigate('dashboard')}
>
<div className="w-8 h-8 bg-gradient-to-br from-accentInfo to-blue-900 rounded flex items-center justify-center shadow-glow group-hover:shadow-lg transition-shadow">
<span className="font-bold text-white text-sm">P.V.</span>
</div>
<span className="font-bold text-lg tracking-tight text-textMain">Projekt: Vollidion</span>
</div>
{/* Desktop Nav */}
<nav className="hidden md:flex items-center gap-6 h-full">
<NavItem active={activeTab === 'dashboard'} label="Übersicht" onClick={() => onNavigate('dashboard')} />
<NavItem active={activeTab === 'cities'} label="Städte" onClick={() => onNavigate('cities')} />
<NavItem active={activeTab === 'players'} label="Bürger" onClick={() => onNavigate('players')} />
{/* <NavItem active={activeTab === 'organizations'} label="Organisationen" onClick={() => onNavigate('organizations')} />*/}
<NavItem active={activeTab === 'projects'} label="Unternehmen" onClick={() => onNavigate('projects')} />
</nav>
</div>
<div className="flex items-center gap-4">
<button
onClick={() => onNavigate('datapack')}
className="hidden md:flex items-center gap-2 text-xs font-medium text-textMain hover:text-accentInfo transition-colors"
>
<Icons.Box className="w-3 h-3" />
<span>Datapack holen</span>
</button>
<button
onClick={() => onNavigate('setup')}
className="hidden md:flex items-center gap-2 text-xs font-medium text-textMuted hover:text-accentInfo transition-colors border border-border rounded-full px-4 py-1.5 hover:bg-surfaceHighlight"
>
<Icons.Terminal className="w-3 h-3" />
<span>Admin Setup</span>
</button>
{/* Mobile Menu Toggle */}
<button
className="md:hidden text-textMuted hover:text-textMain"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
<Icons.Layers className="w-6 h-6" />
</button>
</div>
</div>
{/* Mobile Nav Dropdown */}
{mobileMenuOpen && (
<div className="md:hidden border-t border-border bg-surface px-6 py-4 space-y-4 shadow-xl">
<div onClick={() => { onNavigate('dashboard'); setMobileMenuOpen(false); }} className="block py-2 text-textMuted hover:text-textMain">Übersicht</div>
<div onClick={() => { onNavigate('cities'); setMobileMenuOpen(false); }} className="block py-2 text-textMuted hover:text-textMain">Städte</div>
<div onClick={() => { onNavigate('players'); setMobileMenuOpen(false); }} className="block py-2 text-textMuted hover:text-textMain">Bürger</div>
<div onClick={() => { onNavigate('organizations'); setMobileMenuOpen(false); }} className="block py-2 text-textMuted hover:text-textMain">Organisationen</div>
<div onClick={() => { onNavigate('projects'); setMobileMenuOpen(false); }} className="block py-2 text-textMuted hover:text-textMain">Unternehmen</div>
<div onClick={() => { onNavigate('datapack'); setMobileMenuOpen(false); }} className="block py-2 text-textMain">Datapack holen</div>
<div onClick={() => { onNavigate('setup'); setMobileMenuOpen(false); }} className="block py-2 text-accentInfo font-mono text-sm border-t border-white/5 pt-4">Admin Setup >_</div>
</div>
)}
</header>
{/* Main Content - Page Flow */}
<main className="flex-1 w-full max-w-7xl mx-auto px-6 py-12 md:py-16">
<div className="animate-in fade-in duration-700 slide-in-from-bottom-4">
{children}
</div>
</main>
{/* Footer - Adds to the "Website" feel */}
<footer className="border-t border-border mt-auto bg-surface/30">
<div className="max-w-7xl mx-auto px-6 py-10 flex flex-col md:flex-row justify-between items-center text-sm text-textMuted">
<div className="flex items-center gap-2 mb-4 md:mb-0 opacity-50">
<div className="w-4 h-4 bg-textMuted rounded-full"></div>
<p>© 2024 Obsidian Platform</p>
</div>
<div className="flex gap-8">
<span className="cursor-pointer hover:text-textMain transition-colors">Dokumentation</span>
<span className="cursor-pointer hover:text-textMain transition-colors">Server Status</span>
<span className="cursor-pointer hover:text-textMain transition-colors">Datenschutz</span>
</div>
</div>
</footer>
</div>
);
};
export default Layout;