This commit is contained in:
2026-09-16 05:50:50 +02:00
parent a7c3a5e472
commit fdb684e96f
2 changed files with 176 additions and 39 deletions
+30 -5
View File
@@ -14,6 +14,7 @@
--gray: #262626; --gray: #262626;
--accent: #9f0; --accent: #9f0;
--accent-rgb: 153, 255, 0; --accent-rgb: 153, 255, 0;
--sidebar-w: 300px;
--emoji-fav-color: #f5c518; --emoji-fav-color: #f5c518;
--nav-bg: #2b2b2b; --nav-bg: #2b2b2b;
--nav-brand-border: inset 1px #242424; --nav-brand-border: inset 1px #242424;
@@ -10388,19 +10389,43 @@ div.favs div.posts {
top: 0; top: 0;
left: 0; left: 0;
bottom: 0; bottom: 0;
right: 0; width: calc(100vw - var(--sidebar-w, 300px));
width: 100%;
height: 100%; height: 100%;
transform: translate3d(0, 0, 0) scale(var(--bg-canvas-zoom, 1.12)); transform: translate3d(0, 0, 0) scale(var(--bg-canvas-zoom, 1.12));
transform-origin: center center; transform-origin: center center;
z-index: -2; z-index: -2;
transition: opacity 1.5s cubic-bezier(0.4, 0, 0.2, 1); transition: opacity 1.5s cubic-bezier(0.4, 0, 0.2, 1), width 0.3s ease-in-out;
opacity: var(--bg-canvas-opacity, 1.0); opacity: var(--bg-canvas-opacity, 1.0);
filter: var(--bg-canvas-filter, none); filter: var(--bg-canvas-filter, none);
-webkit-filter: var(--bg-canvas-filter, none); -webkit-filter: var(--bg-canvas-filter, none);
background-color: var(--bg-canvas-color, transparent); background-color: var(--bg-canvas-color, transparent);
} }
body.sidebar-right-hidden,
body:not(:has(.global-sidebar-right)):not(:has(.item-sidebar-right)):not(:has(.index-sidebar-right)) {
--sidebar-w: 0px !important;
}
body.sidebar-right-hidden #bg,
body:not(:has(.global-sidebar-right)):not(:has(.item-sidebar-right)):not(:has(.index-sidebar-right)) #bg {
width: 100vw !important;
}
@media (min-width: 600px) and (max-width: 999px) {
:root {
--sidebar-w: min(280px, 80vw);
}
}
@media (max-width: 599px) {
:root {
--sidebar-w: 0px !important;
}
#bg {
width: 100vw !important;
}
}
button#togglebg { button#togglebg {
display: inline; display: inline;
cursor: pointer; cursor: pointer;
@@ -20863,7 +20888,7 @@ body.onara-modal-open #bg.fader-out,
body.onara-modal-open #bg.fast-fade { body.onara-modal-open #bg.fast-fade {
z-index: 51 !important; z-index: 51 !important;
cursor: pointer !important; cursor: pointer !important;
transition: none !important; transition: width 0.3s ease-in-out !important;
animation: none !important; animation: none !important;
opacity: var(--bg-canvas-opacity, 1.0) !important; opacity: var(--bg-canvas-opacity, 1.0) !important;
} }
@@ -20916,7 +20941,7 @@ body.onara-modal-open .admin-bar.open {
top: var(--navbar-h, 50px) !important; top: var(--navbar-h, 50px) !important;
bottom: 0 !important; bottom: 0 !important;
left: 0 !important; left: 0 !important;
right: 300px !important; right: var(--sidebar-w, 300px) !important;
width: auto !important; width: auto !important;
height: calc(100vh - var(--navbar-h, 50px)) !important; height: calc(100vh - var(--navbar-h, 50px)) !important;
z-index: 10050 !important; z-index: 10050 !important;
+146 -34
View File
@@ -2628,6 +2628,38 @@ window.cancelAnimFrame = (function () {
initialCanvas.classList.add('fader-out'); initialCanvas.classList.add('fader-out');
initialCanvas.classList.remove('fader-in'); initialCanvas.classList.remove('fader-in');
} }
// Live-sync #bg canvas backing store dimensions and redraw when free space changes (sidebar toggle, resize, etc.)
if (window.ResizeObserver) {
let _bgResizeTimer = null;
let _lastBgW = 0;
let _lastBgH = 0;
const _bgObserver = new ResizeObserver((entries) => {
const entry = entries && entries[0];
const cr = entry ? entry.contentRect : initialCanvas.getBoundingClientRect();
const curW = Math.round(cr.width);
const curH = Math.round(cr.height);
if (Math.abs(curW - _lastBgW) <= 2 && Math.abs(curH - _lastBgH) <= 2) return;
_lastBgW = curW;
_lastBgH = curH;
if (_bgResizeTimer) clearTimeout(_bgResizeTimer);
_bgResizeTimer = setTimeout(() => {
if (typeof window.redrawBgCanvas === 'function') {
window.redrawBgCanvas();
} else if (typeof window.initBackground === 'function') {
window.initBackground();
}
}, 50);
});
_bgObserver.observe(initialCanvas);
} else {
window.addEventListener('resize', () => {
if (typeof window.redrawBgCanvas === 'function') {
window.redrawBgCanvas();
}
}, { passive: true });
}
} }
@@ -4137,6 +4169,10 @@ window.cancelAnimFrame = (function () {
canvas._bgFadingOut = false; canvas._bgFadingOut = false;
canvas.classList.add('fader-in'); canvas.classList.add('fader-in');
canvas.classList.remove('fader-out', 'fast-fade'); canvas.classList.remove('fader-out', 'fast-fade');
if (document.body.classList.contains('onara-modal-open')) {
canvas.style.transition = 'none';
canvas.style.opacity = 'var(--bg-canvas-opacity, 1.0)';
}
} else { } else {
// Don't clear the canvas here — let the existing content fade out. // Don't clear the canvas here — let the existing content fade out.
canvas._bgFadingOut = true; canvas._bgFadingOut = true;
@@ -4153,8 +4189,17 @@ window.cancelAnimFrame = (function () {
} }
const SCALE = 0.5; const SCALE = 0.5;
const cw = Math.max(1, (canvas.clientWidth * SCALE) | 0); const syncCanvasDimensions = () => {
const ch = Math.max(1, (canvas.clientHeight * SCALE) | 0); const curCw = Math.max(1, (canvas.clientWidth * SCALE) | 0);
const curCh = Math.max(1, (canvas.clientHeight * SCALE) | 0);
if (canvas.width !== curCw || canvas.height !== curCh) {
canvas.width = curCw;
canvas.height = curCh;
}
return { w: canvas.width, h: canvas.height };
};
const { w: cw, h: ch } = syncCanvasDimensions();
// Capture previous canvas snapshot for buttery-smooth crossfade transition // Capture previous canvas snapshot for buttery-smooth crossfade transition
let prevSnapshot = null; let prevSnapshot = null;
@@ -4170,11 +4215,6 @@ window.cancelAnimFrame = (function () {
} }
} }
if (canvas.width !== cw || canvas.height !== ch) {
canvas.width = cw;
canvas.height = ch;
}
const context = canvas.getContext('2d'); const context = canvas.getContext('2d');
const cfgCurrent = window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING; const cfgCurrent = window.audioVisualizerTuning || DEFAULT_AUDIO_TUNING;
const blurSetting = cfgCurrent.bgCanvasBlur !== undefined ? Number(cfgCurrent.bgCanvasBlur) : 30; const blurSetting = cfgCurrent.bgCanvasBlur !== undefined ? Number(cfgCurrent.bgCanvasBlur) : 30;
@@ -4200,6 +4240,8 @@ window.cancelAnimFrame = (function () {
const drawCoverImage = (ctx, source) => { const drawCoverImage = (ctx, source) => {
if (!source) return; if (!source) return;
const targetCw = (ctx && ctx.canvas) ? ctx.canvas.width : canvas.width;
const targetCh = (ctx && ctx.canvas) ? ctx.canvas.height : canvas.height;
let sw = 0, sh = 0; let sw = 0, sh = 0;
if (source.videoWidth && source.videoHeight) { if (source.videoWidth && source.videoHeight) {
sw = source.videoWidth; sw = source.videoWidth;
@@ -4216,14 +4258,14 @@ window.cancelAnimFrame = (function () {
} }
if (sw > 0 && sh > 0) { if (sw > 0 && sh > 0) {
const scale = Math.max(cw / sw, ch / sh); const scale = Math.max(targetCw / sw, targetCh / sh);
const dw = sw * scale; const dw = sw * scale;
const dh = sh * scale; const dh = sh * scale;
const dx = (cw - dw) / 2; const dx = (targetCw - dw) / 2;
const dy = (ch - dh) / 2; const dy = (targetCh - dh) / 2;
ctx.drawImage(source, dx, dy, dw, dh); ctx.drawImage(source, dx, dy, dw, dh);
} else { } else {
ctx.drawImage(source, 0, 0, cw, ch); ctx.drawImage(source, 0, 0, targetCw, targetCh);
} }
}; };
@@ -4242,13 +4284,17 @@ window.cancelAnimFrame = (function () {
let crossfadeRafId = null; let crossfadeRafId = null;
const crossfadeToSource = (sourceImg, onComplete) => { const crossfadeToSource = (sourceImg, onComplete) => {
if (crossfadeRafId) window.cancelAnimFrame(crossfadeRafId); if (crossfadeRafId) window.cancelAnimFrame(crossfadeRafId);
if (!prevSnapshot) { syncCanvasDimensions();
context.clearRect(0, 0, cw, ch); const targetW = canvas.width;
const targetH = canvas.height;
const isOnara = document.body.classList.contains('onara-modal-open') || (typeof isOnaraActive === 'function' && isOnaraActive());
if (!prevSnapshot || isOnara) {
context.clearRect(0, 0, targetW, targetH);
context.save(); context.save();
context.filter = getCanvasFilter(); context.filter = getCanvasFilter();
drawCoverImage(context, sourceImg); drawCoverImage(context, sourceImg);
context.restore(); context.restore();
applyBgColorOverlay(context, cw, ch); applyBgColorOverlay(context, targetW, targetH);
if (onComplete) onComplete(); if (onComplete) onComplete();
return; return;
} }
@@ -4261,13 +4307,16 @@ window.cancelAnimFrame = (function () {
const progress = Math.min(1.0, elapsed / duration); const progress = Math.min(1.0, elapsed / duration);
const ease = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress; const ease = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
context.clearRect(0, 0, cw, ch); syncCanvasDimensions();
const w = canvas.width;
const h = canvas.height;
context.clearRect(0, 0, w, h);
// 1. Fade out previous background // 1. Fade out previous background
if (ease < 1.0 && prevSnapshot) { if (ease < 1.0 && prevSnapshot) {
context.save(); context.save();
context.globalAlpha = 1.0 - ease; context.globalAlpha = 1.0 - ease;
context.drawImage(prevSnapshot, 0, 0, cw, ch); context.drawImage(prevSnapshot, 0, 0, w, h);
context.restore(); context.restore();
} }
@@ -4281,7 +4330,7 @@ window.cancelAnimFrame = (function () {
context.restore(); context.restore();
// 3. Color overlay tint if configured // 3. Color overlay tint if configured
applyBgColorOverlay(context, cw, ch); applyBgColorOverlay(context, w, h);
if (progress < 1.0) { if (progress < 1.0) {
crossfadeRafId = window.requestAnimFrame(step); crossfadeRafId = window.requestAnimFrame(step);
@@ -4296,10 +4345,23 @@ window.cancelAnimFrame = (function () {
const drawOnce = () => { const drawOnce = () => {
if (!background || !context) return; if (!background || !context) return;
syncCanvasDimensions();
const itemId = window.getCurrentItemId(); const itemId = window.getCurrentItemId();
const isDrawable = elem && elem.tagName === 'IMG'; const isDrawable = elem && elem.tagName === 'IMG';
if (itemId) { if (itemId) {
if (document.body.classList.contains('onara-modal-open')) {
const onaraThumbImg = document.querySelector('.posts > a.thumb.onara-active img, .posts > a.thumb:focus img');
if (onaraThumbImg && onaraThumbImg.complete && onaraThumbImg.naturalWidth > 0) {
crossfadeToSource(onaraThumbImg, () => {
if (isDrawable && elem.complete && elem.naturalWidth > 0) {
crossfadeToSource(elem);
}
});
return;
}
}
const thumb = new Image(); const thumb = new Image();
thumb.onload = () => { thumb.onload = () => {
crossfadeToSource(thumb, () => { crossfadeToSource(thumb, () => {
@@ -4341,8 +4403,12 @@ window.cancelAnimFrame = (function () {
return; return;
} }
try { try {
context.clearRect(0, 0, cw, ch); syncCanvasDimensions();
if (prevSnapshot) { const curCw = canvas.width;
const curCh = canvas.height;
context.clearRect(0, 0, curCw, curCh);
const isOnara = document.body.classList.contains('onara-modal-open') || (typeof isOnaraActive === 'function' && isOnaraActive());
if (prevSnapshot && !isOnara) {
const elapsed = performance.now() - videoFadeStartTime; const elapsed = performance.now() - videoFadeStartTime;
const progress = Math.min(1.0, elapsed / 350); const progress = Math.min(1.0, elapsed / 350);
const ease = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress; const ease = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
@@ -4350,7 +4416,7 @@ window.cancelAnimFrame = (function () {
if (ease < 1.0) { if (ease < 1.0) {
context.save(); context.save();
context.globalAlpha = 1.0 - ease; context.globalAlpha = 1.0 - ease;
context.drawImage(prevSnapshot, 0, 0, cw, ch); context.drawImage(prevSnapshot, 0, 0, curCw, curCh);
context.restore(); context.restore();
} }
@@ -4366,7 +4432,7 @@ window.cancelAnimFrame = (function () {
prevSnapshot = null; prevSnapshot = null;
} }
} else { } else {
// Video already loaded or resumed from pause: render directly at 100% opacity without fading from black // Video already loaded or resumed from pause (or instant in Onara): render directly at 100% opacity without fading from black
context.save(); context.save();
context.filter = getCanvasFilter(); context.filter = getCanvasFilter();
try { try {
@@ -4376,7 +4442,7 @@ window.cancelAnimFrame = (function () {
} }
// Color overlay tint if configured // Color overlay tint if configured
applyBgColorOverlay(context, cw, ch); applyBgColorOverlay(context, curCw, curCh);
} catch (e) { } catch (e) {
bgRafId = null; bgRafId = null;
return; return;
@@ -4439,8 +4505,8 @@ window.cancelAnimFrame = (function () {
if (bgRafId) window.cancelAnimFrame(bgRafId); if (bgRafId) window.cancelAnimFrame(bgRafId);
animationLoop(); animationLoop();
} }
// For album videos that haven't started yet, drawOnce with the thumbnail // For album videos that haven't started yet, or Onara videos pending play, drawOnce with the thumbnail
else if (isAlbumVideo) { else if (isAlbumVideo || document.body.classList.contains('onara-modal-open')) {
drawOnce(); drawOnce();
} }
} }
@@ -8622,11 +8688,8 @@ window.cancelAnimFrame = (function () {
const srcH = innerEyeCanvas.height; const srcH = innerEyeCanvas.height;
const bgScale = cfg.bgCanvasScale !== undefined ? Number(cfg.bgCanvasScale) : 3; const bgScale = cfg.bgCanvasScale !== undefined ? Number(cfg.bgCanvasScale) : 3;
// Measure the sidebar so we center within the content area, not the full viewport // #bg canvas is already positioned to the free space respecting the sidebar
const sidebar = document.querySelector('.global-sidebar-right'); const contentW = bw;
const sidebarW = (sidebar && !document.body.classList.contains('sidebar-right-hidden'))
? (sidebar.offsetWidth || 0) * SCALE : 0;
const contentW = bw - sidebarW;
const fitScale = Math.min(contentW / srcW, bh / srcH); const fitScale = Math.min(contentW / srcW, bh / srcH);
const dw = srcW * fitScale * bgScale; const dw = srcW * fitScale * bgScale;
@@ -9213,6 +9276,9 @@ window.cancelAnimFrame = (function () {
w.style.removeProperty('padding-right'); w.style.removeProperty('padding-right');
w.style.removeProperty('right'); w.style.removeProperty('right');
}); });
if (typeof window.redrawBgCanvas === 'function') {
window.redrawBgCanvas();
}
}); });
}; };
mq.addEventListener('change', applyBreakpoint); mq.addEventListener('change', applyBreakpoint);
@@ -10310,12 +10376,20 @@ window.cancelAnimFrame = (function () {
document.querySelectorAll('video:not(#gchat-messages video), audio:not(#gchat-messages audio)').forEach(el => { try { el.pause(); } catch {} }); document.querySelectorAll('video:not(#gchat-messages video), audio:not(#gchat-messages audio)').forEach(el => { try { el.pause(); } catch {} });
} }
// Fade out background canvas for smooth transition // Fade out background canvas for smooth transition (non-Onara only)
const canvas = document.getElementById('bg'); const canvas = document.getElementById('bg');
if (canvas) { if (canvas) {
canvas.classList.add('fast-fade'); if (useOnara) {
canvas.classList.remove('fader-in'); canvas._bgFadingOut = false;
canvas.classList.add('fader-out'); canvas.classList.remove('fader-out', 'fast-fade');
canvas.classList.add('fader-in');
canvas.style.transition = 'none';
canvas.style.opacity = 'var(--bg-canvas-opacity, 1.0)';
} else {
canvas.classList.add('fast-fade');
canvas.classList.remove('fader-in');
canvas.classList.add('fader-out');
}
} }
} }
@@ -10622,7 +10696,14 @@ window.cancelAnimFrame = (function () {
if (!options.keepMedia) { if (!options.keepMedia) {
setupMedia(); setupMedia();
const _canvas = document.getElementById('bg'); const _canvas = document.getElementById('bg');
if (_canvas) _canvas.classList.remove('fader-out', 'fast-fade'); if (_canvas) {
_canvas.classList.remove('fader-out', 'fast-fade');
_canvas.classList.add('fader-in');
if (useOnara) {
_canvas.style.transition = 'none';
_canvas.style.opacity = 'var(--bg-canvas-opacity, 1.0)';
}
}
if (window.initBackground) window.initBackground(); if (window.initBackground) window.initBackground();
if (window.initVisualizer) window.initVisualizer(); if (window.initVisualizer) window.initVisualizer();
} }
@@ -10891,6 +10972,11 @@ window.cancelAnimFrame = (function () {
const canvas = document.getElementById('bg'); const canvas = document.getElementById('bg');
if (canvas) { if (canvas) {
canvas.classList.remove('fader-out', 'fast-fade'); canvas.classList.remove('fader-out', 'fast-fade');
canvas.classList.add('fader-in');
if (useOnara) {
canvas.style.transition = 'none';
canvas.style.opacity = 'var(--bg-canvas-opacity, 1.0)';
}
} }
if (window.initBackground) window.initBackground(); if (window.initBackground) window.initBackground();
if (window.initVisualizer) window.initVisualizer(); if (window.initVisualizer) window.initVisualizer();
@@ -11040,6 +11126,10 @@ window.cancelAnimFrame = (function () {
if (document.activeElement && document.activeElement !== thumbnail && typeof document.activeElement.blur === 'function') { if (document.activeElement && document.activeElement !== thumbnail && typeof document.activeElement.blur === 'function') {
document.activeElement.blur(); document.activeElement.blur();
} }
openOnaraModal();
if (typeof window.paintImmediateBgThumb === 'function') {
window.paintImmediateBgThumb(thumbnail);
}
} }
// Thumbnails inherit context (e.g. from Tag Index) // Thumbnails inherit context (e.g. from Tag Index)
loadItemAjax(thumbnail.href, true); loadItemAjax(thumbnail.href, true);
@@ -14075,6 +14165,9 @@ window.cancelAnimFrame = (function () {
w.style.removeProperty('right'); w.style.removeProperty('right');
}); });
swipeRT.isDraggingSidebar = false; swipeRT.isDraggingSidebar = false;
if (typeof window.redrawBgCanvas === 'function') {
window.redrawBgCanvas();
}
}); });
}; };
@@ -14332,6 +14425,9 @@ window.cancelAnimFrame = (function () {
w.style.removeProperty('padding-right'); w.style.removeProperty('padding-right');
w.style.removeProperty('right'); w.style.removeProperty('right');
}); });
if (typeof window.redrawBgCanvas === 'function') {
window.redrawBgCanvas();
}
}); });
}; };
@@ -14503,6 +14599,14 @@ window.cancelAnimFrame = (function () {
onaraModal.style.setProperty('right', targetModalRight, 'important'); onaraModal.style.setProperty('right', targetModalRight, 'important');
} }
// Animate #bg canvas width in sync with sidebar so background stays centered
const bgCanvas = document.getElementById('bg');
if (bgCanvas && animateWrappers) {
const targetBgWidth = isHidden ? `calc(100vw - ${sidebarWidth}px)` : '100vw';
bgCanvas.style.setProperty('transition', 'width 0.3s ease-in-out', 'important');
bgCanvas.style.setProperty('width', targetBgWidth, 'important');
}
sidebar.style.setProperty('transition', 'transform 0.3s ease-in-out', 'important'); sidebar.style.setProperty('transition', 'transform 0.3s ease-in-out', 'important');
sidebar.style.transform = `translateX(${targetTranslate}px)`; sidebar.style.transform = `translateX(${targetTranslate}px)`;
@@ -14515,6 +14619,7 @@ window.cancelAnimFrame = (function () {
sidebar.style.setProperty('transition', 'none', 'important'); sidebar.style.setProperty('transition', 'none', 'important');
edgeZone.style.setProperty('transition', 'none', 'important'); edgeZone.style.setProperty('transition', 'none', 'important');
if (onaraModal) onaraModal.style.setProperty('transition', 'none', 'important'); if (onaraModal) onaraModal.style.setProperty('transition', 'none', 'important');
if (bgCanvas) bgCanvas.style.setProperty('transition', 'none', 'important');
const toHidden = !isHidden; const toHidden = !isHidden;
document.body.classList.toggle('sidebar-right-hidden', toHidden); document.body.classList.toggle('sidebar-right-hidden', toHidden);
localStorage.setItem('sidebarRightHidden', toHidden); localStorage.setItem('sidebarRightHidden', toHidden);
@@ -14527,11 +14632,18 @@ window.cancelAnimFrame = (function () {
onaraModal.style.removeProperty('transition'); onaraModal.style.removeProperty('transition');
onaraModal.style.removeProperty('right'); onaraModal.style.removeProperty('right');
} }
if (bgCanvas) {
bgCanvas.style.removeProperty('transition');
bgCanvas.style.removeProperty('width');
}
wrappers.forEach(w => { wrappers.forEach(w => {
w.style.removeProperty('transition'); w.style.removeProperty('transition');
w.style.removeProperty('padding-right'); w.style.removeProperty('padding-right');
w.style.removeProperty('right'); w.style.removeProperty('right');
}); });
if (typeof window.redrawBgCanvas === 'function') {
window.redrawBgCanvas();
}
}); });
}; };