diff --git a/frontend/index.html b/frontend/index.html index eba5a25..2420770 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -7,7 +7,7 @@ - +
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b43ee5d..9414d38 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,9 +8,8 @@ "name": "d4rkbot-frontend", "version": "0.1.0", "dependencies": { - "@fontsource/barlow-condensed": "^5.3.0", - "@fontsource/bebas-neue": "^5.3.0", - "@fontsource/share-tech-mono": "^5.3.0", + "@fontsource/chakra-petch": "^5.3.0", + "@fontsource/ibm-plex-mono": "^5.3.0", "lucide-react": "^1.28.0", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -745,28 +744,19 @@ "node": ">=18" } }, - "node_modules/@fontsource/barlow-condensed": { + "node_modules/@fontsource/chakra-petch": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@fontsource/barlow-condensed/-/barlow-condensed-5.3.0.tgz", - "integrity": "sha512-RA7MmIx0v3eQ6Gcf74qLVLOwLB0GpPOzx+eU9iG/AmCnSJGcIWYeU8y6CEMGZ210MGwGg5CZhzLkkvyZdTTk1g==", + "resolved": "https://registry.npmjs.org/@fontsource/chakra-petch/-/chakra-petch-5.3.0.tgz", + "integrity": "sha512-QZvbM/q2R6n1pg2x+TJPftZmBNS+ADU37L4Z4L/6UJIz+JZ/SRaEf8usPFRiP7Ht28sIideMu/Bm1SnGlSrwNw==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" } }, - "node_modules/@fontsource/bebas-neue": { + "node_modules/@fontsource/ibm-plex-mono": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@fontsource/bebas-neue/-/bebas-neue-5.3.0.tgz", - "integrity": "sha512-nCxMEb9Bg9sjNWm9TIOsvHKDMLRUfEZPWpLgYu6m9KavZZVSA/WoHzI5wROwqA+eNwEi/PNBAcB5Co7HA3S0Cw==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource/share-tech-mono": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@fontsource/share-tech-mono/-/share-tech-mono-5.3.0.tgz", - "integrity": "sha512-hVEzVCzEid/fBfhggMyvkfDzn9ODrMihxC0EiOeQK3BuQNvdjmith2ERnoDNUkbW8zhufbKNuCgaSoT8LUNpuQ==", + "resolved": "https://registry.npmjs.org/@fontsource/ibm-plex-mono/-/ibm-plex-mono-5.3.0.tgz", + "integrity": "sha512-eTgnZjZEGk1QtD3ZstF+Vclo2HLAni8YMy34/DxllwZvyz1lR/1RF/xTiAquOBO7MvqBx8D2Ig2WCPMVfdZu7Q==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" diff --git a/frontend/package.json b/frontend/package.json index 5aef18c..99c5f79 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,9 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@fontsource/barlow-condensed": "^5.3.0", - "@fontsource/bebas-neue": "^5.3.0", - "@fontsource/share-tech-mono": "^5.3.0", + "@fontsource/chakra-petch": "^5.3.0", + "@fontsource/ibm-plex-mono": "^5.3.0", "lucide-react": "^1.28.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/frontend/public/brand/lockup.png b/frontend/public/brand/lockup.png new file mode 100644 index 0000000..f9558e3 Binary files /dev/null and b/frontend/public/brand/lockup.png differ diff --git a/frontend/public/brand/mark.png b/frontend/public/brand/mark.png new file mode 100644 index 0000000..e0e3c3c Binary files /dev/null and b/frontend/public/brand/mark.png differ diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 94ff626..ff1b54d 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { Routes, Route, NavLink, Navigate, useLocation } from 'react-router-dom'; import { apiGet } from './api.js'; import Devlogs from './pages/Devlogs.jsx'; @@ -62,35 +62,9 @@ function DiscordMark() { ); } -/* Aufsteigende Neon-Partikel wie auf der Platform-Seite */ -function Particles() { - const particles = useMemo( - () => - Array.from({ length: 24 }, (_, i) => ({ - id: i, - left: `${Math.random() * 100}%`, - dur: `${6 + Math.random() * 8}s`, - delay: `${Math.random() * 8}s`, - })), - [] - ); - return ( - - ); -} - export default function App() { // Login-Status einmal beim Laden holen const [me, setMe] = useState({ user: null, admin: false, scopes: [], loading: true }); - const [scrolled, setScrolled] = useState(false); const [drawer, setDrawer] = useState(false); const location = useLocation(); const { t } = useT(); @@ -116,18 +90,12 @@ export default function App() { if (gated) apiGet('/api/invite').then((d) => setInvite(d.invite)).catch(() => {}); }, [gated]); - useEffect(() => { - const onScroll = () => setScrolled(window.scrollY > 24); - window.addEventListener('scroll', onScroll, { passive: true }); - return () => window.removeEventListener('scroll', onScroll); - }, []); - return (
- - -
+ {/* Die Leiste ist immer kompakt — kein Zustandswechsel beim Scrollen */} +
+ D4RKST3R @@ -238,18 +206,21 @@ export default function App() {
); diff --git a/frontend/src/BotApp.jsx b/frontend/src/BotApp.jsx index 117e8eb..eed5eba 100644 --- a/frontend/src/BotApp.jsx +++ b/frontend/src/BotApp.jsx @@ -1,4 +1,4 @@ -// Rahmen der Bot-Produktseite — eigene Navigation, orange Leitfarbe. +// Rahmen der Bot-Produktseite — eigene Navigation, gleiche Marke wie der Hub. // Das Dashboard ist dieselbe Config-Seite wie bisher, nur unter /dashboard. import { useEffect, useState } from 'react'; import { Routes, Route, NavLink, Navigate, useLocation } from 'react-router-dom'; @@ -14,7 +14,6 @@ import { useT, LangSwitch } from './i18n.jsx'; export default function BotApp() { const [me, setMe] = useState({ user: null, admin: false, scopes: [], loading: true }); - const [scrolled, setScrolled] = useState(false); const [drawer, setDrawer] = useState(false); const [hub, setHub] = useState(null); // Seiten wie die Nutzungsbedingungen liegen auf dem Hub — verlinkt @@ -33,19 +32,15 @@ export default function BotApp() { apiGet('/api/pages').then((d) => setPages(d.pages)).catch(() => {}); }, []); - useEffect(() => { - const onScroll = () => setScrolled(window.scrollY > 24); - window.addEventListener('scroll', onScroll, { passive: true }); - return () => window.removeEventListener('scroll', onScroll); - }, []); - const canDashboard = me.admin || me.scopes?.length > 0; return ( -
-
+
+ {/* Die Leiste ist immer kompakt — kein Zustandswechsel beim Scrollen */} +
- D4RKBOT. + + D4RKBOT_
); diff --git a/frontend/src/components/Accent.jsx b/frontend/src/components/Accent.jsx new file mode 100644 index 0000000..c6634a1 --- /dev/null +++ b/frontend/src/components/Accent.jsx @@ -0,0 +1,27 @@ +// Betonte Stelle in einer Überschrift. +// +// Welches Wort — oder welche Silbe — den Marken-Verlauf bekommt, steht im +// Wörterbuch: der Teil in eckigen Klammern. So entscheidet jede Sprache +// selbst, wo sich die Überschrift teilen lässt („Funk[tionen]", aber +// „Fea[tures]"), ohne dass die Seite darüber etwas wissen muss. +// +// Mit `outline` bleibt der Rest als Kontur stehen statt gefüllt — so sieht +// die zweite Zeile des Hero auf der Produktseite aus. + +const MARKE = /^(.*?)\[([^\]]*)\](.*)$/s; + +export function Accent({ text, outline = false }) { + const treffer = MARKE.exec(text ?? ''); + if (!treffer) return <>{text}; + + const [, davor, betont, danach] = treffer; + const rest = outline ? 'outline-text' : undefined; + + return ( + <> + {davor && {davor}} + {betont} + {danach && {danach}} + + ); +} diff --git a/frontend/src/components/EmbedComposer.jsx b/frontend/src/components/EmbedComposer.jsx index 1aa2ab1..e4f85d4 100644 --- a/frontend/src/components/EmbedComposer.jsx +++ b/frontend/src/components/EmbedComposer.jsx @@ -162,7 +162,7 @@ export default function EmbedComposer({ channelOptions, flash }) { return (
-

