adjust tag cloud
This commit is contained in:
		
							parent
							
								
									47eb5ad72a
								
							
						
					
					
						commit
						b8183ec961
					
				@ -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>
 | 
			
		||||
		Reference in New Issue
	
	Block a user