From 0e66c6e32f8f8521cf84cb566ee0e004f1b76818 Mon Sep 17 00:00:00 2001 From: overcuriousity Date: Sat, 2 Aug 2025 10:45:49 +0200 Subject: [PATCH] interface improvement (compact filter section) --- src/components/ToolFilters.astro | 267 ++++++++++++++++++++----------- src/styles/global.css | 130 +++++++++++++-- 2 files changed, 295 insertions(+), 102 deletions(-) diff --git a/src/components/ToolFilters.astro b/src/components/ToolFilters.astro index df2a00a..4da34db 100644 --- a/src/components/ToolFilters.astro +++ b/src/components/ToolFilters.astro @@ -91,119 +91,137 @@ const sortedTags = Object.entries(tagFrequency) - +

⚙️ Erweiterte Filter

- +
+ + +
-
-
-
- - +
- +

🏷️ Tag-Filter

-
+
-
-
-
-
- {sortedTags.map((tag, index) => ( - - ))} +
+
+ {sortedTags.map((tag, index) => ( + + ))} +
@@ -293,7 +311,12 @@ const sortedTags = Object.entries(tagFrequency) advanced: document.getElementById('reset-advanced'), tags: document.getElementById('reset-tags'), all: document.getElementById('reset-all-filters') - } + }, + // Collapsible elements + toggleAdvanced: document.getElementById('toggle-advanced'), + toggleTags: document.getElementById('toggle-tags'), + advancedContent: document.getElementById('advanced-filters-content'), + tagContent: document.getElementById('tag-filters-content') }; // Verify critical elements exist @@ -307,6 +330,52 @@ const sortedTags = Object.entries(tagFrequency) let selectedPhase = ''; let isTagCloudExpanded = false; + // Collapsible functionality + function toggleCollapsible(toggleBtn, content, storageKey) { + const isCollapsed = toggleBtn.getAttribute('data-collapsed') === 'true'; + const newState = !isCollapsed; + + toggleBtn.setAttribute('data-collapsed', newState.toString()); + + if (newState) { + // Collapse + content.classList.add('hidden'); + toggleBtn.style.transform = 'rotate(0deg)'; + } else { + // Expand + content.classList.remove('hidden'); + toggleBtn.style.transform = 'rotate(180deg)'; + } + + // Store state in sessionStorage + sessionStorage.setItem(storageKey, newState.toString()); + } + + // Initialize collapsible sections (collapsed by default) + function initializeCollapsible() { + // Advanced filters + const advancedCollapsed = sessionStorage.getItem('advanced-collapsed') !== 'false'; + elements.toggleAdvanced.setAttribute('data-collapsed', advancedCollapsed.toString()); + if (advancedCollapsed) { + elements.advancedContent.classList.add('hidden'); + elements.toggleAdvanced.style.transform = 'rotate(0deg)'; + } else { + elements.advancedContent.classList.remove('hidden'); + elements.toggleAdvanced.style.transform = 'rotate(180deg)'; + } + + // Tag filters + const tagsCollapsed = sessionStorage.getItem('tags-collapsed') !== 'false'; + elements.toggleTags.setAttribute('data-collapsed', tagsCollapsed.toString()); + if (tagsCollapsed) { + elements.tagContent.classList.add('hidden'); + elements.toggleTags.style.transform = 'rotate(0deg)'; + } else { + elements.tagContent.classList.remove('hidden'); + elements.toggleTags.style.transform = 'rotate(180deg)'; + } + } + // Helper function to check if tool is hosted function isToolHosted(tool) { return tool.projectUrl !== undefined && @@ -418,18 +487,23 @@ const sortedTags = Object.entries(tagFrequency) }); } - // Add/remove tags + // Add/remove tags - FIXED: Update ALL matching elements function addTag(tag) { selectedTags.add(tag); - document.querySelector(`[data-tag="${tag}"]`).classList.add('active'); + // FIXED: Use querySelectorAll to update ALL matching tag elements + document.querySelectorAll(`[data-tag="${tag}"]`).forEach(element => { + element.classList.add('active'); + }); updateSelectedTags(); filterTools(); } function removeTag(tag) { selectedTags.delete(tag); - const tagElement = document.querySelector(`[data-tag="${tag}"]`); - if (tagElement) tagElement.classList.remove('active'); + // FIXED: Use querySelectorAll to update ALL matching tag elements + document.querySelectorAll(`[data-tag="${tag}"]`).forEach(element => { + element.classList.remove('active'); + }); updateSelectedTags(); filterTools(); } @@ -553,7 +627,10 @@ const sortedTags = Object.entries(tagFrequency) function resetTags() { selectedTags.clear(); - elements.tagCloudItems.forEach(item => item.classList.remove('active')); + // FIXED: Update ALL tag elements + document.querySelectorAll('.tag-cloud-item').forEach(item => { + item.classList.remove('active'); + }); updateSelectedTags(); filterTools(); } @@ -630,11 +707,21 @@ const sortedTags = Object.entries(tagFrequency) elements.resetButtons.tags.addEventListener('click', resetTags); elements.resetButtons.all.addEventListener('click', resetAllFilters); + // Collapsible toggle listeners + elements.toggleAdvanced.addEventListener('click', () => { + toggleCollapsible(elements.toggleAdvanced, elements.advancedContent, 'advanced-collapsed'); + }); + + elements.toggleTags.addEventListener('click', () => { + toggleCollapsible(elements.toggleTags, elements.tagContent, 'tags-collapsed'); + }); + // Expose functions globally for backwards compatibility window.clearTagFilters = resetTags; window.clearAllFilters = resetAllFilters; // Initialize + initializeCollapsible(); initTagCloud(); filterTagCloud(); updateSelectedTags(); diff --git a/src/styles/global.css b/src/styles/global.css index 14807dd..0515ccc 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1263,6 +1263,12 @@ input[type="checkbox"] { gap: 0.5rem; } +.filter-header-controls { + display: flex; + align-items: center; + gap: 0.5rem; +} + /* Search Components */ .search-wrapper { position: relative; @@ -1315,6 +1321,64 @@ input[type="checkbox"] { color: var(--color-text); } +.collapse-toggle { + background: none; + border: 1px solid var(--color-border); + border-radius: 0.375rem; + color: var(--color-text-secondary); + cursor: pointer; + padding: 0.375rem; + transition: var(--transition-fast); + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; +} + +.collapse-toggle:hover { + background-color: var(--color-bg-secondary); + border-color: var(--color-primary); + color: var(--color-text); +} + +.collapse-toggle svg { + transition: transform var(--transition-medium); +} + +/* When expanded, rotate the chevron */ +.collapse-toggle[data-collapsed="false"] svg { + transform: rotate(180deg); +} + +/* Collapsible Content */ +.collapsible-content { + overflow: hidden; + transition: all var(--transition-medium); + opacity: 1; + max-height: 1000px; +} + +.collapsible-content.hidden { + opacity: 0; + max-height: 0; + padding-top: 0; + padding-bottom: 0; + margin-top: 0; + margin-bottom: 0; +} + +/* Smooth animation for expanding content */ +.collapsible-content:not(.hidden) { + animation: expandContent 0.3s ease-out; +} + +/* Content spacing when expanded */ +.collapsible-content:not(.hidden) .advanced-filters-compact, +.collapsible-content:not(.hidden) .tag-section { + padding-top: 0.75rem; +} + /* Filter Grids & Groups */ .filter-grid-compact { display: grid; @@ -1429,11 +1493,9 @@ input[type="checkbox"] { user-select: none; } -/* Tag System */ -.tag-section { - display: flex; - flex-direction: column; - gap: 1rem; +.tag-section .tag-controls { + order: -1; + margin-bottom: 0.75rem; } .selected-tags { @@ -1574,6 +1636,14 @@ input[type="checkbox"] { transition: var(--transition-fast); } +.filter-reset { + width: 32px; + height: 32px; + display: inline-flex; + align-items: center; + justify-content: center; +} + .filter-reset:hover { background-color: var(--color-bg-secondary); border-color: var(--color-warning); @@ -1591,13 +1661,6 @@ input[type="checkbox"] { opacity: 0.9; } -/* Tag Controls */ -.tag-controls { - display: flex; - align-items: center; - gap: 0.75rem; -} - .tag-toggle { padding: 0.375rem 0.75rem; border: 1px solid var(--color-border); @@ -2391,6 +2454,17 @@ footer { to { opacity: 1; } } +@keyframes expandContent { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + @keyframes fadeInUp { from { opacity: 0; @@ -3385,6 +3459,23 @@ footer { .view-toggle { justify-content: center; } + + .filter-header-controls { + gap: 0.375rem; + } + + .collapse-toggle, + .filter-reset { + width: 28px; + height: 28px; + padding: 0.25rem; + } + + .collapse-toggle svg, + .filter-reset svg { + width: 14px; + height: 14px; + } } @media (width <= 640px) { @@ -3519,6 +3610,21 @@ footer { .filter-card-compact { padding: 0.5rem; } + + .filter-header-compact { + flex-wrap: wrap; + gap: 0.5rem; + } + + .filter-header-compact h3 { + flex: 1 1 100%; + margin-bottom: 0.25rem; + } + + .filter-header-controls { + flex: 1 1 100%; + justify-content: flex-end; + } }