Archived
2
0

adjust tag cloud

This commit is contained in:
overcuriousity 2025-07-14 15:29:11 +02:00
parent 47eb5ad72a
commit b8183ec961

View File

@ -11,8 +11,18 @@ const data = load(yamlContent) as any;
const domains = data.domains;
const phases = data.phases;
// Get unique tags from all tools
const allTags = [...new Set(data.tools.flatMap((tool: any) => tool.tags))].sort();
// Get unique tags from all tools with frequency count
const tagFrequency = data.tools.reduce((acc: Record<string, number>, tool: any) => {
tool.tags.forEach((tag: string) => {
acc[tag] = (acc[tag] || 0) + 1;
});
return acc;
}, {});
// Sort tags by frequency (descending)
const sortedTags = Object.entries(tagFrequency)
.sort(([,a], [,b]) => (b as number) - (a as number))
.map(([tag]) => tag);
---
<div class="filters-container">
@ -56,24 +66,28 @@ const allTags = [...new Set(data.tools.flatMap((tool: any) => tool.tags))].sort(
<!-- Additional Filters -->
<div style="margin-bottom: 1.5rem;">
<div class="checkbox-wrapper" style="margin-bottom: 1rem;">
<input type="checkbox" id="include-proprietary" />
<input type="checkbox" id="include-proprietary" checked />
<label for="include-proprietary">Include Proprietary Software</label>
</div>
<!-- Tag Filters -->
<details>
<summary style="cursor: pointer; font-weight: 500; margin-bottom: 0.5rem;">
<!-- Tag Cloud -->
<div style="margin-bottom: 1rem;">
<label style="display: block; margin-bottom: 0.75rem; font-weight: 500;">
Filter by Tags
</summary>
<div class="grid grid-cols-3 gap-2" style="margin-top: 0.5rem;">
{allTags.map(tag => (
<div class="checkbox-wrapper">
<input type="checkbox" id={`tag-${tag}`} data-tag={tag} class="tag-filter" />
<label for={`tag-${tag}`} style="font-size: 0.875rem;">{tag}</label>
</div>
</label>
<div class="tag-cloud">
{sortedTags.map(tag => (
<button
class="tag-cloud-item"
data-tag={tag}
data-frequency={tagFrequency[tag]}
>
{tag}
<span class="tag-frequency">({tagFrequency[tag]})</span>
</button>
))}
</div>
</details>
</div>
</div>
<!-- View Toggle -->
@ -84,7 +98,56 @@ const allTags = [...new Set(data.tools.flatMap((tool: any) => tool.tags))].sort(
</div>
</div>
<script define:vars={{ toolsData: data.tools }}>
<style>
.tag-cloud {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 0.5rem;
}
.tag-cloud-item {
display: inline-flex;
align-items: center;
gap: 0.25rem;
padding: 0.375rem 0.75rem;
border: 1px solid var(--color-border);
border-radius: 1rem;
background-color: var(--color-bg);
color: var(--color-text);
font-size: 0.875rem;
cursor: pointer;
transition: all 0.2s ease;
user-select: none;
}
.tag-cloud-item:hover {
border-color: var(--color-primary);
background-color: var(--color-bg-secondary);
}
.tag-cloud-item.active {
background-color: var(--color-accent);
border-color: var(--color-accent);
color: white;
}
.tag-cloud-item.active:hover {
background-color: var(--color-accent-hover);
border-color: var(--color-accent-hover);
}
.tag-frequency {
font-size: 0.75rem;
opacity: 0.8;
}
.tag-cloud-item.active .tag-frequency {
opacity: 1;
}
</style>
<script define:vars={{ toolsData: data.tools, tagFrequency }}>
// Store tools data globally for filtering
window.toolsData = toolsData;
@ -94,18 +157,18 @@ const allTags = [...new Set(data.tools.flatMap((tool: any) => tool.tags))].sort(
const domainSelect = document.getElementById('domain-select');
const phaseSelect = document.getElementById('phase-select');
const proprietaryCheckbox = document.getElementById('include-proprietary');
const tagFilters = document.querySelectorAll('.tag-filter');
const tagCloudItems = document.querySelectorAll('.tag-cloud-item');
const viewToggles = document.querySelectorAll('.view-toggle');
// Track selected tags
let selectedTags = new Set();
// Filter function
function filterTools() {
const searchTerm = searchInput.value.toLowerCase();
const selectedDomain = domainSelect.value;
const selectedPhase = phaseSelect.value;
const includeProprietary = proprietaryCheckbox.checked;
const selectedTags = Array.from(tagFilters)
.filter(cb => cb.checked)
.map(cb => cb.getAttribute('data-tag'));
const filtered = window.toolsData.filter(tool => {
// Search filter
@ -133,7 +196,7 @@ const allTags = [...new Set(data.tools.flatMap((tool: any) => tool.tags))].sort(
}
// Tag filter
if (selectedTags.length > 0 && !selectedTags.some(tag => tool.tags.includes(tag))) {
if (selectedTags.size > 0 && !Array.from(selectedTags).some(tag => tool.tags.includes(tag))) {
return false;
}
@ -144,6 +207,21 @@ const allTags = [...new Set(data.tools.flatMap((tool: any) => tool.tags))].sort(
window.dispatchEvent(new CustomEvent('toolsFiltered', { detail: filtered }));
}
// Handle tag cloud clicks
function handleTagClick(tagItem) {
const tag = tagItem.getAttribute('data-tag');
if (selectedTags.has(tag)) {
selectedTags.delete(tag);
tagItem.classList.remove('active');
} else {
selectedTags.add(tag);
tagItem.classList.add('active');
}
filterTools();
}
// View toggle handler
function handleViewToggle(view) {
viewToggles.forEach(btn => {
@ -161,17 +239,31 @@ const allTags = [...new Set(data.tools.flatMap((tool: any) => tool.tags))].sort(
}
}
// Clear all tag filters function
function clearTagFilters() {
selectedTags.clear();
tagCloudItems.forEach(item => item.classList.remove('active'));
filterTools();
}
// Attach event listeners
searchInput.addEventListener('input', filterTools);
domainSelect.addEventListener('change', filterTools);
phaseSelect.addEventListener('change', filterTools);
proprietaryCheckbox.addEventListener('change', filterTools);
tagFilters.forEach(cb => cb.addEventListener('change', filterTools));
tagCloudItems.forEach(item => {
item.addEventListener('click', () => handleTagClick(item));
});
viewToggles.forEach(btn => {
btn.addEventListener('click', () => handleViewToggle(btn.getAttribute('data-view')));
});
// Initial filter
// Expose clear function globally for potential use
window.clearTagFilters = clearTagFilters;
// Initial filter - this ensures the initial state matches the checkbox state
filterTools();
});
</script>