Redesign Webinterface: Voxel-Game-Ästhetik
- Selbst gehostete Fonts (Inter Variable, JetBrains Mono) — kein CDN - Voxel-Würfel-Logo (SVG), Grid-Hintergrund mit grünem Glow, Gradient-Hero - Devlogs als Timeline mit Voxel-Markern, Datums-Chips und Relativzeit - Commits als Zeilen-Liste mit SHA-, Repo- und Branch-Chips statt Tabelle - Discord-Login-Button mit Logo, User-Chip mit Avatar im Header - Mobile-Layout (Karten, umbrechende Commit-Zeilen) - Im Browser verifiziert: Desktop + Mobile, Devlogs + Commits (mit Admin-Session) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+43
-9
@@ -4,6 +4,28 @@ import { apiGet } from './api.js';
|
||||
import Devlogs from './pages/Devlogs.jsx';
|
||||
import Commits from './pages/Commits.jsx';
|
||||
|
||||
// Isometrischer Voxel-Würfel als Logo
|
||||
function VoxelLogo() {
|
||||
return (
|
||||
<svg className="logo" viewBox="0 0 32 32" aria-hidden="true">
|
||||
<path d="M16 2 L29 9 L16 16 L3 9 Z" fill="#4ade80" />
|
||||
<path d="M3 9 L16 16 L16 31 L3 23 Z" fill="#15803d" />
|
||||
<path d="M29 9 L16 16 L16 31 L29 23 Z" fill="#22c55e" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function DiscordMark() {
|
||||
return (
|
||||
<svg className="discord-mark" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M20.32 4.37a19.8 19.8 0 0 0-4.93-1.51 13.78 13.78 0 0 0-.64 1.28 18.27 18.27 0 0 0-5.5 0 12.64 12.64 0 0 0-.64-1.28c-1.71.29-3.37.8-4.93 1.51A20.26 20.26 0 0 0 .1 18.06a19.9 19.9 0 0 0 6.07 3.03c.49-.66.93-1.37 1.3-2.1a12.9 12.9 0 0 1-2.05-.98c.17-.12.34-.25.5-.38a14.2 14.2 0 0 0 12.16 0c.16.13.33.26.5.38-.65.39-1.34.71-2.05.98.37.73.81 1.44 1.3 2.1a19.84 19.84 0 0 0 6.07-3.03 20.2 20.2 0 0 0-3.58-13.69ZM8.02 15.33c-1.18 0-2.16-1.08-2.16-2.42 0-1.33.95-2.42 2.16-2.42 1.21 0 2.18 1.09 2.16 2.42 0 1.34-.95 2.42-2.16 2.42Zm7.96 0c-1.18 0-2.15-1.08-2.15-2.42 0-1.33.95-2.42 2.15-2.42 1.22 0 2.18 1.09 2.16 2.42 0 1.34-.94 2.42-2.16 2.42Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
// Login-Status einmal beim Laden holen
|
||||
const [me, setMe] = useState({ user: null, admin: false, loading: true });
|
||||
@@ -16,26 +38,35 @@ export default function App() {
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<div className="bg-glow" aria-hidden="true" />
|
||||
|
||||
<header className="header">
|
||||
<div className="header-inner">
|
||||
<NavLink to="/" className="brand">
|
||||
<span className="brand-dot" /> EcoGame
|
||||
<VoxelLogo />
|
||||
<span className="brand-name">
|
||||
Eco<span className="brand-accent">Game</span>
|
||||
</span>
|
||||
</NavLink>
|
||||
|
||||
<nav className="nav">
|
||||
<NavLink to="/devlogs">Devlogs</NavLink>
|
||||
{me.admin && <NavLink to="/commits">Commits</NavLink>}
|
||||
</nav>
|
||||
|
||||
<div className="auth">
|
||||
{me.loading ? null : me.user ? (
|
||||
<>
|
||||
<div className="user-chip">
|
||||
{me.user.avatar && (
|
||||
<img className="avatar" src={me.user.avatar} alt="" />
|
||||
)}
|
||||
<span className="username">{me.user.username}</span>
|
||||
<a className="btn btn-ghost" href="/auth/logout">Logout</a>
|
||||
</>
|
||||
<a className="logout" href="/auth/logout" title="Logout">✕</a>
|
||||
</div>
|
||||
) : (
|
||||
<a className="btn" href="/auth/login">Login mit Discord</a>
|
||||
<a className="btn btn-discord" href="/auth/login">
|
||||
<DiscordMark /> Login
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -51,10 +82,13 @@ export default function App() {
|
||||
</main>
|
||||
|
||||
<footer className="footer">
|
||||
EcoGame Devlog-Archiv ·{' '}
|
||||
<a href="https://git.d4rkst3r.de/D4rkst3r" target="_blank" rel="noreferrer">
|
||||
git.d4rkst3r.de
|
||||
</a>
|
||||
<VoxelLogo />
|
||||
<span>
|
||||
EcoGame Devlog-Archiv ·{' '}
|
||||
<a href="https://git.d4rkst3r.de/D4rkst3r" target="_blank" rel="noreferrer">
|
||||
git.d4rkst3r.de
|
||||
</a>
|
||||
</span>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user