diff --git a/public/data/logos.json b/public/data/logos.json index 4093b86..35eca97 100644 --- a/public/data/logos.json +++ b/public/data/logos.json @@ -3,60 +3,90 @@ "name": "Apple (black)", "path": "logos/apple_black.svg", "format": "SVG", - "disable": false + "disable": false, + "tags": [ + {"text":"tech", "color": "silver"} + ] }, { "name": "ATB", "path": "logos/atb.svg", "format": "SVG", - "disable": false + "disable": false, + "tags": [ + "retail" + ] }, { "name": "Binance", "path": "logos/binance.svg", "format": "SVG", - "disable": false + "disable": false, + "tags": [ + "crypto", + "finance", + "exchange" + ] }, { "name": "Dalnoboy Service", "path": "logos/dalnoboy-service.svg", "format": "SVG", - "disable": false + "disable": false, + "tags": [] }, { "name": "Google", "path": "logos/google.svg", "format": "SVG", - "disable": false + "disable": false, + "tags": [] }, { "name": "Privatbank", "path": "logos/privatbank.png", "format": "PNG", - "disable": false + "disable": false, + "tags": [ + "bank", + "finance" + ] }, { "name": "Pumb", "path": "logos/pumb.png", "format": "PNG", - "disable": false + "disable": false, + "tags": [ + "bank", + "finance" + ] }, { "name": "Roomerin", "path": "logos/roomerin.svg", "format": "SVG", - "disable": false + "disable": false, + "tags": [ + "furniture" + ] }, { "name": "Shkafnik", "path": "logos/shkafnik.svg", "format": "SVG", - "disable": false + "disable": false, + "tags": [ + "furniture" + ] }, { "name": "Shkafnik Small", "path": "logos/shkafnik_small.png", "format": "PNG", - "disable": false + "disable": false, + "tags": [ + "furniture" + ] } -] \ No newline at end of file +] diff --git a/scripts/scanLogos.js b/scripts/scanLogos.js index 619e52d..8971785 100644 --- a/scripts/scanLogos.js +++ b/scripts/scanLogos.js @@ -61,9 +61,10 @@ function scanLogos() { const format = getFileExtension(file); const logoPath = `logos/${file}`; const existingItem = existingMap.get(logoPath); + let logoObj; if (existingItem) { - // Preserve name and disable, update format/path - return { + // Preserve name, tags, and disable, update format/path + logoObj = { ...existingItem, path: logoPath, format: format, @@ -71,13 +72,18 @@ function scanLogos() { }; } else { // New logo - return { + logoObj = { name: formatName(file), path: logoPath, format: format, disable: false }; } + // Ensure tags field exists and is an array + if (!Array.isArray(logoObj.tags)) { + logoObj.tags = []; + } + return logoObj; }); return logos; } catch (error) { diff --git a/src/App.svelte b/src/App.svelte index bc686a3..e39dd83 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -9,6 +9,9 @@ let filteredLogos = []; let theme = 'system'; let mq; + let allTags = []; + let selectedTags = []; + let tagDropdownOpen = false; // Load logos from JSON file with cache busting onMount(async () => { @@ -53,11 +56,21 @@ applyTheme(); } - $: { - filteredLogos = logos.filter(logo => - logo.name.toLowerCase().includes(searchQuery.toLowerCase()) - ); - } + // Compute all unique tags as objects with text and optional color + $: allTags = Array.from( + new Map( + logos.flatMap(logo => (logo.tags || []).map(tag => { + if (typeof tag === 'string') return [tag, { text: tag }]; + return [tag.text, tag]; + })) + ).values() + ).sort((a, b) => a.text.localeCompare(b.text)); + + $: filteredLogos = logos.filter(logo => { + const matchesSearch = logo.name.toLowerCase().includes(searchQuery.toLowerCase()); + const matchesTags = !selectedTags.length || (logo.tags && logo.tags.some(tag => selectedTags.includes(typeof tag === 'string' ? tag : tag.text))); + return matchesSearch && matchesTags; + }); function setGridView() { console.log('Setting view mode to: grid'); @@ -104,6 +117,46 @@ console.log('[theme] setTheme:', newTheme); applyTheme(); } + + function toggleTag(tag) { + if (selectedTags.includes(tag)) { + selectedTags = selectedTags.filter(t => t !== tag); + } else { + selectedTags = [...selectedTags, tag]; + } + } + + function addTag(tag) { + if (!selectedTags.includes(tag)) { + selectedTags = [...selectedTags, tag]; + } + tagDropdownOpen = false; + } + + function removeTag(tag) { + selectedTags = selectedTags.filter(t => t !== tag); + } + + function toggleDropdown() { + tagDropdownOpen = !tagDropdownOpen; + } + + function closeDropdown(e) { + if (!e.target.closest('.tag-dropdown')) { + tagDropdownOpen = false; + } + } + + function getTagObj(text) { + return allTags.find(t => t.text === text); + } + + // Listen for outside click to close dropdown + $: if (tagDropdownOpen) { + window.addEventListener('click', closeDropdown); + } else { + window.removeEventListener('click', closeDropdown); + }
@@ -126,6 +179,41 @@ +
+ {#each selectedTags as tagText} + {#if getTagObj(tagText)} + + {/if} + {/each} +
+ + {#if tagDropdownOpen} + + {/if} +
+
@@ -133,4 +140,23 @@ .logo-details p { margin-bottom: 0.5rem; } + + .logo-tags { + margin-top: 1rem; + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + } + + .logo-tag { + display: inline-block; + background: var(--color-accent, #4f8cff); + color: #fff; + border-radius: 12px; + padding: 0.2em 0.8em; + font-size: 0.85em; + font-weight: 500; + letter-spacing: 0.02em; + transition: background 0.2s; + }