feat: enhance BackgroundImageSelector with custom image management
- Removed preserved custom URL handling and replaced it with a custom images array for better management of user-added backgrounds. - Updated the component to allow adding, selecting, and removing custom images, improving user experience and flexibility. - Adjusted background cycling logic to include custom images, ensuring a seamless integration with existing backgrounds.
This commit is contained in:
@@ -87,19 +87,11 @@ export function BackgroundImageSelector() {
|
||||
const [customUrl, setCustomUrl] = useState('');
|
||||
const [showCustomInput, setShowCustomInput] = useState(false);
|
||||
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
|
||||
const [preservedCustomUrl, setPreservedCustomUrl] = useState<string>('');
|
||||
|
||||
const currentBackground = preferences?.viewPreferences?.backgroundImage;
|
||||
const backgroundBlur = preferences?.viewPreferences?.backgroundBlur || 0;
|
||||
const backgroundOpacity = preferences?.viewPreferences?.backgroundOpacity || 100;
|
||||
|
||||
// Préserver l'URL personnalisée si elle existe
|
||||
useEffect(() => {
|
||||
if (currentBackground && !PRESET_BACKGROUNDS.some(preset => preset.id === currentBackground)) {
|
||||
setPreservedCustomUrl(currentBackground);
|
||||
localStorage.setItem('preservedCustomBackground', currentBackground);
|
||||
}
|
||||
}, [currentBackground]);
|
||||
const customImages = preferences?.viewPreferences?.customImages || [];
|
||||
|
||||
const handlePresetSelect = (presetId: string) => {
|
||||
const backgroundImage = presetId === 'none' ? undefined : presetId;
|
||||
@@ -110,23 +102,33 @@ export function BackgroundImageSelector() {
|
||||
if (!customUrl.trim()) return;
|
||||
|
||||
const url = customUrl.trim();
|
||||
|
||||
// Ajouter l'image aux images personnalisées si elle n'existe pas déjà
|
||||
if (!customImages.includes(url)) {
|
||||
const newCustomImages = [...customImages, url];
|
||||
updateViewPreferences({
|
||||
backgroundImage: url,
|
||||
customImages: newCustomImages
|
||||
});
|
||||
} else {
|
||||
// Si elle existe déjà, juste la sélectionner
|
||||
updateViewPreferences({ backgroundImage: url });
|
||||
setPreservedCustomUrl(url);
|
||||
localStorage.setItem('preservedCustomBackground', url);
|
||||
}
|
||||
|
||||
setCustomUrl('');
|
||||
setShowCustomInput(false);
|
||||
};
|
||||
|
||||
const handleRemoveCustom = () => {
|
||||
updateViewPreferences({ backgroundImage: undefined });
|
||||
setPreservedCustomUrl('');
|
||||
localStorage.removeItem('preservedCustomBackground');
|
||||
const handleRemoveCustomImage = (urlToRemove: string) => {
|
||||
const newCustomImages = customImages.filter(url => url !== urlToRemove);
|
||||
updateViewPreferences({
|
||||
customImages: newCustomImages,
|
||||
backgroundImage: currentBackground === urlToRemove ? undefined : currentBackground
|
||||
});
|
||||
};
|
||||
|
||||
const handleRestoreCustom = () => {
|
||||
if (preservedCustomUrl) {
|
||||
updateViewPreferences({ backgroundImage: preservedCustomUrl });
|
||||
}
|
||||
const handleSelectCustomImage = (url: string) => {
|
||||
updateViewPreferences({ backgroundImage: url });
|
||||
};
|
||||
|
||||
const handleBlurChange = (blur: number) => {
|
||||
@@ -219,6 +221,60 @@ export function BackgroundImageSelector() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Images personnalisées */}
|
||||
{customImages.length > 0 && (
|
||||
<Card variant="glass">
|
||||
<CardContent className="p-4">
|
||||
<div className="text-sm text-[var(--muted-foreground)] mb-4">Images personnalisées :</div>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
|
||||
{customImages.map((url, index) => (
|
||||
<div key={url} className="relative">
|
||||
<Button
|
||||
onClick={() => handleSelectCustomImage(url)}
|
||||
variant={currentBackground === url ? 'selected' : 'secondary'}
|
||||
className="p-3 h-auto text-left justify-start w-full"
|
||||
>
|
||||
<div className="flex items-start gap-3 w-full">
|
||||
{/* Aperçu */}
|
||||
<div
|
||||
className="w-12 h-8 rounded border border-[var(--border)]/30 flex-shrink-0 bg-cover bg-center"
|
||||
style={{ backgroundImage: `url("${url}")` }}
|
||||
/>
|
||||
|
||||
<div className="flex-1 min-w-0 pr-8">
|
||||
<div className="font-medium text-[var(--foreground)] mb-1">
|
||||
Image {index + 1}
|
||||
</div>
|
||||
<div className="text-xs text-[var(--muted-foreground)] leading-relaxed truncate">
|
||||
{url.length > 25 ? `${url.substring(0, 25)}...` : url}
|
||||
</div>
|
||||
{currentBackground === url && (
|
||||
<div className="mt-1 text-xs text-[var(--primary)] font-medium">
|
||||
✓ Sélectionné
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
|
||||
{/* Bouton supprimer - positionné absolument */}
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemoveCustomImage(url);
|
||||
}}
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
className="absolute top-2 right-2 px-2 py-1 text-xs h-6 w-6 min-w-0"
|
||||
>
|
||||
×
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* URL personnalisée */}
|
||||
<Card>
|
||||
@@ -231,17 +287,6 @@ export function BackgroundImageSelector() {
|
||||
Ajoutez votre propre image de fond
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{preservedCustomUrl && (
|
||||
<Button
|
||||
onClick={handleRestoreCustom}
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
className="text-xs"
|
||||
>
|
||||
Restaurer
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
onClick={() => setShowCustomInput(!showCustomInput)}
|
||||
variant="secondary"
|
||||
@@ -250,7 +295,6 @@ export function BackgroundImageSelector() {
|
||||
{showCustomInput ? 'Masquer' : 'Ajouter'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showCustomInput && (
|
||||
<div className="space-y-3">
|
||||
@@ -282,17 +326,6 @@ export function BackgroundImageSelector() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Bouton pour supprimer l'image personnalisée */}
|
||||
{currentBackground && !PRESET_BACKGROUNDS.find(p => p.id === currentBackground) && (
|
||||
<Button
|
||||
onClick={handleRemoveCustom}
|
||||
variant="destructive"
|
||||
className="w-full"
|
||||
>
|
||||
Supprimer l'image personnalisée
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -23,23 +23,17 @@ export function useBackgroundCycle() {
|
||||
|
||||
const cycleBackground = () => {
|
||||
const currentBackground = preferences?.viewPreferences?.backgroundImage;
|
||||
const customImages = preferences?.viewPreferences?.customImages || [];
|
||||
|
||||
// Construire la liste complète des backgrounds (prédéfinis + personnalisé)
|
||||
// Construire la liste complète des backgrounds (prédéfinis + personnalisés)
|
||||
const allBackgrounds = [...BACKGROUND_CYCLE];
|
||||
|
||||
// Ajouter l'image personnalisée préservée si elle existe
|
||||
const preservedCustomUrl = localStorage.getItem('preservedCustomBackground');
|
||||
|
||||
if (preservedCustomUrl && !BACKGROUND_CYCLE.includes(preservedCustomUrl)) {
|
||||
allBackgrounds.push(preservedCustomUrl);
|
||||
}
|
||||
|
||||
// Ajouter aussi l'image actuelle si elle est personnalisée ET différente de celle préservée
|
||||
if (currentBackground &&
|
||||
!BACKGROUND_CYCLE.includes(currentBackground) &&
|
||||
currentBackground !== preservedCustomUrl) {
|
||||
allBackgrounds.push(currentBackground);
|
||||
// Ajouter toutes les images personnalisées
|
||||
customImages.forEach(url => {
|
||||
if (!allBackgrounds.includes(url)) {
|
||||
allBackgrounds.push(url);
|
||||
}
|
||||
});
|
||||
|
||||
const currentIndex = allBackgrounds.findIndex(bg => bg === currentBackground);
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ export interface ViewPreferences {
|
||||
backgroundImage?: string;
|
||||
backgroundBlur?: number;
|
||||
backgroundOpacity?: number;
|
||||
customImages?: string[];
|
||||
[key: string]:
|
||||
| boolean
|
||||
| 'tags'
|
||||
@@ -117,6 +118,7 @@ export interface ViewPreferences {
|
||||
| 'large'
|
||||
| string
|
||||
| number
|
||||
| string[]
|
||||
| undefined;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user