78 lines
2.6 KiB
PHP
78 lines
2.6 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
|
||
function h($s)
|
||
{
|
||
return htmlspecialchars((string)$s, ENT_QUOTES);
|
||
}
|
||
|
||
function admin_layout($title, $bodyHtml, $subtitle = 'Datenbankverwaltung', string $wrapClass = '')
|
||
{
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title><?= h($title) ?> – Fabian Schieder</title>
|
||
<link rel="stylesheet" href="/adminer/adminer.css">
|
||
</head>
|
||
<body>
|
||
|
||
<canvas id="particle-canvas"></canvas>
|
||
<div class="orb orb-1"></div>
|
||
<div class="orb orb-2"></div>
|
||
<div class="orb orb-3"></div>
|
||
<div class="orb orb-4"></div>
|
||
<div class="background-blur"></div>
|
||
|
||
<div class="wrap <?= h($wrapClass) ?>">
|
||
|
||
<div class="admin-header">
|
||
<div class="admin-avatar">FS</div>
|
||
<div class="admin-title"><?= h($title) ?></div>
|
||
<div class="admin-subtitle"><?= h($subtitle) ?></div>
|
||
</div>
|
||
|
||
<?= $bodyHtml ?>
|
||
|
||
<footer style="margin-top:3rem;padding-top:1.5rem;color:var(--text-muted);font-size:.8rem;text-align:center;border-top:1px solid var(--border)">
|
||
© <?= date('Y') ?> Fabian Schieder —
|
||
<a href="/" style="color:var(--text-muted)">← Zurück zur Startseite</a>
|
||
</footer>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
// ── Particles ──────────────────────────────────────────────────────────
|
||
(function(){
|
||
const canvas=document.getElementById('particle-canvas');
|
||
if(!canvas)return;
|
||
const ctx=canvas.getContext('2d');
|
||
const COLORS=['#6366f1','#0ea5e9','#a855f7','#ec4899','#22d3ee'];
|
||
let W,H,particles=[];
|
||
function resize(){W=canvas.width=window.innerWidth;H=canvas.height=window.innerHeight;}
|
||
function rand(a,b){return Math.random()*(b-a)+a;}
|
||
function mkP(){return{x:rand(0,W),y:rand(0,H),r:rand(.8,2.2),dx:rand(-.25,.25),dy:rand(-.35,-.08),alpha:rand(.2,.8),fade:rand(.002,.006),color:COLORS[Math.floor(Math.random()*COLORS.length)]};}
|
||
function init(){resize();particles=Array.from({length:80},mkP);}
|
||
function draw(){
|
||
ctx.clearRect(0,0,W,H);
|
||
for(let p of particles){
|
||
ctx.beginPath();ctx.arc(p.x,p.y,p.r,0,Math.PI*2);
|
||
ctx.fillStyle=p.color;ctx.globalAlpha=p.alpha;ctx.fill();
|
||
p.x+=p.dx;p.y+=p.dy;p.alpha-=p.fade;
|
||
if(p.alpha<=0||p.y<-5)Object.assign(p,mkP(),{y:H+5,alpha:rand(.2,.7)});
|
||
}
|
||
ctx.globalAlpha=1;
|
||
requestAnimationFrame(draw);
|
||
}
|
||
window.addEventListener('resize',resize);
|
||
init();draw();
|
||
})();
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|
||
<?php
|
||
}
|