Files
project_vollidioten_website/pages/Dashboard.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

111 lines
5.6 KiB
TypeScript

import React from 'react';
import { MOCK_PLAYERS, MOCK_PROJECTS, MOCK_ORGS } from '../constants';
import { Icons } from '../components/IconSet';
const StatCard = ({ label, value, trend, icon: Icon }: any) => (
<div className="bg-surface/50 border border-border p-6 rounded-xl hover:border-accentInfo/30 transition-all duration-300 group">
<div className="flex justify-between items-start mb-6">
<div className="p-3 bg-surfaceHighlight rounded-lg text-textMuted group-hover:text-textMain transition-colors">
<Icon className="w-6 h-6" />
</div>
{trend && (
<span className={`text-xs font-medium px-2.5 py-1 rounded-full ${
trend > 0 ? 'bg-accentSuccess/10 text-accentSuccess' : 'bg-accentWarn/10 text-accentWarn'
}`}>
{trend > 0 ? '+' : ''}{trend}%
</span>
)}
</div>
<div className="text-4xl font-bold text-textMain font-mono mb-2 tracking-tight">{value}</div>
<div className="text-sm text-textMuted font-medium">{label}</div>
</div>
);
const ProjectCard = ({ project }: { project: any }) => (
<div className="flex items-center gap-6 py-4 border-b border-white/5 last:border-0 group hover:bg-white/[0.02] px-2 rounded transition-colors -mx-2">
<div className={`w-2.5 h-2.5 rounded-full shadow-sm ${
project.status === 'active' ? 'bg-accentInfo' :
project.status === 'recruiting' ? 'bg-accentSuccess' : 'bg-textMuted'
}`} />
<div className="flex-1">
<div className="text-base font-medium text-textMain group-hover:text-accentInfo transition-colors">{project.title}</div>
<div className="text-xs text-textMuted mt-0.5 uppercase tracking-wide">Inhaber: {project.owner}</div>
</div>
<div className="w-32 hidden sm:block">
<div className="h-2 bg-surfaceHighlight rounded-full overflow-hidden">
<div className="h-full bg-accentInfo/80" style={{ width: `${project.progress}%` }} />
</div>
</div>
<div className="text-sm font-mono text-textMuted w-12 text-right">{project.progress}%</div>
</div>
);
const Dashboard: React.FC = () => {
return (
<div className="space-y-12">
{/* Intro Section */}
<div className="flex flex-col md:flex-row md:items-end justify-between gap-4 pb-4 border-b border-border">
<div>
<h2 className="text-sm font-bold text-accentInfo tracking-widest uppercase mb-2">Live-Telemetrie</h2>
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-white">Tal-Übersicht</h1>
</div>
<p className="text-textMuted text-right hidden md:block max-w-xs leading-relaxed">
Echtzeit-Datenaggregation aus dem Zentralarchiv.
</p>
</div>
{/* KPI Grid */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<StatCard label="Registrierte Bürger" value={MOCK_PLAYERS.length} trend={12} icon={Icons.Users} />
<StatCard label="Aktive Unternehmen" value={MOCK_PROJECTS.filter(p => p.status === 'active' || p.status === 'recruiting').length} trend={5} icon={Icons.Layers} />
<StatCard label="Organisationen" value={MOCK_ORGS.length} trend={0} icon={Icons.Map} />
</div>
{/* Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12">
{/* Projects List - Wider */}
<div className="lg:col-span-7">
<div className="flex justify-between items-end mb-6">
<h3 className="text-xl font-semibold">Top Unternehmen</h3>
<button className="text-sm text-textMuted hover:text-accentInfo transition-colors">Verzeichnis ansehen </button>
</div>
<div className="bg-surface/30 border border-border rounded-2xl p-6 backdrop-blur-sm">
{MOCK_PROJECTS.slice(0, 5).map(p => <ProjectCard key={p.id} project={p} />)}
</div>
</div>
{/* Decree / News - Narrower */}
<div className="lg:col-span-5 flex flex-col">
<h3 className="text-xl font-semibold mb-6">Offizieller Erlass</h3>
<div className="flex-1 bg-gradient-to-b from-surface/50 to-surface/20 border border-border rounded-2xl p-8 relative overflow-hidden group">
{/* Decorative background element */}
<div className="absolute -top-10 -right-10 w-40 h-40 bg-accentInfo/10 rounded-full blur-3xl group-hover:bg-accentInfo/20 transition-all duration-700" />
<div className="relative z-10">
<div className="mb-6">
<span className="text-xs font-mono px-2 py-1 bg-accentInfo/20 text-accentInfo rounded border border-accentInfo/20">NEU</span>
<span className="text-xs font-mono px-2 py-1 ml-2 text-textMuted">VOR 12 MIN</span>
</div>
<div className="prose prose-invert prose-lg text-textMuted leading-relaxed">
<p className="text-textMain italic text-lg font-serif mb-6">
"Im Auftrag des Bürgermeisters ist jeglicher Handel innerhalb der inneren Mauern für das kommende Fest steuerbefreit."
</p>
<p className="text-sm">
Bürger werden ermutigt, ihre Stände im Marktviertel aufzubauen, bevor der Mond am 14. Tag aufgeht.
</p>
</div>
</div>
<div className="absolute bottom-6 left-8 flex gap-2">
<span className="text-xs text-textMuted hover:text-white cursor-pointer">#Wirtschaft</span>
<span className="text-xs text-textMuted hover:text-white cursor-pointer">#Events</span>
</div>
</div>
</div>
</div>
</div>
);
};
export default Dashboard;