refactor(Background): make the background filters an overlay to prevent juttery transition of styles being added AFTER completion

This commit is contained in:
alexsparkes
2025-10-31 13:56:03 +00:00
parent 94c92f7216
commit ef22e91b07
6 changed files with 85 additions and 19 deletions

View File

@@ -3,7 +3,7 @@ import BackgroundVideo from './components/BackgroundVideo';
import { useBackgroundState } from './hooks/useBackgroundState';
import { useBackgroundLoader } from './hooks/useBackgroundLoader';
import { useBackgroundRenderer, useBackgroundFilters } from './hooks/useBackgroundRenderer';
import { useBackgroundRenderer, useBackgroundFilters, useBackgroundOverlayFilters } from './hooks/useBackgroundRenderer';
import { useBackgroundEvents } from './hooks/useBackgroundEvents';
import './scss/index.scss';
@@ -16,18 +16,23 @@ export default function Background() {
const { backgroundData, updateBackground, resetBackground } = useBackgroundState();
const { refreshBackground } = useBackgroundLoader(updateBackground, resetBackground);
const filterStyle = useBackgroundFilters();
const overlayFilterStyle = useBackgroundOverlayFilters();
useBackgroundRenderer(backgroundData);
useBackgroundEvents(backgroundData, refreshBackground);
return backgroundData.video ? (
<BackgroundVideo url={backgroundData.url} filterStyle={filterStyle} />
) : (
<BackgroundImage
filterStyle={filterStyle}
photoInfo={backgroundData.photoInfo}
currentAPI={backgroundData.currentAPI}
url={backgroundData.url}
/>
return (
<>
{backgroundData.video ? (
<BackgroundVideo url={backgroundData.url} filterStyle={filterStyle} />
) : (
<BackgroundImage
photoInfo={backgroundData.photoInfo}
currentAPI={backgroundData.currentAPI}
url={backgroundData.url}
/>
)}
<div id="backgroundFilterOverlay" style={overlayFilterStyle} />
</>
);
}

View File

@@ -1,5 +1,5 @@
/**
* Generates the filter style string for backgrounds
* Generates the filter style string for backgrounds (legacy)
* @returns {string} The filter CSS string
*/
export function getBackgroundFilterStyle() {
@@ -16,3 +16,34 @@ export function getBackgroundFilterStyle() {
return filterString;
}
/**
* Generates styles for the background filter overlay
* Uses backdrop-filter for blur and additional effects, and background-color for brightness
* @returns {Object} Style object with backdropFilter and backgroundColor
*/
export function getBackgroundOverlayStyle() {
const blur = localStorage.getItem('blur') || '0';
const brightness = localStorage.getItem('brightness') || '100';
const backgroundFilter = localStorage.getItem('backgroundFilter');
const backgroundFilterAmount = localStorage.getItem('backgroundFilterAmount') || '100';
// Build backdrop-filter string for blur and other effects
let backdropFilterString = `blur(${blur}px)`;
if (backgroundFilter && backgroundFilter !== 'none') {
backdropFilterString += ` ${backgroundFilter}(${backgroundFilterAmount}%)`;
}
// Calculate brightness overlay (black overlay for darkening)
// brightness 100% = no overlay (opacity 0)
// brightness 0% = full black overlay (opacity 1)
const brightnessValue = parseInt(brightness, 10);
const overlayOpacity = (100 - brightnessValue) / 100;
return {
backdropFilter: backdropFilterString,
WebkitBackdropFilter: backdropFilterString, // Safari support
backgroundColor: `rgba(0, 0, 0, ${overlayOpacity})`,
};
}

View File

@@ -4,10 +4,10 @@ import PhotoInformation from './PhotoInformation';
/**
* BackgroundImage component for rendering image backgrounds
*/
function BackgroundImage({ filterStyle, photoInfo, currentAPI, url }) {
function BackgroundImage({ photoInfo, currentAPI, url }) {
return (
<>
<div style={filterStyle} id="backgroundImage" />
<div id="backgroundImage" />
{photoInfo?.credit && (
<PhotoInformation info={photoInfo} api={currentAPI} url={url} />
)}

View File

@@ -1,6 +1,6 @@
import { useEffect } from 'react';
import EventBus from 'utils/eventbus';
import { getBackgroundFilterStyle } from '../api/backgroundFilters';
import { getBackgroundFilterStyle, getBackgroundOverlayStyle } from '../api/backgroundFilters';
/**
* Hook for handling EventBus background events
@@ -45,9 +45,21 @@ export function useBackgroundEvents(backgroundData, refreshBackground) {
};
const applyFilters = () => {
const filter = getBackgroundFilterStyle();
const element = document.getElementById(backgroundData.video ? 'backgroundVideo' : 'backgroundImage');
if (element) element.style.webkitFilter = filter;
// For video backgrounds, apply filters directly to the video element
if (backgroundData.video) {
const filter = getBackgroundFilterStyle();
const element = document.getElementById('backgroundVideo');
if (element) element.style.webkitFilter = filter;
} else {
// For image backgrounds, apply filters to the overlay element
const overlayElement = document.getElementById('backgroundFilterOverlay');
if (overlayElement) {
const overlayStyle = getBackgroundOverlayStyle();
overlayElement.style.backdropFilter = overlayStyle.backdropFilter;
overlayElement.style.webkitBackdropFilter = overlayStyle.WebkitBackdropFilter;
overlayElement.style.backgroundColor = overlayStyle.backgroundColor;
}
}
};
EventBus.on('refresh', handleEvent);

View File

@@ -1,7 +1,7 @@
import { useEffect, useRef } from 'react';
import { createBlobUrl } from '../api/blobUrl';
import { generateBlurHashDataUrl } from '../api/blurHash';
import { getBackgroundFilterStyle } from '../api/backgroundFilters';
import { getBackgroundFilterStyle, getBackgroundOverlayStyle } from '../api/backgroundFilters';
/**
* Hook for rendering backgrounds to the DOM
@@ -110,8 +110,15 @@ export function useBackgroundRenderer(backgroundData) {
}
/**
* Hook to get computed filter styles
* Hook to get computed filter styles (legacy - for video backgrounds)
*/
export function useBackgroundFilters() {
return { WebkitFilter: getBackgroundFilterStyle() };
}
/**
* Hook to get computed overlay filter styles
*/
export function useBackgroundOverlayFilters() {
return getBackgroundOverlayStyle();
}

View File

@@ -27,6 +27,17 @@
transition: opacity 1.2s ease-in-out;
}
#backgroundFilterOverlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
pointer-events: none;
z-index: 0;
transition: backdrop-filter 0.3s ease-in-out, background-color 0.3s ease-in-out;
}
.backgroundPreload {
opacity: 0;
}