// Post verfassen

+

Post verfassen

diff --git a/frontend/src/locales/de.js b/frontend/src/locales/de.js index 83529b1..36d488a 100644 --- a/frontend/src/locales/de.js +++ b/frontend/src/locales/de.js @@ -44,7 +44,7 @@ export default { 'common.monthsAgo': 'vor %s Monaten', // ── Startseite (Hub) ────────────────────────────── - 'home.tag': '// Community-Hub', + 'home.tag': 'Community-Hub', 'home.welcome': 'Willkommen', 'home.at': 'bei', 'home.subtitle': 'Devlogs, Roadmap, Server-Status und alles aus der Community — an einem Ort, direkt aus dem Discord.', @@ -53,8 +53,8 @@ export default { 'home.members': 'Member im Discord', 'home.serversOnline': 'Server online', 'home.playersNow': 'Spieler gerade drauf', - 'home.services': '// Dienste', - 'home.latestDevlog': '// Neuestes Devlog', + 'home.services': 'Dienste', + 'home.latestDevlog': 'Neuestes Devlog', 'home.more': 'Weiterlesen', 'home.tile.devlog': 'Entwicklungs-Updates, frisch aus dem Editor', 'home.tile.roadmap': 'Meilensteine + Community-Wünsche zum Abstimmen', @@ -64,7 +64,7 @@ export default { 'home.tile.events': 'Playtests, Streams und was sonst ansteht', 'nav.status': 'Status', - 'status.tag': '// Betriebslage', + 'status.tag': 'Betriebslage', 'status.subtitle': 'Erreichbarkeit der Dienste und Game-Server — alle 60 Sekunden aktualisiert.', 'status.error': 'Der Status konnte nicht geladen werden.', 'status.allOk': 'Alle Systeme betriebsbereit', @@ -72,9 +72,9 @@ export default { 'status.majorOutage': 'Größere Störung', 'status.waiting': 'Wird geprüft', 'status.nothing': 'Nichts eingerichtet', - 'status.services': '// Dienste', - 'status.gameservers': '// Game-Server', - 'status.incidents': '// Störungen der letzten 90 Tage', + 'status.services': 'Dienste', + 'status.gameservers': 'Game-Server', + 'status.incidents': 'Störungen der letzten 90 Tage', 'status.noIncidents': 'Keine Störungen aufgezeichnet.', 'status.ok': 'erreichbar', 'status.down': 'nicht erreichbar', @@ -82,7 +82,7 @@ export default { 'status.minutes': '%s min', 'status.days90': 'vor 90 Tagen', // ── Devlogs ─────────────────────────────────────── - 'devlogs.tag': '// Archiv', + 'devlogs.tag': 'Archiv', 'devlogs.subtitle': 'Entwicklungs-Updates, frisch aus dem Editor — automatisch archiviert.', 'devlogs.all': 'Alle', 'devlogs.search': 'Devlogs durchsuchen …', @@ -98,7 +98,7 @@ export default { 'devlogs.screenshot': 'Devlog-Screenshot', // ── Devlog-Permalink ────────────────────────────── - 'devlog.tag': '// Devlog', + 'devlog.tag': 'Devlog', 'devlog.project': 'Projekt: %s', 'devlog.notFound': 'Devlog nicht gefunden —', 'devlog.backToArchive': 'zurück zum Archiv', @@ -107,17 +107,17 @@ export default { 'devlog.linkCopied': 'Link kopiert', // ── Roadmap ─────────────────────────────────────── - 'roadmap.tag': '// Wohin die Reise geht', + 'roadmap.tag': 'Wohin die Reise geht', 'roadmap.subtitle': 'Meilensteine direkt aus der Entwicklung — live aus dem Issue-Tracker.', 'roadmap.error': 'Roadmap konnte nicht geladen werden.', 'roadmap.noMilestones': 'Noch keine Meilensteine angelegt.', - 'roadmap.active': '// In Arbeit', - 'roadmap.planned': '// Geplant', - 'roadmap.done': '// Fertig', + 'roadmap.active': 'In Arbeit', + 'roadmap.planned': 'Geplant', + 'roadmap.done': 'Fertig', 'roadmap.nothingActive': 'Gerade nichts in Arbeit.', 'roadmap.due': 'Ziel: %s', 'roadmap.tasks': '%s / %s Aufgaben', - 'roadmap.activity': '// Aktivität — %s Commits in 12 Monaten', + 'roadmap.activity': 'Aktivität — %s Commits in 12 Monaten', 'roadmap.commitsOn': '%s: %s Commits', 'roadmap.commitOn': '%s: 1 Commit', 'roadmap.sort': 'Sortierung', @@ -127,13 +127,13 @@ export default { 'roadmap.status': 'Stand', 'roadmap.area': 'Bereich', 'roadmap.areaPick': '— Bereich —', - 'wunsch.tag': '// Idee', + 'wunsch.tag': 'Idee', 'wunsch.back': 'Zurück zur Roadmap', 'wunsch.notFound': 'Diese Idee gibt es nicht (mehr).', 'wunsch.by': 'von %s', 'wunsch.teamSays': 'Vom Team', - 'wunsch.comments': '// %s Beiträge', - 'wunsch.oneComment': '// 1 Beitrag', + 'wunsch.comments': '%s Beiträge', + 'wunsch.oneComment': '1 Beitrag', 'wunsch.noComments': 'Noch nichts dazu geschrieben — mach den Anfang im Thread.', 'wunsch.joinThread': 'Im Discord mitreden', 'wish.alle': 'Alle', @@ -144,7 +144,7 @@ export default { 'wish.abgelehnt': 'Nicht geplant', 'roadmap.noneInFilter': 'Hier steht gerade nichts.', 'roadmap.alreadyThere': 'Gibt es schon — stimm lieber dafür:', - 'roadmap.wishes': '// Community-Wünsche', + 'roadmap.wishes': 'Community-Wünsche', 'roadmap.unvote': 'Vote zurücknehmen', 'roadmap.vote': 'Dafür stimmen', 'roadmap.ideaPlaceholder': 'Deine Idee für den Server …', @@ -157,7 +157,7 @@ export default { 'roadmap.submitFailed': '✗ Konnte den Wunsch nicht einreichen.', // ── Server ──────────────────────────────────────── - 'server.tag': '// Live-Status', + 'server.tag': 'Live-Status', 'server.subtitle': 'Alle Game-Server auf einen Blick — aktualisiert alle 2 Minuten.', 'server.error': 'Server-Status konnte nicht geladen werden.', 'server.none': 'Noch keine Server eingetragen.', @@ -166,7 +166,7 @@ export default { 'server.waiting': 'Warte auf Check', 'server.players24h': 'Spielerzahl · letzte 24h', // ── Mods eines LS-Servers ───────────────────────── - 'mods.tag': '// Modliste', + 'mods.tag': 'Modliste', 'mods.title': 'Mods', 'mods.subtitle': 'Alle Mods dieses Servers einzeln zum Laden — statt eines Pakets über alles.', 'mods.error': 'Modliste konnte nicht geladen werden.', @@ -207,7 +207,7 @@ export default { 'server.modsDownload': 'Mods laden', // ── Galerie ─────────────────────────────────────── - 'gallery.tag': '// Community', + 'gallery.tag': 'Community', 'gallery.subtitle': 'Screenshots aus der Community — direkt aus dem Discord.', 'gallery.error': 'Galerie konnte nicht geladen werden.', 'gallery.emptyTitle': 'Noch keine Screenshots', @@ -215,17 +215,17 @@ export default { 'gallery.shotBy': 'Screenshot von %s', // ── Level ───────────────────────────────────────── - 'level.tag': '// Bestenliste', + 'level.tag': 'Bestenliste', 'level.subtitle': 'XP gibt’s fürs Mitreden im Discord — hier stehen die Aktivsten. %s zeigt deinen Platz.', 'level.error': 'Bestenliste konnte nicht geladen werden.', 'level.emptyTitle': 'Noch keine XP vergeben', 'level.emptyText': 'XP gibt es fürs Mitreden im Discord. Sobald geschrieben wird, füllt sich die Bestenliste von selbst.', 'level.lv': 'Lv. %s', - 'level.activity': '// Server-Aktivität — %s Nachrichten in 30 Tagen · %s Member', + 'level.activity': 'Server-Aktivität — %s Nachrichten in 30 Tagen · %s Member', 'level.barTitle': '%s: %s Nachrichten · +%s/−%s Member', // ── Events ──────────────────────────────────────── - 'events.tag': '// Termine', + 'events.tag': 'Termine', 'events.subtitle': 'Playtests, Streams & Community-Abende — direkt aus dem Discord.', 'events.error': 'Events konnten nicht geladen werden.', 'events.emptyTitle': 'Noch keine Events geplant', @@ -235,7 +235,7 @@ export default { 'events.viewInDiscord': 'Im Discord ansehen', // ── Changelog ───────────────────────────────────── - 'changelog.tag': '// Releases', + 'changelog.tag': 'Releases', 'changelog.subtitle': 'Alle Versionen und Release-Notes.', 'changelog.error': 'Changelog konnte nicht geladen werden.', 'changelog.emptyTitle': 'Noch keine Releases', @@ -245,18 +245,21 @@ export default { 'changelog.viewInGitea': 'Release in Gitea ansehen', // ── Bot-Produktseite: Start ─────────────────────── - 'bot.tag': '// Selbst gebaut, keine Paywall', + 'bot.tag': 'Selbst gebaut · keine Paywall', 'bot.title1': 'Ein Discord-Bot,', - 'bot.title2': 'der alles macht', + 'bot.title2': 'der alles [macht]', 'bot.subtitle': 'Devlogs, Level, Moderation, Server-Monitoring, Verlosungen, Tickets — was sonst drei Bots mit Abo-Modell erledigen, läuft hier in einem, mit eigenem Webinterface.', 'bot.allFeatures': 'Alle Funktionen', 'bot.viewCommands': 'Befehle ansehen', - 'bot.statFeatures': 'Funktionen, einzeln schaltbar', + 'bot.statFeatures': 'Funktionen', 'bot.statCommands': 'Slash-Befehle', 'bot.statGames': 'Spiele im Monitor', - 'bot.statCost': 'Kosten, keine Premium-Stufen', - 'bot.whatItDoes': '// Was er kann', - 'bot.forDevs': '// Für Entwickler', + 'bot.statCost': 'Kosten', + 'bot.online': 'Online', + 'bot.hosting': 'Hosting', + 'bot.modulesMeta': '%s Module · einzeln schaltbar', + 'bot.whatItDoes': 'Was er kann', + 'bot.forDevs': 'Für Entwickler', 'bot.runsFor': 'Der Bot läuft für die D4RKST3R-Community', 'bot.runsForWith': 'Der Bot läuft für die D4RKST3R-Community mit %s Mitgliedern', 'bot.toHub': 'zum Community-Hub', @@ -285,11 +288,12 @@ export default { 'bot.dev.host.text': 'Node und SQLite in einem Container, ein Volume für die Daten. Nächtliche Sicherungen inklusive — von der Datenbank und allen Repositories.', // ── Bot-Produktseite: Funktionen ────────────────── - 'features.tag': '// Alles drin, nichts hinter einer Paywall', - 'features.title': 'Funktionen', + 'features.tag': 'Alles drin, nichts hinter einer Paywall', + 'features.title': 'Funk[tionen]', 'features.subtitleN': '%s Funktionen — jede einzeln ein- und ausschaltbar, jede im Browser einstellbar.', 'features.subtitle': 'Jede Funktion einzeln ein- und ausschaltbar, jede im Browser einstellbar.', - 'features.extras': '// Drumherum', + 'features.count': '%s Module', + 'features.extras': 'Drumherum', 'features.outro': 'Gebaut, weil drei Bots mit je eigenem Abo für eine Community weder übersichtlich noch günstig sind. Der Quelltext liegt offen, der Betrieb kostet einen Container.', 'features.overview': 'Zur Übersicht', 'features.x.brand': 'Webinterface im eigenen Look', @@ -306,8 +310,8 @@ export default { 'features.x.host.text': 'Node und SQLite in einem Container, ein Volume für die Daten. Nächtliche Sicherungen inklusive — von der Datenbank und allen Repositories.', // ── Bot-Produktseite: Befehle ───────────────────── - 'commands.tag': '// Referenz', - 'commands.title': 'Befehle', + 'commands.tag': 'Referenz', + 'commands.title': 'Be[fehle]', 'commands.subtitle': 'Alle Slash-Befehle im Überblick. Vieles läuft zusätzlich über Knöpfe direkt in den Nachrichten.', 'commands.note': 'Moderations- und Einrichtungs-Befehle sind Mitgliedern mit den passenden Discord-Rechten vorbehalten.', 'commands.g.everyone': 'Für alle', diff --git a/frontend/src/locales/en.js b/frontend/src/locales/en.js index 40952bf..661728a 100644 --- a/frontend/src/locales/en.js +++ b/frontend/src/locales/en.js @@ -43,7 +43,7 @@ export default { 'common.monthsAgo': '%s months ago', // ── Home (hub) ──────────────────────────────────── - 'home.tag': '// Community hub', + 'home.tag': 'Community hub', 'home.welcome': 'Welcome', 'home.at': 'to', 'home.subtitle': 'Devlogs, roadmap, server status and everything from the community — in one place, straight out of Discord.', @@ -52,8 +52,8 @@ export default { 'home.members': 'members on Discord', 'home.serversOnline': 'servers online', 'home.playersNow': 'players right now', - 'home.services': '// Services', - 'home.latestDevlog': '// Latest devlog', + 'home.services': 'Services', + 'home.latestDevlog': 'Latest devlog', 'home.more': 'Read more', 'home.tile.devlog': 'Development updates, fresh from the editor', 'home.tile.roadmap': 'Milestones plus community wishes to vote on', @@ -63,7 +63,7 @@ export default { 'home.tile.events': 'Playtests, streams and whatever else is coming up', 'nav.status': 'Status', - 'status.tag': '// Operational status', + 'status.tag': 'Operational status', 'status.subtitle': 'Reachability of services and game servers — refreshed every 60 seconds.', 'status.error': 'The status could not be loaded.', 'status.allOk': 'All systems operational', @@ -71,9 +71,9 @@ export default { 'status.majorOutage': 'Major outage', 'status.waiting': 'Checking', 'status.nothing': 'Nothing set up', - 'status.services': '// Services', - 'status.gameservers': '// Game servers', - 'status.incidents': '// Incidents in the last 90 days', + 'status.services': 'Services', + 'status.gameservers': 'Game servers', + 'status.incidents': 'Incidents in the last 90 days', 'status.noIncidents': 'No incidents recorded.', 'status.ok': 'operational', 'status.down': 'down', @@ -81,7 +81,7 @@ export default { 'status.minutes': '%s min', 'status.days90': '90 days ago', // ── Devlogs ─────────────────────────────────────── - 'devlogs.tag': '// Archive', + 'devlogs.tag': 'Archive', 'devlogs.subtitle': 'Development updates, fresh from the editor — archived automatically.', 'devlogs.all': 'All', 'devlogs.search': 'Search devlogs …', @@ -97,7 +97,7 @@ export default { 'devlogs.screenshot': 'Devlog screenshot', // ── Devlog permalink ────────────────────────────── - 'devlog.tag': '// Devlog', + 'devlog.tag': 'Devlog', 'devlog.project': 'Project: %s', 'devlog.notFound': 'Devlog not found —', 'devlog.backToArchive': 'back to the archive', @@ -106,17 +106,17 @@ export default { 'devlog.linkCopied': 'Link copied', // ── Roadmap ─────────────────────────────────────── - 'roadmap.tag': '// Where this is heading', + 'roadmap.tag': 'Where this is heading', 'roadmap.subtitle': 'Milestones straight from development — live from the issue tracker.', 'roadmap.error': 'The roadmap could not be loaded.', 'roadmap.noMilestones': 'No milestones yet.', - 'roadmap.active': '// In progress', - 'roadmap.planned': '// Planned', - 'roadmap.done': '// Done', + 'roadmap.active': 'In progress', + 'roadmap.planned': 'Planned', + 'roadmap.done': 'Done', 'roadmap.nothingActive': 'Nothing in progress right now.', 'roadmap.due': 'Due: %s', 'roadmap.tasks': '%s / %s tasks', - 'roadmap.activity': '// Activity — %s commits in 12 months', + 'roadmap.activity': 'Activity — %s commits in 12 months', 'roadmap.commitsOn': '%s: %s commits', 'roadmap.commitOn': '%s: 1 commit', 'roadmap.sort': 'Sort', @@ -126,13 +126,13 @@ export default { 'roadmap.status': 'Status', 'roadmap.area': 'Area', 'roadmap.areaPick': '— Area —', - 'wunsch.tag': '// Idea', + 'wunsch.tag': 'Idea', 'wunsch.back': 'Back to the roadmap', 'wunsch.notFound': 'This idea does not exist (any more).', 'wunsch.by': 'by %s', 'wunsch.teamSays': 'From the team', - 'wunsch.comments': '// %s comments', - 'wunsch.oneComment': '// 1 comment', + 'wunsch.comments': '%s comments', + 'wunsch.oneComment': '1 comment', 'wunsch.noComments': 'Nothing said about this yet — start it off in the thread.', 'wunsch.joinThread': 'Join the thread on Discord', 'wish.alle': 'All', @@ -143,7 +143,7 @@ export default { 'wish.abgelehnt': 'Not planned', 'roadmap.noneInFilter': 'Nothing here right now.', 'roadmap.alreadyThere': 'Already suggested — vote for it instead:', - 'roadmap.wishes': '// Community wishes', + 'roadmap.wishes': 'Community wishes', 'roadmap.unvote': 'Take back your vote', 'roadmap.vote': 'Vote for this', 'roadmap.ideaPlaceholder': 'Your idea for the server …', @@ -156,7 +156,7 @@ export default { 'roadmap.submitFailed': '✗ Could not submit the wish.', // ── Servers ─────────────────────────────────────── - 'server.tag': '// Live status', + 'server.tag': 'Live status', 'server.subtitle': 'Every game server at a glance — refreshed every 2 minutes.', 'server.error': 'The server status could not be loaded.', 'server.none': 'No servers added yet.', @@ -165,7 +165,7 @@ export default { 'server.waiting': 'Waiting for check', 'server.players24h': 'Player count · last 24h', // ── Mods of an FS server ────────────────────────── - 'mods.tag': '// Mod list', + 'mods.tag': 'Mod list', 'mods.title': 'Mods', 'mods.subtitle': 'Every mod on this server, one by one — instead of one big bundle.', 'mods.error': 'Could not load the mod list.', @@ -206,7 +206,7 @@ export default { 'server.modsDownload': 'Get mods', // ── Gallery ─────────────────────────────────────── - 'gallery.tag': '// Community', + 'gallery.tag': 'Community', 'gallery.subtitle': 'Screenshots from the community — straight out of Discord.', 'gallery.error': 'The gallery could not be loaded.', 'gallery.emptyTitle': 'No screenshots yet', @@ -214,17 +214,17 @@ export default { 'gallery.shotBy': 'Screenshot by %s', // ── Levels ──────────────────────────────────────── - 'level.tag': '// Leaderboard', + 'level.tag': 'Leaderboard', 'level.subtitle': 'XP comes from joining the conversation on Discord — here are the most active. %s shows your rank.', 'level.error': 'The leaderboard could not be loaded.', 'level.emptyTitle': 'No XP awarded yet', 'level.emptyText': 'XP comes from joining the conversation on Discord. As soon as people start writing, the leaderboard fills itself.', 'level.lv': 'Lv. %s', - 'level.activity': '// Server activity — %s messages in 30 days · %s members', + 'level.activity': 'Server activity — %s messages in 30 days · %s members', 'level.barTitle': '%s: %s messages · +%s/−%s members', // ── Events ──────────────────────────────────────── - 'events.tag': '// Dates', + 'events.tag': 'Dates', 'events.subtitle': 'Playtests, streams & community nights — straight out of Discord.', 'events.error': 'Events could not be loaded.', 'events.emptyTitle': 'No events planned yet', @@ -234,7 +234,7 @@ export default { 'events.viewInDiscord': 'View on Discord', // ── Changelog ───────────────────────────────────── - 'changelog.tag': '// Releases', + 'changelog.tag': 'Releases', 'changelog.subtitle': 'Every version and its release notes.', 'changelog.error': 'The changelog could not be loaded.', 'changelog.emptyTitle': 'No releases yet', @@ -244,18 +244,21 @@ export default { 'changelog.viewInGitea': 'View release on Gitea', // ── Bot product page: landing ───────────────────── - 'bot.tag': '// Self-built, no paywall', + 'bot.tag': 'Self-built · no paywall', 'bot.title1': 'A Discord bot', - 'bot.title2': 'that does it all', + 'bot.title2': 'that does it [all]', 'bot.subtitle': 'Devlogs, levels, moderation, server monitoring, giveaways, tickets — what usually takes three subscription bots runs here in one, with its own web interface.', 'bot.allFeatures': 'All features', 'bot.viewCommands': 'View commands', - 'bot.statFeatures': 'features, each one switchable', + 'bot.statFeatures': 'features', 'bot.statCommands': 'slash commands', 'bot.statGames': 'games in the monitor', - 'bot.statCost': 'cost, no premium tiers', - 'bot.whatItDoes': '// What it does', - 'bot.forDevs': '// For developers', + 'bot.statCost': 'cost', + 'bot.online': 'Online', + 'bot.hosting': 'Hosting', + 'bot.modulesMeta': '%s modules · individually switchable', + 'bot.whatItDoes': 'What it does', + 'bot.forDevs': 'For developers', 'bot.runsFor': 'The bot runs for the D4RKST3R community', 'bot.runsForWith': 'The bot runs for the D4RKST3R community with %s members', 'bot.toHub': 'to the community hub', @@ -284,11 +287,12 @@ export default { 'bot.dev.host.text': 'Node and SQLite in one container, one volume for the data. Nightly backups included — of the database and every repository.', // ── Bot product page: features ──────────────────── - 'features.tag': '// Everything included, nothing behind a paywall', - 'features.title': 'Features', + 'features.tag': 'Everything included, nothing behind a paywall', + 'features.title': 'Fea[tures]', 'features.subtitleN': '%s features — each one switchable, each one configurable in the browser.', 'features.subtitle': 'Every feature switchable on its own, every one configurable in the browser.', - 'features.extras': '// Around it', + 'features.count': '%s modules', + 'features.extras': 'Around it', 'features.outro': 'Built because three bots with three subscriptions for one community is neither tidy nor cheap. The source is open, running it costs one container.', 'features.overview': 'Back to the overview', 'features.x.brand': 'Web interface in your own look', @@ -395,8 +399,8 @@ export default { 'feat.member_gate.desc': 'Only people on the Discord server can sign in on the web.', // ── Bot product page: commands ──────────────────── - 'commands.tag': '// Reference', - 'commands.title': 'Commands', + 'commands.tag': 'Reference', + 'commands.title': 'Com[mands]', 'commands.subtitle': 'Every slash command at a glance. A lot also runs through buttons right inside the messages.', 'commands.note': 'Moderation and setup commands are reserved for members with the matching Discord permissions.', 'commands.g.everyone': 'For everyone', diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index 142c203..fab5b0f 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -5,11 +5,12 @@ import App from './App.jsx'; import BotApp from './BotApp.jsx'; import { IS_BOT } from './site.js'; import { LangProvider } from './i18n.jsx'; -import '@fontsource/bebas-neue'; -import '@fontsource/barlow-condensed/300.css'; -import '@fontsource/barlow-condensed/400.css'; -import '@fontsource/barlow-condensed/600.css'; -import '@fontsource/share-tech-mono'; +import '@fontsource/chakra-petch/400.css'; +import '@fontsource/chakra-petch/500.css'; +import '@fontsource/chakra-petch/600.css'; +import '@fontsource/chakra-petch/700.css'; +import '@fontsource/ibm-plex-mono/400.css'; +import '@fontsource/ibm-plex-mono/500.css'; import './style.css'; // Zwei Gesichter, eine Anwendung: Der Server sagt über data-site am , diff --git a/frontend/src/pages/BotCommands.jsx b/frontend/src/pages/BotCommands.jsx index b3c9368..36eea0c 100644 --- a/frontend/src/pages/BotCommands.jsx +++ b/frontend/src/pages/BotCommands.jsx @@ -1,6 +1,7 @@ // Übersicht aller Slash-Befehle des Bots. import { useEffect } from 'react'; import { IconLock } from '../icons.jsx'; +import { Accent } from '../components/Accent.jsx'; import { useT } from '../i18n.jsx'; // Befehlsname bleibt wie er ist — nur die Erklärung wird übersetzt. @@ -40,11 +41,9 @@ export default function BotCommands() { return ( <>
-
BEFEHLE
-
@@ -53,8 +52,12 @@ export default function BotCommands() { {GROUPS.map(([groupKey, restricted, commands]) => (

- // {t(groupKey)} - {restricted && } + {/* Schloss gehört zum Titel, nicht als eigene + Spalte daneben — deshalb in einer Hülle */} + + {t(groupKey)} + {restricted && } +

{commands.map(([name, descKey]) => ( diff --git a/frontend/src/pages/BotFeatures.jsx b/frontend/src/pages/BotFeatures.jsx index 91e427e..5f0d030 100644 --- a/frontend/src/pages/BotFeatures.jsx +++ b/frontend/src/pages/BotFeatures.jsx @@ -12,6 +12,7 @@ import { IconMessage, IconTeam, IconServer, IconApi, IconPages, IconBrand, IconBot, IconArrowRight, } from '../icons.jsx'; +import { Accent } from '../components/Accent.jsx'; import { moduleIcon } from '../module-icons.jsx'; // Was kein Discord-Modul ist, sondern zum Drumherum gehört @@ -38,11 +39,9 @@ export default function BotFeatures() { return ( <>
-
FEATURES
-