From 1a006e75b8ba59e7a126e306df86d2ec631c4815 Mon Sep 17 00:00:00 2001 From: sHa Date: Thu, 12 Jun 2025 17:34:43 +0300 Subject: [PATCH] feat: Enhance filtering capabilities by adding support for variants in Filter, Header, and Home components --- src/App.svelte | 184 +++++++++++++++++++++++++---------- src/components/Filter.svelte | 130 +++++++++++++++++++++++-- src/components/Header.svelte | 8 +- src/pages/Home.svelte | 25 +++++ 4 files changed, 288 insertions(+), 59 deletions(-) diff --git a/src/App.svelte b/src/App.svelte index bc2db30..5aa88bb 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -51,11 +51,9 @@ (logo.brand && selectedBrands.includes(logo.brand)); const matchesVariants = !selectedVariants.length || - (logo.variant && ( - Array.isArray(logo.variant) - ? logo.variant.some((v) => selectedVariants.includes(v)) - : selectedVariants.includes(logo.variant) - )); + (logo.variants && + Array.isArray(logo.variants) && + logo.variants.some((v) => selectedVariants.includes(v))); return matchesSearch && matchesTags && matchesBrands && matchesVariants; }); @@ -223,7 +221,51 @@ const searchParam = params.get("search"); if (searchParam) { searchQuery = searchParam; - } // Restore view mode and compact mode from localStorage + } + + // Restore selected tags from URL + const tagsParam = params.get("tags"); + if (tagsParam) { + selectedTags = tagsParam.split(",").filter(tag => tag.trim()); + console.log("App: Restored selectedTags from URL:", selectedTags); + // Update localStorage with URL values + localStorage.setItem("selectedTags", JSON.stringify(selectedTags)); + } + + // Restore selected brands from URL + const brandsParam = params.get("brands"); + if (brandsParam) { + selectedBrands = brandsParam.split(",").filter(brand => brand.trim()); + console.log("App: Restored selectedBrands from URL:", selectedBrands); + // Update localStorage with URL values localStorage.setItem("selectedBrands", JSON.stringify(selectedBrands)); + } + + // Restore selected variants from URL + const variantsParam = params.get("variants"); + if (variantsParam) { + selectedVariants = variantsParam.split(",").filter(variant => variant.trim()); + console.log("App: Restored selectedVariants from URL:", selectedVariants); + // Update localStorage with URL values + localStorage.setItem("selectedVariants", JSON.stringify(selectedVariants)); + } + + // Force update window.appData after restoration + setTimeout(() => { + if (typeof window !== "undefined" && window.appData) { + window.appData.selectedTags = [...selectedTags]; + window.appData.selectedBrands = [...selectedBrands]; + window.appData.selectedVariants = [...selectedVariants]; + console.log("App: Updated window.appData after restoration with variants:", selectedVariants); + updateFilteredLogosImmediate(); + + // Force re-render of components by updating references + selectedTags = [...selectedTags]; + selectedBrands = [...selectedBrands]; + selectedVariants = [...selectedVariants]; + } + }, 100); + + // Restore view mode and compact mode from localStorage const savedViewMode = localStorage.getItem("viewMode"); if (savedViewMode === "grid" || savedViewMode === "list" || savedViewMode === "compact") { viewMode = savedViewMode; @@ -233,48 +275,54 @@ setCompactMode(savedCompact === "true"); } - // Restore selected tags from localStorage - const savedTags = localStorage.getItem("selectedTags"); - if (savedTags) { - try { - const parsedTags = JSON.parse(savedTags); - if (Array.isArray(parsedTags)) { - selectedTags = parsedTags; - console.log("App: Restored selectedTags from localStorage:", selectedTags); + // Restore selected tags from localStorage (only if not already set from URL) + if (!tagsParam) { + const savedTags = localStorage.getItem("selectedTags"); + if (savedTags) { + try { + const parsedTags = JSON.parse(savedTags); + if (Array.isArray(parsedTags)) { + selectedTags = parsedTags; + console.log("App: Restored selectedTags from localStorage:", selectedTags); + } + } catch (error) { + console.error("App: Error parsing saved tags:", error); + localStorage.removeItem("selectedTags"); } - } catch (error) { - console.error("App: Error parsing saved tags:", error); - localStorage.removeItem("selectedTags"); } } - // Restore selected brands from localStorage - const savedBrands = localStorage.getItem("selectedBrands"); - if (savedBrands) { - try { - const parsedBrands = JSON.parse(savedBrands); - if (Array.isArray(parsedBrands)) { - selectedBrands = parsedBrands; - console.log("App: Restored selectedBrands from localStorage:", selectedBrands); + // Restore selected brands from localStorage (only if not already set from URL) + if (!brandsParam) { + const savedBrands = localStorage.getItem("selectedBrands"); + if (savedBrands) { + try { + const parsedBrands = JSON.parse(savedBrands); + if (Array.isArray(parsedBrands)) { + selectedBrands = parsedBrands; + console.log("App: Restored selectedBrands from localStorage:", selectedBrands); + } + } catch (error) { + console.error("App: Error parsing saved brands:", error); + localStorage.removeItem("selectedBrands"); } - } catch (error) { - console.error("App: Error parsing saved brands:", error); - localStorage.removeItem("selectedBrands"); } } - // Restore selected variants from localStorage - const savedVariants = localStorage.getItem("selectedVariants"); - if (savedVariants) { - try { - const parsedVariants = JSON.parse(savedVariants); - if (Array.isArray(parsedVariants)) { - selectedVariants = parsedVariants; - console.log("App: Restored selectedVariants from localStorage:", selectedVariants); + // Restore selected variants from localStorage (only if not already set from URL) + if (!variantsParam) { + const savedVariants = localStorage.getItem("selectedVariants"); + if (savedVariants) { + try { + const parsedVariants = JSON.parse(savedVariants); + if (Array.isArray(parsedVariants)) { + selectedVariants = parsedVariants; + console.log("App: Restored selectedVariants from localStorage:", selectedVariants); + } + } catch (error) { + console.error("App: Error parsing saved variants:", error); + localStorage.removeItem("selectedVariants"); } - } catch (error) { - console.error("App: Error parsing saved variants:", error); - localStorage.removeItem("selectedVariants"); } } }); @@ -314,11 +362,9 @@ (logo.brand && selectedBrands.includes(logo.brand)); const matchesVariants = !selectedVariants.length || - (logo.variant && ( - Array.isArray(logo.variant) - ? logo.variant.some((v) => selectedVariants.includes(v)) - : selectedVariants.includes(logo.variant) - )); + (logo.variants && + Array.isArray(logo.variants) && + logo.variants.some((v) => selectedVariants.includes(v))); return matchesSearch && matchesTags && matchesBrands && matchesVariants; }); @@ -604,17 +650,51 @@ } function addVariant(variant) { + console.log("App: Adding variant:", variant); if (!selectedVariants.includes(variant)) { selectedVariants = [...selectedVariants, variant]; localStorage.setItem("selectedVariants", JSON.stringify(selectedVariants)); - updateFilteredLogosImmediate(); + console.log("App: Updated selectedVariants:", selectedVariants); + + // Update window.appData immediately + if (typeof window !== "undefined" && window.appData) { + window.appData.selectedVariants = [...selectedVariants]; + console.log("App: Updated selectedVariants in window.appData"); + + // Update filtered logos immediately + updateFilteredLogosImmediate(); + } } + + // Close dropdown after adding variant + tagDropdownOpen = false; + + // Also update the dropdown state in window.appData + if (typeof window !== "undefined" && window.appData) { + window.appData.tagDropdownOpen = false; + } + + // Force reactive update + selectedVariants = selectedVariants; } function removeVariant(variant) { + console.log("App: Removing variant:", variant); selectedVariants = selectedVariants.filter((v) => v !== variant); localStorage.setItem("selectedVariants", JSON.stringify(selectedVariants)); - updateFilteredLogosImmediate(); + console.log("App: Updated selectedVariants:", selectedVariants); + + // Update window.appData immediately + if (typeof window !== "undefined" && window.appData) { + window.appData.selectedVariants = [...selectedVariants]; + console.log("App: Updated selectedVariants in window.appData"); + + // Update filtered logos immediately + updateFilteredLogosImmediate(); + } + + // Force reactive update + selectedVariants = selectedVariants; } // Helper function to immediately update filtered/display logos in window.appData @@ -636,11 +716,9 @@ (logo.brand && selectedBrands.includes(logo.brand)); const matchesVariants = !selectedVariants.length || - (logo.variant && ( - Array.isArray(logo.variant) - ? logo.variant.some((v) => selectedVariants.includes(v)) - : selectedVariants.includes(logo.variant) - )); + (logo.variants && + Array.isArray(logo.variants) && + logo.variants.some((v) => selectedVariants.includes(v))); return matchesSearch && matchesTags && matchesBrands && matchesVariants; }); @@ -659,6 +737,10 @@ window.appData.filteredLogos.length, window.appData.displayLogos.length, ); + + // Force update the main reactive statements as well + filteredLogos = [...window.appData.filteredLogos]; + displayLogos = [...window.appData.displayLogos]; } } diff --git a/src/components/Filter.svelte b/src/components/Filter.svelte index 52e7d89..fc233f4 100644 --- a/src/components/Filter.svelte +++ b/src/components/Filter.svelte @@ -3,18 +3,21 @@ export let allTags = []; export let selectedTags = []; export let selectedBrands = []; + export let selectedVariants = []; export let tagDropdownOpen = false; export let toggleDropdown = () => console.log("toggleDropdown not provided"); export let addTag = () => console.log("addTag not provided"); export let removeTag = () => console.log("removeTag not provided"); export let addBrand = () => console.log("addBrand not provided"); export let removeBrand = () => console.log("removeBrand not provided"); + export let addVariant = () => console.log("addVariant not provided"); + export let removeVariant = () => console.log("removeVariant not provided"); export let getTagObj = (tag) => ({ text: tag }); export let compactMode = false; export let setCompactMode = () => {}; let tagSearchQuery = ""; // Search query for filtering tags - let activeTab = "categories"; // "categories" or "brands" + let activeTab = "categories"; // "categories", "brands", or "variants" // Filter available tags based on search query $: filteredAvailableTags = allTags.filter( @@ -37,11 +40,26 @@ ) ).sort(); + // Compute all unique variants + $: allVariants = Array.from( + new Set( + allLogos + .filter((logo) => logo.variants && Array.isArray(logo.variants)) + .flatMap((logo) => logo.variants) + .filter((variant) => variant && variant.trim() !== "") + ) + ).sort(); + // Filter brands based on search query $: filteredAllBrands = allBrands.filter((brand) => brand.toLowerCase().includes(tagSearchQuery.toLowerCase()) ); + // Filter variants based on search query + $: filteredAllVariants = allVariants.filter((variant) => + variant.toLowerCase().includes(tagSearchQuery.toLowerCase()) + ); + function toggleBrand(brand) { if (selectedBrands.includes(brand)) { selectedBrands = selectedBrands.filter(b => b !== brand); @@ -56,6 +74,17 @@ updateFilterParams(); } + function toggleVariant(variant) { + if (selectedVariants.includes(variant)) { + removeVariant(variant); + } else { + addVariant(variant); + } + + // Update URL parameters + updateFilterParams(); + } + function updateFilterParams() { const params = new URLSearchParams(window.location.search); @@ -73,6 +102,13 @@ params.delete("brands"); } + // Update variants + if (selectedVariants.length > 0) { + params.set("variants", selectedVariants.join(",")); + } else { + params.delete("variants"); + } + const newUrl = window.location.pathname + (params.toString() ? "?" + params.toString() : ""); history.replaceState(null, "", newUrl); } @@ -98,9 +134,9 @@ fill="currentColor" /> - {#if selectedTags.length + selectedBrands.length + (compactMode ? 1 : 0) > 0} + {#if selectedTags.length + selectedBrands.length + selectedVariants.length + (compactMode ? 1 : 0) > 0} {selectedTags.length + selectedBrands.length + (compactMode ? 1 : 0)}{selectedTags.length + selectedBrands.length + selectedVariants.length + (compactMode ? 1 : 0)} {/if} @@ -138,7 +174,7 @@ - {#if filteredAvailableTags.length > 0 || tagSearchQuery || allBrands.length > 0} + {#if filteredAvailableTags.length > 0 || tagSearchQuery || allBrands.length > 0 || allVariants.length > 0}
@@ -156,12 +192,19 @@ > Brands +
{/if} - {:else} + {:else if activeTab === "brands"} {#if filteredAllBrands.length > 0}
{#each filteredAllBrands as brand} @@ -275,11 +318,49 @@ : "No available brands"}
{/if} + {:else if activeTab === "variants"} + {#if filteredAllVariants.length > 0} +
+ {#each filteredAllVariants as variant} + {@const isSelected = selectedVariants.includes(variant)} + + {/each} +
+ {:else} +
+ {tagSearchQuery + ? "No variants match your search" + : "No available variants"} +
+ {/if} {/if}
{/if} - {#if selectedTags.length > 0 || selectedBrands.length > 0 || compactMode} + {#if selectedTags.length > 0 || selectedBrands.length > 0 || selectedVariants.length > 0 || compactMode}
{/each} + {#each selectedVariants as variant} + + {/each} + {#if compactMode}
- {#if (searchQuery && searchQuery.trim() !== "") || selectedTags.length > 0 || selectedBrands.length > 0 || compactMode} + {#if (searchQuery && searchQuery.trim() !== "") || selectedTags.length > 0 || selectedBrands.length > 0 || selectedVariants.length > 0 || compactMode} {displayLogos ? displayLogos.length : 0} of {allLogos ? allLogos.length : 0} images displayed {:else} @@ -55,12 +58,15 @@ {allTags} {selectedTags} {selectedBrands} + {selectedVariants} {tagDropdownOpen} {toggleDropdown} {addTag} {removeTag} {addBrand} {removeBrand} + {addVariant} + {removeVariant} {getTagObj} {compactMode} {setCompactMode} diff --git a/src/pages/Home.svelte b/src/pages/Home.svelte index 1cc46a1..9ba4a8b 100644 --- a/src/pages/Home.svelte +++ b/src/pages/Home.svelte @@ -15,8 +15,11 @@ let selectedTags = []; let allTags = []; let selectedBrands = []; + let selectedVariants = []; let addBrand = () => {}; let removeBrand = () => {}; + let addVariant = () => {}; + let removeVariant = () => {}; let setTheme = () => {}; @@ -31,6 +34,7 @@ allTags = [], selectedTags = [], selectedBrands = [], + selectedVariants = [], tagDropdownOpen = false, compactMode = false, setSearchQuery = () => {}, @@ -43,6 +47,8 @@ removeTag = () => {}, addBrand = () => {}, removeBrand = () => {}, + addVariant = () => {}, + removeVariant = () => {}, toggleTag = () => {}, getTagObj = () => ({ text: "" }), closeDropdown = () => {}, @@ -83,6 +89,18 @@ selectedBrands = window.appData.selectedBrands; } + if (window.appData.addVariant && typeof window.appData.addVariant === 'function') { + addVariant = window.appData.addVariant; + } + + if (window.appData.removeVariant && typeof window.appData.removeVariant === 'function') { + removeVariant = window.appData.removeVariant; + } + + if (window.appData.selectedVariants) { + selectedVariants = window.appData.selectedVariants; + } + // Set up reactivity with window.appData const interval = setInterval(() => { if (window.appData) { @@ -108,6 +126,10 @@ if (window.appData.selectedBrands) { selectedBrands = [...window.appData.selectedBrands]; } + + if (window.appData.selectedVariants) { + selectedVariants = [...window.appData.selectedVariants]; + } } }, 100); @@ -200,12 +222,15 @@ allTags={allTags} selectedTags={selectedTags} selectedBrands={selectedBrands} + selectedVariants={selectedVariants} {tagDropdownOpen} {toggleDropdown} {addTag} {removeTag} addBrand={addBrand} removeBrand={removeBrand} + addVariant={addVariant} + removeVariant={removeVariant} getTagObj={(tag) => (window.appData?.getTagObj ? window.appData.getTagObj(tag) : {text: tag})} {compactMode} {setCompactMode}