mirror of
https://github.com/ceratic/project_vollidioten_website.git
synced 2026-05-14 00:16:47 +02:00
feat: add world map functionality and admin map management
- Added world map page with interactive marker display - Implemented admin map management for marker CRUD operations - Added map layers and markers seed data to database - Integrated new routes for map functionality - Updated database configuration for production environment - Added documentation page route - Enhanced package.json with required dependencies for map features
This commit is contained in:
@@ -7,6 +7,43 @@ import InventoryGrid from '../components/InventoryGrid';
|
||||
import EditModal from '../components/EditModal';
|
||||
import { Icons } from '../components/IconSet';
|
||||
|
||||
// Helper function to get advancement icon path
|
||||
const getAdvancementIconPath = (advancementId: string): string => {
|
||||
// Remove 'minecraft:' prefix if present
|
||||
const cleanId = advancementId.replace('minecraft:', '');
|
||||
|
||||
// Map advancement ID to icon path
|
||||
return `/assets/advancement/${cleanId}.png`;
|
||||
};
|
||||
|
||||
// Helper function to get advancement category
|
||||
const getAdvancementCategory = (advancementId: string): string => {
|
||||
const cleanId = advancementId.replace('minecraft:', '');
|
||||
|
||||
if (cleanId.startsWith('adventure/')) return 'Abenteuer';
|
||||
if (cleanId.startsWith('nether/')) return 'Nether';
|
||||
if (cleanId.startsWith('end/')) return 'End';
|
||||
if (cleanId.startsWith('husbandry/')) return 'Tierhaltung';
|
||||
if (cleanId.startsWith('story/')) return 'Geschichte';
|
||||
|
||||
return 'Sonstige';
|
||||
};
|
||||
|
||||
// Helper function to organize advancements by category
|
||||
const organizeAdvancementsByCategory = (advancements: any[]) => {
|
||||
const categories: { [key: string]: any[] } = {};
|
||||
|
||||
advancements.forEach(advancement => {
|
||||
const category = getAdvancementCategory(advancement.id);
|
||||
if (!categories[category]) {
|
||||
categories[category] = [];
|
||||
}
|
||||
categories[category].push(advancement);
|
||||
});
|
||||
|
||||
return categories;
|
||||
};
|
||||
|
||||
const PlayerProfile: React.FC = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
@@ -241,7 +278,7 @@ const PlayerProfile: React.FC = () => {
|
||||
<span className="font-mono text-textMain">
|
||||
{player.minecraftStats?.statistics?.general?.["minecraft:play_time"]
|
||||
? `${Math.round((player.minecraftStats.statistics.general["minecraft:play_time"] || 0) / 20 / 3600)}h`
|
||||
: `${player.minecraftStats?.playtimeHours || 0}h`
|
||||
: '0h'
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
@@ -280,8 +317,7 @@ const PlayerProfile: React.FC = () => {
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
{/* Left Col: Inventory & Org */}
|
||||
<div className="lg:col-span-1 space-y-6">
|
||||
<InventoryGrid items={player.inventory || []} />
|
||||
<div className="lg:col-span-1 space-y-6">
|
||||
|
||||
<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>
|
||||
@@ -302,7 +338,7 @@ const PlayerProfile: React.FC = () => {
|
||||
{playerOrg.name}
|
||||
</div>
|
||||
<div className="text-xs text-textMuted">
|
||||
{player.minecraftStats?.role || 'Unbekannt'} • Klick zum Anzeigen
|
||||
{player.stats?.role || 'Unbekannt'} • Klick zum Anzeigen
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -464,13 +500,43 @@ const PlayerProfile: React.FC = () => {
|
||||
{player.minecraftStats.advancements && player.minecraftStats.advancements.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-md font-semibold mb-3 text-textMain">Erfolge ({player.minecraftStats.advancements.length})</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
{player.minecraftStats.advancements.map((advancement) => (
|
||||
<div key={advancement.id} className="p-3 bg-surfaceHighlight/20 rounded border border-white/5">
|
||||
<div className="text-sm font-medium text-textMain">{advancement.title}</div>
|
||||
<div className="text-xs text-textMuted font-mono">{advancement.id.replace('minecraft:', '')}</div>
|
||||
</div>
|
||||
))}
|
||||
<div className="space-y-6">
|
||||
{Object.entries(organizeAdvancementsByCategory(player.minecraftStats.advancements))
|
||||
.sort(([a], [b]) => a.localeCompare(b))
|
||||
.map(([category, advancements]) => (
|
||||
<div key={category} className="bg-surfaceHighlight/20 rounded-lg border border-white/5 p-4">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<span className="text-sm font-semibold text-accentInfo uppercase tracking-wide">{category}</span>
|
||||
<span className="text-xs text-textMuted">({advancements.length})</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-4 gap-1">
|
||||
{advancements.map((advancement) => (
|
||||
<div
|
||||
key={advancement.id}
|
||||
className="group cursor-pointer hover:bg-white/5 p-2 rounded transition-all"
|
||||
title={advancement.title}
|
||||
>
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<div className="bg-white/5 rounded-lg flex items-center justify-center border border-white/10 group-hover:border-white/20 transition-colors">
|
||||
<img
|
||||
src={getAdvancementIconPath(advancement.id)}
|
||||
alt={advancement.title}
|
||||
className="w-28 h-28 object-contain"
|
||||
onError={(e) => {
|
||||
// Fallback to a default icon if the specific advancement icon doesn't exist
|
||||
e.currentTarget.src = '/assets/advancement/advancement_categories.png';
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-xs text-center text-textMuted font-mono truncate w-full">
|
||||
{advancement.id.replace('minecraft:', '').split('/')[1] || advancement.id.replace('minecraft:', '')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user