diff --git a/src/lib/components/functional/FormatDropdown.svelte b/src/lib/components/functional/FormatDropdown.svelte index 163384f..ed315d1 100644 --- a/src/lib/components/functional/FormatDropdown.svelte +++ b/src/lib/components/functional/FormatDropdown.svelte @@ -21,22 +21,77 @@ disabled, settingsStyle, }: Props = $props(); - let open = $state(false); let hover = $state(false); - let isUp = $state(false); let dropdown = $state(); let currentCategory = $state(); - let shownCategories = $state(Object.keys(categories)); + let searchQuery = $state(""); + + // initialize current category + $effect(() => { + if (!currentCategory) { + if (selected) { + const foundCat = Object.keys(categories).find((cat) => + categories[cat].formats.includes(selected), + ); + currentCategory = + foundCat || Object.keys(categories)[0] || null; + } else { + // find category based on file types + const fileFormats = files.files.map((f) => f.from); + const foundCat = Object.keys(categories).find((cat) => + fileFormats.some((format) => + categories[cat].formats.includes(format), + ), + ); + currentCategory = + foundCat || Object.keys(categories)[0] || null; + } + } + }); + + // other available categories based on current category (e.g. converting between video and audio) + const availableCategories = $derived.by(() => { + if (!currentCategory) return Object.keys(categories); + + return Object.keys(categories).filter( + (cat) => + cat === currentCategory || + categories[cat].canConvertTo?.includes(currentCategory || ""), + ); + }); + + const filteredData = $derived.by(() => { + if (!searchQuery) { + return { + categories: availableCategories, + formats: currentCategory + ? categories[currentCategory].formats + : [], + }; + } + + // filter formats across all available categories + const allFormats = availableCategories.flatMap((cat) => + categories[cat].formats.filter((format) => + format.toLowerCase().includes(searchQuery.toLowerCase()), + ), + ); + + // filter categories that have matching formats + const matchingCategories = availableCategories.filter((cat) => + categories[cat].formats.some((format) => + format.toLowerCase().includes(searchQuery.toLowerCase()), + ), + ); + + return { + categories: matchingCategories, + formats: allFormats, + }; + }); const selectOption = (option: string) => { - const oldIndex = - currentCategory && - categories[currentCategory]?.formats.indexOf(selected || ""); - const newIndex = - currentCategory && - categories[currentCategory]?.formats.indexOf(option); - isUp = (oldIndex ?? 0) > (newIndex ?? 0); selected = option; open = false; onselect?.(option); @@ -45,74 +100,39 @@ const selectCategory = (category: string) => { if (categories[category]) { currentCategory = category; - console.log(`Selected category: ${category}`); - console.log(`Formats: ${categories[category].formats.join(", ")}`); + // clear search when switching categories + searchQuery = ""; } }; - const search = (event: Event) => { - const query = (event.target as HTMLInputElement).value; - console.log(`Searching for: ${query}`); - // TODO: search logic + const handleSearch = (event: Event) => { + searchQuery = (event.target as HTMLInputElement).value; }; onMount(() => { - const click = (e: MouseEvent) => { + const handleClickOutside = (e: MouseEvent) => { if (dropdown && !dropdown.contains(e.target as Node)) { open = false; } }; - window.addEventListener("click", click); + window.addEventListener("click", handleClickOutside); + return () => window.removeEventListener("click", handleClickOutside); + }); - // depending on selected, find category - if (selected) { - currentCategory = Object.keys(categories).find((cat) => - categories[cat].formats.includes(selected), + // initialize selected format if none chosen + $effect(() => { + if ( + !selected && + currentCategory && + categories[currentCategory]?.formats?.length > 0 + ) { + const from = files.files[0]?.from; + const firstDiff = categories[currentCategory].formats.find( + (f) => f !== from, ); - if (!currentCategory) { - currentCategory = Object.keys(categories)[0] || null; - } - - shownCategories = Object.keys(categories).filter( - (cat) => - cat === currentCategory || - categories[cat].canConvertTo?.includes( - currentCategory || "", - ), - ); - } else { - // find current category based on files - const fileCategories = [ - ...new Set( - files.files - .map(f => - Object.keys(categories).find(cat => - categories[cat].formats.includes(f.from), - ), - ) - .filter(Boolean), - ), - ]; - currentCategory = fileCategories[0] || Object.keys(categories)[0] || null; - - // only show categories that can convert to current category / itself - shownCategories = Object.keys(categories).filter( - cat => - cat === currentCategory || - categories[cat].canConvertTo?.includes(currentCategory || ""), - ); - - // if no selected format, select first format of current category - if ( - !selected && - currentCategory && - categories[currentCategory].formats.length > 0 - ) - selected = categories[currentCategory].formats[0]; + selected = firstDiff || categories[currentCategory].formats[0]; } - - return () => window.removeEventListener("click", click); }); @@ -192,7 +212,8 @@ type="text" placeholder="Search format" class="flex-grow w-full !pl-11 !pr-3 rounded-lg bg-panel text-foreground" - oninput={search} + bind:value={searchQuery} + oninput={handleSearch} /> - +
- {#each shownCategories as category} + {#each filteredData.categories as category} - {/each} - {/if} + {#each filteredData.formats as format} + + {/each}
{/if}