Host-Routing: Bot-Produktseite und Community-Hub getrennt
Eine Anwendung, zwei Gesichter — der Server erkennt an der Domain, welche Seite gefragt ist, und schreibt das als data-site an den <body>. Das Frontend rendert daraufhin entweder den Community-Hub wie bisher oder die neue Produktseite. - Bot-Produktseite (BotApp): Landing mit Feature-Übersicht, Befehls- referenz, Dashboard unter /dashboard, Orange als Leitfarbe - Weiterleitungen: Community-Routen auf der Bot-Domain und umgekehrt werden dauerhaft (301) auf die richtige Adresse geschickt — geteilte Devlog-Permalinks laufen also nicht ins Leere. Rechtstexte bleiben auf beiden erreichbar. - Open-Graph-Tags je Domain, inklusive eigener Vorschau für frei angelegte Seiten (Entwürfe bekommen bewusst keine) - Login: neue Einstellung für die Cookie-Domain, damit die Anmeldung auf beiden Seiten gilt; nach dem Discord-Login landet man wieder auf der Seite, von der man gestartet ist (vorher immer auf der Hauptadresse) - Alles greift erst, wenn beide Adressen im Setup eingetragen sind — bis dahin verhält sich die Anwendung unverändert Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
// Produktseite des Bots: was er kann, wie er aussieht, wo es weitergeht.
|
||||
// Bewusst ohne „Einladen"-Button — der Bot ist auf einen Server ausgelegt.
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { apiGet } from '../api.js';
|
||||
import {
|
||||
IconDevlog, IconLevel, IconRoles, IconServer, IconSupport, IconGiveaway,
|
||||
IconBirthday, IconShield, IconMagic, IconKey, IconArrowRight, IconBot,
|
||||
} from '../icons.jsx';
|
||||
|
||||
const HIGHLIGHTS = [
|
||||
[IconDevlog, 'Devlogs & Feeds', 'Entwicklungs-Berichte landen als gebrandetes Embed im Discord und werden gleichzeitig durchsuchbar archiviert. Commits und Releases aus Gitea genauso.'],
|
||||
[IconServer, 'Server-Monitor', 'Über 300 Spiele per gamedig, dazu FiveM und einfache Erreichbarkeits-Checks. Ein Live-Embed pro Server, Alarm bei Ausfall, Spielerzahl in der Bot-Präsenz.'],
|
||||
[IconLevel, 'Level & Aktivität', 'XP fürs Mitreden mit Rollen-Belohnungen, öffentliche Bestenliste und Aktivitäts-Statistik des Servers.'],
|
||||
[IconRoles, 'Rollen-Menüs', 'Selbstbedienung per Knopfdruck — im Discord und im Browser. Farben pro Knopf, wahlweise exklusiv.'],
|
||||
[IconSupport, 'Support & Kontakt', 'Tickets als private Threads mit Gesprächsprotokoll, dazu Modmail: eine Direktnachricht an den Bot landet beim Team.'],
|
||||
[IconShield, 'Moderation', 'Verwarnungen mit Verlauf, Auszeiten, Aufräumen — alles im Mod-Log, dazu Protokoll für Beitritte, Namens- und Rollenwechsel.'],
|
||||
[IconGiveaway, 'Verlosungen', 'Teilnahme per Knopf, automatische Ziehung, Neuauslosung wenn sich niemand meldet.'],
|
||||
[IconBirthday, 'Geburtstage', 'Wer mag, trägt seinen Tag ein — der Bot gratuliert morgens und vergibt eine Rolle für den Tag.'],
|
||||
[IconMagic, 'Willkommens-Karten', 'Neue Mitglieder bekommen ein gerendertes Bild mit Avatar und Mitglieds-Nummer.'],
|
||||
];
|
||||
|
||||
export default function BotLanding() {
|
||||
const [status, setStatus] = useState(null);
|
||||
const [hub, setHub] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
apiGet('/api/legal').then((d) => setHub(d)).catch(() => {});
|
||||
apiGet('/api/serverstats').then(setStatus).catch(() => {});
|
||||
window.scrollTo(0, 0);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="page-header bot-hero">
|
||||
<div className="page-bg-text">BOT</div>
|
||||
<div className="page-header-grid" aria-hidden="true" />
|
||||
<div className="page-header-content">
|
||||
<div className="page-tag">// Selbst gebaut, keine Paywall</div>
|
||||
<h1 className="page-title">
|
||||
Ein Discord-Bot,<br />der alles macht
|
||||
</h1>
|
||||
<p className="page-subtitle">
|
||||
Devlogs, Level, Moderation, Server-Monitoring, Verlosungen, Tickets —
|
||||
was sonst drei Bots mit Abo-Modell erledigen, läuft hier in einem,
|
||||
mit eigenem Webinterface.
|
||||
</p>
|
||||
<div className="home-cta">
|
||||
<Link className="btn btn-save with-icon" to="/features">
|
||||
Alle Funktionen <IconArrowRight size={15} />
|
||||
</Link>
|
||||
<Link className="btn btn-ghost with-icon" to="/commands">
|
||||
<IconBot /> Befehle ansehen
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="content">
|
||||
<div className="srv-summary">
|
||||
<div className="srv-sum-item">
|
||||
<span className="srv-sum-n">16</span>
|
||||
<span className="srv-sum-label">Slash-Befehle</span>
|
||||
</div>
|
||||
<div className="srv-sum-item">
|
||||
<span className="srv-sum-n">300<span className="srv-sum-of">+</span></span>
|
||||
<span className="srv-sum-label">Spiele im Monitor</span>
|
||||
</div>
|
||||
<div className="srv-sum-item">
|
||||
<span className="srv-sum-n">0<span className="srv-sum-of"> €</span></span>
|
||||
<span className="srv-sum-label">Kosten, keine Premium-Stufen</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 className="settings-title" style={{ marginTop: '2.5rem' }}>// Was er kann</h2>
|
||||
<div className="home-tiles">
|
||||
{HIGHLIGHTS.map(([Icon, title, text]) => (
|
||||
<div className="card home-tile" key={title}>
|
||||
<span className="home-tile-icon"><Icon size={24} /></span>
|
||||
<span className="home-tile-title">{title}</span>
|
||||
<span className="home-tile-desc">{text}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="roadmap-group" style={{ marginTop: '2.5rem' }}>
|
||||
<h2 className="settings-title">// Für Entwickler</h2>
|
||||
<div className="home-tiles">
|
||||
<div className="card home-tile">
|
||||
<span className="home-tile-icon"><IconKey size={24} /></span>
|
||||
<span className="home-tile-title">API & Single Sign-On</span>
|
||||
<span className="home-tile-desc">
|
||||
Eigene Skripte posten über die API v1 mit Bearer-Schlüsseln und Bereichs-Rechten.
|
||||
Andere Dienste nutzen den Discord-Login des Bots mit und bekommen die Rollen
|
||||
gleich mitgeliefert.
|
||||
</span>
|
||||
</div>
|
||||
<div className="card home-tile">
|
||||
<span className="home-tile-icon"><IconServer size={24} /></span>
|
||||
<span className="home-tile-title">Läuft überall</span>
|
||||
<span className="home-tile-desc">
|
||||
Node und SQLite in einem Container, ein Volume für die Daten.
|
||||
Nächtliche Sicherungen inklusive — von der Datenbank und allen Repositories.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{hub?.publicUrl && (
|
||||
<p className="notice" style={{ marginTop: '2rem' }}>
|
||||
Der Bot läuft für die D4RKST3R-Community
|
||||
{status?.members ? ` mit ${status.members} Mitgliedern` : ''} —
|
||||
{' '}<a href={hub.publicUrl} style={{ textDecoration: 'underline' }}>zum Community-Hub</a>.
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user