Header menu via header.js
This commit is contained in:
74
frontend/public/assets/bubbles.js
Normal file
74
frontend/public/assets/bubbles.js
Normal file
@@ -0,0 +1,74 @@
|
||||
// === SuperSunday moving bubbles (canvas) — robust autoload ===
|
||||
(function(){
|
||||
function ensureCanvas(){
|
||||
let layer = document.getElementById('bubble-layer');
|
||||
if (!layer) {
|
||||
layer = document.createElement('canvas');
|
||||
layer.id = 'bubble-layer';
|
||||
document.body.appendChild(layer);
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
|
||||
const c = ensureCanvas();
|
||||
const ctx = c.getContext('2d', { alpha: true });
|
||||
|
||||
function resize(){
|
||||
c.width = window.innerWidth;
|
||||
c.height = window.innerHeight;
|
||||
}
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
const COLORS = [
|
||||
{from:'#1f2a6d', to:'#5b39a8'},
|
||||
{from:'#1a255d', to:'#3e2a7a'},
|
||||
{from:'#233278', to:'#7a42c4'},
|
||||
];
|
||||
const BUBBLES = [];
|
||||
const N = Math.min(24, Math.max(12, Math.floor((window.innerWidth*window.innerHeight)/120000)));
|
||||
function rand(a,b){ return a + Math.random()*(b-a); }
|
||||
|
||||
function makeBubble(){
|
||||
const r = rand(30, 120);
|
||||
const x = rand(-0.1*c.width, 1.1*c.width);
|
||||
const y = rand(-0.1*c.height, 1.1*c.height);
|
||||
const vy = rand(0.05, 0.2) * (Math.random()<0.5? 1 : -1);
|
||||
const vx = rand(-0.08, 0.08);
|
||||
const col = COLORS[Math.floor(Math.random()*COLORS.length)];
|
||||
const opacity = rand(0.08, 0.22);
|
||||
return {x,y,r,vx,vy,col,opacity, phase: rand(0, Math.PI*2)};
|
||||
}
|
||||
for(let i=0;i<N;i++) BUBBLES.push(makeBubble());
|
||||
|
||||
function tick(){
|
||||
ctx.clearRect(0,0,c.width,c.height);
|
||||
for(const b of BUBBLES){
|
||||
b.phase += 0.01 + (b.r/1200);
|
||||
const sway = Math.sin(b.phase) * 0.3;
|
||||
b.x += b.vx + sway;
|
||||
b.y += b.vy;
|
||||
if (b.x < -200 || b.x > c.width+200 || b.y < -200 || b.y > c.height+200) {
|
||||
const idx = BUBBLES.indexOf(b);
|
||||
BUBBLES[idx] = makeBubble();
|
||||
continue;
|
||||
}
|
||||
const g = ctx.createRadialGradient(b.x, b.y, b.r*0.1, b.x, b.y, b.r);
|
||||
g.addColorStop(0, hexA(b.col.to, b.opacity*1.0));
|
||||
g.addColorStop(1, hexA(b.col.from, 0));
|
||||
ctx.fillStyle = g;
|
||||
ctx.beginPath();
|
||||
ctx.arc(b.x, b.y, b.r, 0, Math.PI*2);
|
||||
ctx.fill();
|
||||
}
|
||||
requestAnimationFrame(tick);
|
||||
}
|
||||
function hexA(hex, a){
|
||||
const h = hex.replace('#','');
|
||||
const r = parseInt(h.substring(0,2),16);
|
||||
const g = parseInt(h.substring(2,4),16);
|
||||
const b = parseInt(h.substring(4,6),16);
|
||||
return `rgba(${r},${g},${b},${a})`;
|
||||
}
|
||||
requestAnimationFrame(tick);
|
||||
})();
|
||||
42
frontend/public/assets/header.js
Normal file
42
frontend/public/assets/header.js
Normal file
@@ -0,0 +1,42 @@
|
||||
// Shared header navigation for all pages
|
||||
(function(){
|
||||
const links = [
|
||||
{ href: '/', label: 'Accueil' },
|
||||
{ href: '/events', label: 'Événements' },
|
||||
{ href: '/admin', label: 'Admin' },
|
||||
{ href: '/scoreboard', label: 'Classement' },
|
||||
];
|
||||
|
||||
const path = location.pathname.replace(/\/index\.html$/, '');
|
||||
const isActive = (href) => {
|
||||
if (href === '/') return path === '/' || path === '';
|
||||
return path.startsWith(href);
|
||||
};
|
||||
|
||||
const nav = document.createElement('nav');
|
||||
nav.className = 'site-nav';
|
||||
nav.innerHTML = links.map(l =>
|
||||
`<a href="${l.href}" class="${isActive(l.href) ? 'active' : ''}">${l.label}</a>`
|
||||
).join('');
|
||||
|
||||
let header = document.querySelector('header');
|
||||
if (!header) {
|
||||
header = document.createElement('header');
|
||||
document.body.prepend(header);
|
||||
}
|
||||
// Basic style if not present (non-intrusive)
|
||||
header.style.position = header.style.position || 'sticky';
|
||||
header.style.top = header.style.top || '0';
|
||||
header.style.zIndex = header.style.zIndex || '4';
|
||||
|
||||
// Title (keep existing title if present)
|
||||
let h1 = header.querySelector('h1');
|
||||
if (!h1) {
|
||||
h1 = document.createElement('h1');
|
||||
h1.textContent = 'Super Sunday';
|
||||
header.prepend(h1);
|
||||
}
|
||||
// Replace or add nav
|
||||
const oldNav = header.querySelector('nav');
|
||||
if (oldNav) oldNav.replaceWith(nav); else header.appendChild(nav);
|
||||
})();
|
||||
58
frontend/public/assets/patch-bubbles.css
Normal file
58
frontend/public/assets/patch-bubbles.css
Normal file
@@ -0,0 +1,58 @@
|
||||
/* === SuperSunday Bubbles Patch Overrides (strong) === */
|
||||
:root{
|
||||
--z-bg: 0;
|
||||
--z-bubbles: 2;
|
||||
--z-content: 3;
|
||||
--z-header: 4;
|
||||
}
|
||||
|
||||
html, body{ height:100%; }
|
||||
|
||||
body{
|
||||
background: #0b1020;
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
body::before{
|
||||
content:"";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: var(--z-bg);
|
||||
background: url("/assets/images/backgroundp24p.jpg") center/cover no-repeat fixed;
|
||||
background-color: rgba(0,0,0,.55);
|
||||
background-blend-mode: multiply;
|
||||
}
|
||||
|
||||
/* Bubble layer sits between bg and content */
|
||||
#bubble-layer{
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: var(--z-bubbles);
|
||||
pointer-events: none;
|
||||
opacity: .6;
|
||||
mix-blend-mode: normal;
|
||||
}
|
||||
|
||||
/* Content above bubbles */
|
||||
main, .container, .card, .hero, .section{
|
||||
position: relative;
|
||||
z-index: var(--z-content);
|
||||
}
|
||||
|
||||
/* Header above all */
|
||||
header{
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: var(--z-header);
|
||||
backdrop-filter: blur(8px);
|
||||
background: linear-gradient(180deg, rgba(6,10,24,.9), rgba(6,10,24,.55));
|
||||
border-bottom: 1px solid rgba(255,255,255,.08);
|
||||
}
|
||||
|
||||
/* Avoid accidental stacking contexts */
|
||||
.card, .container, main, .hero, .section{
|
||||
transform: none !important;
|
||||
filter: none !important;
|
||||
isolation: auto;
|
||||
}
|
||||
Reference in New Issue
Block a user