mirror of
https://github.com/mue/mue.git
synced 2026-07-24 09:17:24 +02:00
feat: add onChange handlers to ChipSelect and Text components; clear imageQueue on background type and category changes
This commit is contained in:
@@ -8,7 +8,7 @@ import FormControl from '@mui/material/FormControl';
|
|||||||
import Select from '@mui/material/Select';
|
import Select from '@mui/material/Select';
|
||||||
import Chip from '@mui/material/Chip';
|
import Chip from '@mui/material/Chip';
|
||||||
|
|
||||||
function ChipSelect({ label, options }) {
|
function ChipSelect({ label, options, onChange }) {
|
||||||
let start = (localStorage.getItem('apiCategories') || '').split(',');
|
let start = (localStorage.getItem('apiCategories') || '').split(',');
|
||||||
if (start[0] === '') {
|
if (start[0] === '') {
|
||||||
start = [];
|
start = [];
|
||||||
@@ -22,6 +22,11 @@ function ChipSelect({ label, options }) {
|
|||||||
} = event;
|
} = event;
|
||||||
setoptionsSelected(typeof value === 'string' ? value.split(',') : value);
|
setoptionsSelected(typeof value === 'string' ? value.split(',') : value);
|
||||||
localStorage.setItem('apiCategories', value);
|
localStorage.setItem('apiCategories', value);
|
||||||
|
|
||||||
|
// Call parent onChange if provided
|
||||||
|
if (onChange) {
|
||||||
|
onChange(value);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ const Text = memo((props) => {
|
|||||||
localStorage.setItem(props.name, value);
|
localStorage.setItem(props.name, value);
|
||||||
setValue(value);
|
setValue(value);
|
||||||
|
|
||||||
|
// Call parent onChange if provided
|
||||||
|
if (props.onChange) {
|
||||||
|
props.onChange(value);
|
||||||
|
}
|
||||||
|
|
||||||
if (props.element) {
|
if (props.element) {
|
||||||
if (!document.querySelector(props.element)) {
|
if (!document.querySelector(props.element)) {
|
||||||
document.querySelector('.reminder-info').style.display = 'flex';
|
document.querySelector('.reminder-info').style.display = 'flex';
|
||||||
@@ -28,7 +33,7 @@ const Text = memo((props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EventBus.emit('refresh', props.category);
|
EventBus.emit('refresh', props.category);
|
||||||
}, [props.name, props.upperCaseFirst, props.element, props.category]);
|
}, [props.name, props.upperCaseFirst, props.element, props.category, props.onChange]);
|
||||||
|
|
||||||
const resetItem = useCallback(() => {
|
const resetItem = useCallback(() => {
|
||||||
handleChange({
|
handleChange({
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { memo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BackgroundVideo component for rendering video backgrounds
|
* BackgroundVideo component for rendering video backgrounds
|
||||||
*/
|
*/
|
||||||
function BackgroundVideo({ url, filterStyle }) {
|
function BackgroundVideo({ url, filterStyle }) {
|
||||||
const isMuted = localStorage.getItem('backgroundVideoMute') === 'true';
|
const isMuted = useMemo(() => localStorage.getItem('backgroundVideoMute') === 'true', []);
|
||||||
const shouldLoop = localStorage.getItem('backgroundVideoLoop') === 'true';
|
const shouldLoop = useMemo(() => localStorage.getItem('backgroundVideoLoop') === 'true', []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<video
|
<video
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef, useMemo } from 'react';
|
||||||
import { createBlobUrl } from '../api/blobUrl';
|
import { createBlobUrl } from '../api/blobUrl';
|
||||||
import { generateBlurHashDataUrl } from '../api/blurHash';
|
import { generateBlurHashDataUrl } from '../api/blurHash';
|
||||||
import { getBackgroundFilterStyle, getBackgroundOverlayStyle } from '../api/backgroundFilters';
|
import { getBackgroundFilterStyle, getBackgroundOverlayStyle } from '../api/backgroundFilters';
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const TRANSITION_DURATION = 1200; // milliseconds
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for rendering backgrounds to the DOM
|
* Hook for rendering backgrounds to the DOM
|
||||||
*/
|
*/
|
||||||
export function useBackgroundRenderer(backgroundData) {
|
export function useBackgroundRenderer(backgroundData) {
|
||||||
const blobRef = useRef(null);
|
const blobRef = useRef(null);
|
||||||
|
const abortControllerRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (backgroundData.video) return;
|
if (backgroundData.video) return;
|
||||||
@@ -15,11 +19,18 @@ export function useBackgroundRenderer(backgroundData) {
|
|||||||
const element = document.getElementById('backgroundImage');
|
const element = document.getElementById('backgroundImage');
|
||||||
if (!element) return;
|
if (!element) return;
|
||||||
|
|
||||||
|
// Abort any pending image loads
|
||||||
|
if (abortControllerRef.current) {
|
||||||
|
abortControllerRef.current.abort();
|
||||||
|
}
|
||||||
|
abortControllerRef.current = new AbortController();
|
||||||
|
|
||||||
const applyBackground = async () => {
|
const applyBackground = async () => {
|
||||||
if (backgroundData.url) {
|
if (backgroundData.url) {
|
||||||
const hasTransition = localStorage.getItem('bgtransition') !== 'false';
|
const hasTransition = localStorage.getItem('bgtransition') !== 'false';
|
||||||
|
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||||
|
|
||||||
if (!hasTransition) {
|
if (!hasTransition || prefersReducedMotion) {
|
||||||
element.style.background = `url(${backgroundData.url})`;
|
element.style.background = `url(${backgroundData.url})`;
|
||||||
document.querySelector('.photoInformation')?.style.setProperty('display', 'flex');
|
document.querySelector('.photoInformation')?.style.setProperty('display', 'flex');
|
||||||
return;
|
return;
|
||||||
@@ -82,7 +93,7 @@ export function useBackgroundRenderer(backgroundData) {
|
|||||||
void overlay.offsetHeight;
|
void overlay.offsetHeight;
|
||||||
|
|
||||||
// Re-enable transition
|
// Re-enable transition
|
||||||
overlay.style.transition = 'opacity 1.2s ease-in-out';
|
overlay.style.transition = `opacity ${TRANSITION_DURATION / 1000}s ease-in-out`;
|
||||||
|
|
||||||
// Force another reflow before changing opacity
|
// Force another reflow before changing opacity
|
||||||
void overlay.offsetHeight;
|
void overlay.offsetHeight;
|
||||||
@@ -95,7 +106,7 @@ export function useBackgroundRenderer(backgroundData) {
|
|||||||
element.style.backgroundImage = `url(${finalUrl})`;
|
element.style.backgroundImage = `url(${finalUrl})`;
|
||||||
overlay.style.opacity = '0';
|
overlay.style.opacity = '0';
|
||||||
overlay.style.backgroundImage = '';
|
overlay.style.backgroundImage = '';
|
||||||
}, 1300);
|
}, TRANSITION_DURATION + 100);
|
||||||
} else if (backgroundData.style) {
|
} else if (backgroundData.style) {
|
||||||
element.setAttribute('style', backgroundData.style);
|
element.setAttribute('style', backgroundData.style);
|
||||||
}
|
}
|
||||||
@@ -104,7 +115,21 @@ export function useBackgroundRenderer(backgroundData) {
|
|||||||
applyBackground();
|
applyBackground();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (blobRef.current) URL.revokeObjectURL(blobRef.current);
|
// Cleanup blob URL
|
||||||
|
if (blobRef.current) {
|
||||||
|
URL.revokeObjectURL(blobRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abort pending image loads
|
||||||
|
if (abortControllerRef.current) {
|
||||||
|
abortControllerRef.current.abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove overlay element to prevent memory leak
|
||||||
|
const overlay = document.getElementById('backgroundOverlay');
|
||||||
|
if (overlay) {
|
||||||
|
overlay.remove();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [backgroundData.url, backgroundData.style, backgroundData.video, backgroundData.photoInfo]);
|
}, [backgroundData.url, backgroundData.style, backgroundData.video, backgroundData.photoInfo]);
|
||||||
}
|
}
|
||||||
@@ -113,12 +138,12 @@ export function useBackgroundRenderer(backgroundData) {
|
|||||||
* Hook to get computed filter styles (legacy - for video backgrounds)
|
* Hook to get computed filter styles (legacy - for video backgrounds)
|
||||||
*/
|
*/
|
||||||
export function useBackgroundFilters() {
|
export function useBackgroundFilters() {
|
||||||
return { WebkitFilter: getBackgroundFilterStyle() };
|
return useMemo(() => ({ WebkitFilter: getBackgroundFilterStyle() }), []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to get computed overlay filter styles
|
* Hook to get computed overlay filter styles
|
||||||
*/
|
*/
|
||||||
export function useBackgroundOverlayFilters() {
|
export function useBackgroundOverlayFilters() {
|
||||||
return getBackgroundOverlayStyle();
|
return useMemo(() => getBackgroundOverlayStyle(), []);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ const BackgroundOptions = memo(() => {
|
|||||||
|
|
||||||
const updateAPI = useCallback((e) => {
|
const updateAPI = useCallback((e) => {
|
||||||
localStorage.setItem('nextImage', null);
|
localStorage.setItem('nextImage', null);
|
||||||
|
// Clear prefetch queue when API changes to prevent showing cached images from old API
|
||||||
|
localStorage.removeItem('imageQueue');
|
||||||
if (e === 'mue') {
|
if (e === 'mue') {
|
||||||
setBackgroundCategories(backgroundCategoriesOG);
|
setBackgroundCategories(backgroundCategoriesOG);
|
||||||
setBackgroundAPI('mue');
|
setBackgroundAPI('mue');
|
||||||
@@ -177,7 +179,11 @@ const BackgroundOptions = memo(() => {
|
|||||||
<Dropdown
|
<Dropdown
|
||||||
label={variables.getMessage('modals.main.settings.sections.background.type.title')}
|
label={variables.getMessage('modals.main.settings.sections.background.type.title')}
|
||||||
name="backgroundType"
|
name="backgroundType"
|
||||||
onChange={(value) => setBackgroundType(value)}
|
onChange={(value) => {
|
||||||
|
// Clear prefetch queue when changing background type
|
||||||
|
localStorage.removeItem('imageQueue');
|
||||||
|
setBackgroundType(value);
|
||||||
|
}}
|
||||||
category="background"
|
category="background"
|
||||||
items={getBackgroundOptionItems(marketplaceEnabled)}
|
items={getBackgroundOptionItems(marketplaceEnabled)}
|
||||||
/>
|
/>
|
||||||
@@ -208,7 +214,11 @@ const BackgroundOptions = memo(() => {
|
|||||||
<SourceSection
|
<SourceSection
|
||||||
backgroundType={backgroundType}
|
backgroundType={backgroundType}
|
||||||
marketplaceEnabled={marketplaceEnabled}
|
marketplaceEnabled={marketplaceEnabled}
|
||||||
onTypeChange={(value) => setBackgroundType(value)}
|
onTypeChange={(value) => {
|
||||||
|
// Clear prefetch queue when changing background type
|
||||||
|
localStorage.removeItem('imageQueue');
|
||||||
|
setBackgroundType(value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{getBackgroundSettings()}
|
{getBackgroundSettings()}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ const APISettings = ({ backgroundAPI, backgroundCategories, onUpdateAPI }) => {
|
|||||||
label={variables.getMessage('modals.main.settings.sections.background.categories')}
|
label={variables.getMessage('modals.main.settings.sections.background.categories')}
|
||||||
options={backgroundCategories}
|
options={backgroundCategories}
|
||||||
name="apiCategories"
|
name="apiCategories"
|
||||||
|
onChange={() => {
|
||||||
|
// Clear prefetch queue when categories change
|
||||||
|
localStorage.removeItem('imageQueue');
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Dropdown
|
<Dropdown
|
||||||
@@ -43,6 +47,10 @@ const APISettings = ({ backgroundAPI, backgroundCategories, onUpdateAPI }) => {
|
|||||||
name="apiQuality"
|
name="apiQuality"
|
||||||
element=".other"
|
element=".other"
|
||||||
items={APIQualityOptions}
|
items={APIQualityOptions}
|
||||||
|
onChange={() => {
|
||||||
|
// Clear prefetch queue when quality changes
|
||||||
|
localStorage.removeItem('imageQueue');
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Radio
|
<Radio
|
||||||
title="API"
|
title="API"
|
||||||
@@ -81,6 +89,10 @@ const APISettings = ({ backgroundAPI, backgroundCategories, onUpdateAPI }) => {
|
|||||||
name="unsplashCollections"
|
name="unsplashCollections"
|
||||||
category="background"
|
category="background"
|
||||||
element="#backgroundImage"
|
element="#backgroundImage"
|
||||||
|
onChange={() => {
|
||||||
|
// Clear prefetch queue when Unsplash collections change
|
||||||
|
localStorage.removeItem('imageQueue');
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Action>
|
</Action>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
Reference in New Issue
Block a user