// Startseite: Hero mit CTAs, Live-Zahlen, neuestes Devlog und Bereichs-Kacheln. // Nutzt nur öffentliche APIs — alles best effort, die Seite steht auch ohne Daten. import { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { apiGet } from '../api.js'; import { Markdown } from '../markdown.jsx'; import { useT, useFmt } from '../i18n.jsx'; import { IconDevlog, IconRoadmap, IconServer, IconGallery, IconLevel, IconEvents, IconMessage, IconArrowRight, IconLink, } from '../icons.jsx'; const TILES = [ ['/devlogs', IconDevlog, 'nav.devlog', 'home.tile.devlog'], ['/roadmap', IconRoadmap, 'nav.roadmap', 'home.tile.roadmap'], ['/server', IconServer, 'nav.server', 'home.tile.server'], ['/galerie', IconGallery, 'nav.gallery', 'home.tile.gallery'], ['/level', IconLevel, 'nav.level', 'home.tile.level'], ['/events', IconEvents, 'nav.events', 'home.tile.events'], ]; /** Devlog-Text für den Teaser kürzen (erste Sätze, ohne Titel-Zeile) */ function teaser(content) { const body = content .split(/\n{2,}/) .filter((b) => !/^Devlog\s*[—–-]/i.test(b.trim()) && !/^\*[^*]+\*$/s.test(b.trim())) .join('\n\n'); return body.length > 420 ? `${body.slice(0, 420).trimEnd()} …` : body; } export default function Home() { const { t } = useT(); const { zahl } = useFmt(); const [stats, setStats] = useState(null); const [servers, setServers] = useState(null); const [latest, setLatest] = useState(null); const [invite, setInvite] = useState(null); const [services, setServices] = useState([]); useEffect(() => { apiGet('/api/serverstats').then(setStats).catch(() => {}); apiGet('/api/servers').then((d) => setServers(d.servers)).catch(() => {}); apiGet('/api/devlogs?page=1').then((d) => setLatest(d.items?.[0] ?? null)).catch(() => {}); apiGet('/api/invite').then((d) => setInvite(d.invite)).catch(() => {}); apiGet('/api/services').then((d) => setServices(d.services)).catch(() => {}); window.scrollTo(0, 0); }, []); const online = servers?.filter((s) => s.online) ?? []; const players = online.reduce((sum, s) => sum + (s.players ?? 0), 0); return ( <> D4RKST3R {t('home.tag')} {t('home.welcome')}{t('home.at')} D4RKST3R {t('home.subtitle')} {invite && ( {t('home.discord')} )} {t('home.readDevlogs')} {(stats || servers) && ( {stats?.members > 0 && ( {zahl(stats.members)} {t('home.members')} )} {servers?.length > 0 && ( {online.length} / {servers.length} {t('home.serversOnline')} )} {online.length > 0 && ( {players} {t('home.playersNow')} )} )} {TILES.map(([to, Icon, titleKey, descKey]) => ( {t(titleKey)} {t(descKey)} ))} {services.length > 0 && ( {t('home.services')} {/* Dienst-Icons pflegt der Owner selbst — daher bleiben es Emojis */} {services.map((s) => ( {s.icon} {s.name} {s.description && {s.description}} ))} )} {latest && ( {t('home.latestDevlog')} {t('home.more')} )} > ); }
{t('home.subtitle')}