refactor: Improve tabbed container and add active class to selected tab

This commit is contained in:
sethburkart123
2024-09-17 17:59:00 +10:00
parent fea486aa52
commit f65dc92490
3 changed files with 34 additions and 29 deletions
@@ -72,7 +72,7 @@
> >
<div class="flex"> <div class="flex">
{#each tabs as { Content }, index} {#each tabs as { Content }, index}
<div class="absolute w-full h-full transition-opacity duration-300 overflow-y-scroll {activeTab === index ? 'opacity-100' : 'opacity-0'}" <div class="absolute w-full h-full transition-opacity duration-300 overflow-y-scroll tab {activeTab === index ? 'opacity-100 active' : 'opacity-0'}"
style="left: {index * 100}%;"> style="left: {index * 100}%;">
{@render Content()} {@render Content()}
</div> </div>
@@ -2,8 +2,8 @@
interface Background { interface Background {
id: string; id: string;
type: string; type: string;
blob: Blob; blob: Blob | null;
url?: string; url?: string | undefined;
} }
let { bg, isSelected, isEditMode, onClick, onDelete } = $props<{ bg: Background, isSelected: boolean, isEditMode: boolean, onClick: () => void, onDelete: () => void }>(); let { bg, isSelected, isEditMode, onClick, onDelete } = $props<{ bg: Background, isSelected: boolean, isEditMode: boolean, onClick: () => void, onDelete: () => void }>();
@@ -28,9 +28,11 @@
<div class="w-4 h-0.5 bg-white"></div> <div class="w-4 h-0.5 bg-white"></div>
</div> </div>
{/if} {/if}
{#if bg.url}
{#if bg.type === 'image'} {#if bg.type === 'image'}
<img class="object-cover w-full h-full rounded-xl" src={bg.url} alt="swatch" /> <img class="object-cover w-full h-full rounded-xl" src={bg.url} alt="swatch" />
{:else if bg.type === 'video'} {:else if bg.type === 'video'}
<video muted loop autoplay src={bg.url} class="object-cover w-full h-full rounded-xl"></video> <video muted loop autoplay src={bg.url} class="object-cover w-full h-full rounded-xl"></video>
{/if} {/if}
{/if}
</div> </div>
@@ -2,21 +2,21 @@
import { hasEnoughStorageSpace, isIndexedDBSupported, writeData, openDatabase, readAllData, deleteData } from '@/svelte-interface/hooks/BackgroundDataLoader' import { hasEnoughStorageSpace, isIndexedDBSupported, writeData, openDatabase, readAllData, deleteData } from '@/svelte-interface/hooks/BackgroundDataLoader'
import BackgroundUploader from './BackgroundUploader.svelte'; import BackgroundUploader from './BackgroundUploader.svelte';
import BackgroundItem from './BackgroundItem.svelte' import BackgroundItem from './BackgroundItem.svelte'
import { onMount } from 'svelte' import { onMount, onDestroy } from 'svelte'
import { loadBackground } from '@/seqta/ui/ImageBackgrounds' import { loadBackground } from '@/seqta/ui/ImageBackgrounds'
import { delay } from 'lodash' import { delay } from 'lodash'
let { isEditMode, selectNoBackground = $bindable(), selectedBackground = $bindable() } = $props<{ isEditMode: boolean, selectNoBackground: () => void, selectedBackground: string | null }>(); let { isEditMode, selectNoBackground = $bindable(), selectedBackground = $bindable() } = $props<{ isEditMode: boolean, selectNoBackground: () => void, selectedBackground: string | null }>();
let backgrounds = $state<{ id: string; type: string; blob: Blob; url?: string }[]>([]); let backgrounds = $state<{ id: string; type: string; blob: Blob | null; url?: string }[]>([]);
let isLoading = $state<boolean>(false);
let error = $state<string | null>(null); let error = $state<string | null>(null);
let imageBackgrounds = $derived(backgrounds.filter(bg => bg.type === 'image')); let imageBackgrounds = $derived(backgrounds.filter(bg => bg.type === 'image'));
let videoBackgrounds = $derived(backgrounds.filter(bg => bg.type === 'video')); let videoBackgrounds = $derived(backgrounds.filter(bg => bg.type === 'video'));
let isVisible = $state(false); let isVisible = $state(false);
let observer: IntersectionObserver;
let element: HTMLElement; let element: HTMLElement;
let observer: MutationObserver;
let parentElement: HTMLElement | null = null;
async function getTheme() { async function getTheme() {
return localStorage.getItem('selectedBackground'); return localStorage.getItem('selectedBackground');
@@ -56,7 +56,6 @@
async function loadBackgroundMetadata(): Promise<void> { async function loadBackgroundMetadata(): Promise<void> {
try { try {
isLoading = true;
error = null; error = null;
if (!isIndexedDBSupported()) { if (!isIndexedDBSupported()) {
@@ -75,14 +74,11 @@
} else { } else {
error = 'An unknown error occurred'; error = 'An unknown error occurred';
} }
} finally {
isLoading = false;
} }
} }
async function loadFullBackgrounds(): Promise<void> { async function loadFullBackgrounds(): Promise<void> {
try { try {
isLoading = true;
error = null; error = null;
if (!isIndexedDBSupported()) { if (!isIndexedDBSupported()) {
@@ -97,8 +93,6 @@
} else { } else {
error = 'An unknown error occurred'; error = 'An unknown error occurred';
} }
} finally {
isLoading = false;
} }
} }
@@ -152,24 +146,33 @@
} }
}); });
onMount(() => { function checkActiveClass() {
loadBackgroundMetadata(); if (parentElement?.classList.contains('active')) {
observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
delay(() => { delay(() => {
isVisible = true; isVisible = true;
loadFullBackgrounds(); loadFullBackgrounds();
}, 450); }, 600);
observer.disconnect(); }
} }
});
observer.observe(element); onMount(() => {
loadBackgroundMetadata();
parentElement = element.closest('.tab');
if (parentElement) {
observer = new MutationObserver(checkActiveClass);
observer.observe(parentElement, { attributes: true, attributeFilter: ['class'] });
return () => { return () => {
observer.disconnect(); observer.disconnect();
}; };
}
});
onDestroy(() => {
if (observer) {
observer.disconnect();
}
}); });
</script> </script>