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

128 lines
6.0 KiB
TypeScript

import React from 'react';
import { Player } from '../types';
import { MOCK_ORGS } from '../constants';
import InventoryGrid from '../components/InventoryGrid';
import { Icons } from '../components/IconSet';
interface PlayerProfileProps {
player: Player;
onBack: () => void;
}
const PlayerProfile: React.FC<PlayerProfileProps> = ({ player, onBack }) => {
const playerOrg = MOCK_ORGS.find(o => o.id === player.stats.organizationId);
// Simple markdown renderer replacement for demo purposes
// In production, use 'react-markdown'
const renderMarkdown = (text: string) => {
return text.split('\n').map((line, i) => {
if (line.startsWith('# ')) return <h1 key={i} className="text-2xl font-bold mt-6 mb-3 text-textMain border-b border-border pb-2">{line.replace('# ', '')}</h1>;
if (line.startsWith('### ')) return <h3 key={i} className="text-lg font-semibold mt-4 mb-2 text-textMain">{line.replace('### ', '')}</h3>;
if (line.startsWith('> ')) return <blockquote key={i} className="border-l-2 border-accentInfo pl-4 italic text-textMuted my-4 bg-surfaceHighlight/30 py-2 pr-2 rounded-r">{line.replace('> ', '')}</blockquote>;
if (line.startsWith('* ')) return <li key={i} className="ml-4 list-disc text-textMuted mb-1 marker:text-accentInfo">{line.replace('* ', '')}</li>;
return <p key={i} className="mb-2 text-textMuted leading-relaxed">{line}</p>;
});
};
return (
<div className="max-w-4xl mx-auto animate-in slide-in-from-right-4 duration-300">
<button onClick={onBack} className="flex items-center gap-2 text-sm text-textMuted hover:text-textMain mb-6 transition-colors">
<span className="text-lg"></span> Zurück zur Liste
</button>
{/* Header */}
<div className="bg-surface border border-border rounded-xl p-6 shadow-card mb-6">
<div className="flex flex-col md:flex-row gap-6 items-start md:items-center">
<div className="w-20 h-20 rounded-lg flex items-center justify-center shadow-inner shrink-0">
<img src={"https://minotar.net/armor/bust/"+player.username+"/500.png"}></img>
</div>
<div className="flex-1">
<div className="flex flex-wrap items-center gap-3 mb-1">
<h1 className="text-3xl font-bold text-textMain tracking-tight">{player.username}</h1>
{player.isOnline && (
<span className="flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-accentSuccess/10 border border-accentSuccess/20 text-accentSuccess text-xs font-medium">
<span className="w-1.5 h-1.5 rounded-full bg-accentSuccess animate-pulse"></span>
Online
</span>
)}
</div>
<div className="flex flex-wrap gap-2 mb-4">
{player.tags.map(tag => (
<span key={tag} className="text-xs px-2 py-1 bg-surfaceHighlight rounded text-textMuted border border-white/5 font-mono">
{tag}
</span>
))}
</div>
<div className="flex gap-6 text-sm">
<div className="flex items-center gap-2 text-textMuted">
<Icons.Terminal className="w-4 h-4" />
<span className="font-mono text-textMain">{player.stats.playtimeHours}h</span>
</div>
<div className="flex items-center gap-2 text-textMuted">
<Icons.Box className="w-4 h-4" />
<span className="font-mono text-textMain">Lvl {player.stats.level}</span>
</div>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Left Col: Inventory */}
<div className="lg:col-span-1">
{/* <InventoryGrid items={player.inventory} /> */}
<div className="bg-surface border border-border rounded-xl p-4 shadow-card">
<h3 className="text-xs font-bold uppercase tracking-wider text-textMuted mb-3">Zugehörigkeit</h3>
<div className="flex items-center gap-3">
<div className={`w-10 h-10 rounded flex items-center justify-center text-lg font-bold border border-white/5 ${
playerOrg
? (playerOrg.type === 'City' ? 'bg-blue-500/10 text-blue-400' :
playerOrg.type === 'Guild' ? 'bg-amber-500/10 text-amber-400' :
'bg-purple-500/10 text-purple-400')
: 'bg-surfaceHighlight text-textMuted'
}`}>
{playerOrg ? playerOrg.name.charAt(0) : <Icons.Map className="w-5 h-5 opacity-50" />}
</div>
<div>
<div className="text-sm font-medium text-textMain">{player.stats.role}</div>
<div className="text-xs text-textMuted">
{playerOrg ? (
<span className="group-hover:text-accentInfo transition-colors">{playerOrg.name}</span>
) : (
'Freiberufler / Keine Zugehörigkeit'
)}
</div>
</div>
</div>
{playerOrg && (
<div className="mt-3 pt-3 border-t border-white/5 text-xs text-textMuted leading-relaxed">
{playerOrg.type} {playerOrg.description}
</div>
)}
</div>
</div>
{/* Right Col: Story */}
<div className="lg:col-span-2">
<div className="bg-surface border border-border rounded-xl p-8 shadow-card min-h-[400px]">
<div className="flex items-center justify-between mb-6 border-b border-border pb-4">
<h2 className="text-lg font-semibold flex items-center gap-2">
Charakter-Journal
</h2>
<span className="text-xs text-textMuted font-mono">Markdown Rendered</span>
</div>
<div className="prose-custom text-sm">
{renderMarkdown(player.storyMarkdown)}
</div>
</div>
</div>
</div>
</div>
);
};
export default PlayerProfile;