interface improvement (compact filter section)
This commit is contained in:
@@ -91,119 +91,137 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Advanced Filters Section -->
|
||||
<!-- Advanced Filters Section - COLLAPSIBLE -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-card-compact">
|
||||
<div class="filter-header-compact">
|
||||
<h3>⚙️ Erweiterte Filter</h3>
|
||||
<button class="filter-reset" id="reset-advanced" title="Erweiterte Filter zurücksetzen">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="1 4 1 10 7 10"/>
|
||||
<path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="filter-header-controls">
|
||||
<button class="filter-reset" id="reset-advanced" title="Erweiterte Filter zurücksetzen">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="1 4 1 10 7 10"/>
|
||||
<path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="collapse-toggle" id="toggle-advanced" data-collapsed="true" title="Erweiterte Filter ein/ausblenden">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="advanced-filters-compact">
|
||||
<div class="filter-grid-compact">
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Tool-Typ</label>
|
||||
<select id="type-select" class="filter-select">
|
||||
<option value="">Alle Typen</option>
|
||||
{toolTypes.map((type: string) => (
|
||||
<option value={type}>{type}</option>
|
||||
))}
|
||||
</select>
|
||||
<div class="collapsible-content hidden" id="advanced-filters-content">
|
||||
<div class="advanced-filters-compact">
|
||||
<div class="filter-grid-compact">
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Tool-Typ</label>
|
||||
<select id="type-select" class="filter-select">
|
||||
<option value="">Alle Typen</option>
|
||||
{toolTypes.map((type: string) => (
|
||||
<option value={type}>{type}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Skill Level</label>
|
||||
<select id="skill-select" class="filter-select">
|
||||
<option value="">Alle Level</option>
|
||||
{skillLevels.map((level: string) => (
|
||||
<option value={level}>{level}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Plattform</label>
|
||||
<select id="platform-select" class="filter-select">
|
||||
<option value="">Alle Plattformen</option>
|
||||
{platforms.map((platform: string) => (
|
||||
<option value={platform}>{platform}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Lizenztyp</label>
|
||||
<select id="license-select" class="filter-select">
|
||||
<option value="">Alle Lizenzen</option>
|
||||
{licenses.map((license: string) => (
|
||||
<option value={license}>{license}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Zugangsart</label>
|
||||
<select id="access-select" class="filter-select">
|
||||
<option value="">Alle Zugangsarten</option>
|
||||
{accessTypes.map((access: string) => (
|
||||
<option value={access}>{access}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Skill Level</label>
|
||||
<select id="skill-select" class="filter-select">
|
||||
<option value="">Alle Level</option>
|
||||
{skillLevels.map((level: string) => (
|
||||
<option value={level}>{level}</option>
|
||||
))}
|
||||
</select>
|
||||
<div class="filter-toggles-compact">
|
||||
<label class="toggle-wrapper">
|
||||
<input type="checkbox" id="hosted-only" />
|
||||
<span class="toggle-label">🟣 Nur CC24-Server Tools</span>
|
||||
</label>
|
||||
|
||||
<label class="toggle-wrapper">
|
||||
<input type="checkbox" id="knowledgebase-only" />
|
||||
<span class="toggle-label">📖 Nur Tools mit Knowledgebase</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Plattform</label>
|
||||
<select id="platform-select" class="filter-select">
|
||||
<option value="">Alle Plattformen</option>
|
||||
{platforms.map((platform: string) => (
|
||||
<option value={platform}>{platform}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Lizenztyp</label>
|
||||
<select id="license-select" class="filter-select">
|
||||
<option value="">Alle Lizenzen</option>
|
||||
{licenses.map((license: string) => (
|
||||
<option value={license}>{license}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label class="filter-label">Zugangsart</label>
|
||||
<select id="access-select" class="filter-select">
|
||||
<option value="">Alle Zugangsarten</option>
|
||||
{accessTypes.map((access: string) => (
|
||||
<option value={access}>{access}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-toggles-compact">
|
||||
<label class="toggle-wrapper">
|
||||
<input type="checkbox" id="hosted-only" />
|
||||
<span class="toggle-label">🟣 Nur CC24-Server Tools</span>
|
||||
</label>
|
||||
|
||||
<label class="toggle-wrapper">
|
||||
<input type="checkbox" id="knowledgebase-only" />
|
||||
<span class="toggle-label">📖 Nur Tools mit Knowledgebase</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tag Filters Section -->
|
||||
<!-- Tag Filters Section - COLLAPSIBLE -->
|
||||
<div class="filter-section">
|
||||
<div class="filter-card-compact">
|
||||
<div class="filter-header-compact">
|
||||
<h3>🏷️ Tag-Filter</h3>
|
||||
<div class="tag-controls">
|
||||
<div class="filter-header-controls">
|
||||
<button class="filter-reset" id="reset-tags" title="Tags zurücksetzen">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="1 4 1 10 7 10"/>
|
||||
<path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button id="tag-cloud-toggle" class="tag-toggle" data-expanded="false">
|
||||
Mehr zeigen
|
||||
<button class="collapse-toggle" id="toggle-tags" data-collapsed="true" title="Tag-Filter ein/ausblenden">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tag-section">
|
||||
<div class="selected-tags" id="selected-tags"></div>
|
||||
<div class="tag-cloud" id="tag-cloud">
|
||||
{sortedTags.map((tag, index) => (
|
||||
<button
|
||||
class="tag-cloud-item"
|
||||
data-tag={tag}
|
||||
data-frequency={tagFrequency[tag]}
|
||||
data-index={index}
|
||||
>
|
||||
{tag}
|
||||
<span class="tag-frequency">({tagFrequency[tag]})</span>
|
||||
<div class="collapsible-content hidden" id="tag-filters-content">
|
||||
<div class="tag-section">
|
||||
<div class="selected-tags" id="selected-tags"></div>
|
||||
<div class="tag-controls">
|
||||
<button id="tag-cloud-toggle" class="tag-toggle" data-expanded="false">
|
||||
Mehr zeigen
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div class="tag-cloud" id="tag-cloud">
|
||||
{sortedTags.map((tag, index) => (
|
||||
<button
|
||||
class="tag-cloud-item"
|
||||
data-tag={tag}
|
||||
data-frequency={tagFrequency[tag]}
|
||||
data-index={index}
|
||||
>
|
||||
{tag}
|
||||
<span class="tag-frequency">({tagFrequency[tag]})</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user