adjust style
This commit is contained in:
@@ -36,13 +36,14 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Domain and Phase Dropdowns -->
|
||||
<div class="grid grid-cols-2 gap-4" style="margin-bottom: 1.5rem;">
|
||||
<div>
|
||||
<!-- Domain Dropdown and Phase Buttons -->
|
||||
<div class="domain-phase-container" style="margin-bottom: 1.5rem;">
|
||||
<!-- Domain Selection -->
|
||||
<div class="domain-section">
|
||||
<label for="domain-select" style="display: block; margin-bottom: 0.5rem; font-weight: 500;">
|
||||
Forensic Domain
|
||||
</label>
|
||||
<select id="domain-select">
|
||||
<select id="domain-select" style="max-width: 300px;">
|
||||
<option value="">All Domains</option>
|
||||
{domains.map((domain: any) => (
|
||||
<option value={domain.id}>{domain.name}</option>
|
||||
@@ -50,16 +51,22 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="phase-select" style="display: block; margin-bottom: 0.5rem; font-weight: 500;">
|
||||
<!-- Phase Selection Buttons -->
|
||||
<div class="phase-section">
|
||||
<label style="display: block; margin-bottom: 0.75rem; font-weight: 500;">
|
||||
Investigation Phase
|
||||
</label>
|
||||
<select id="phase-select">
|
||||
<option value="">All Phases</option>
|
||||
<div class="phase-buttons">
|
||||
{phases.map((phase: any) => (
|
||||
<option value={phase.id}>{phase.name}</option>
|
||||
<button
|
||||
class="phase-button"
|
||||
data-phase={phase.id}
|
||||
type="button"
|
||||
>
|
||||
{phase.name}
|
||||
</button>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -72,15 +79,25 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
|
||||
<!-- Tag Cloud -->
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label style="display: block; margin-bottom: 0.75rem; font-weight: 500;">
|
||||
Filter by Tags
|
||||
</label>
|
||||
<div class="tag-cloud">
|
||||
{sortedTags.map(tag => (
|
||||
<div class="tag-header">
|
||||
<label style="font-weight: 500;">
|
||||
Filter by Tags
|
||||
</label>
|
||||
<button
|
||||
id="tag-cloud-toggle"
|
||||
class="btn-tag-toggle"
|
||||
data-expanded="false"
|
||||
>
|
||||
Show More
|
||||
</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>
|
||||
@@ -98,56 +115,8 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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 }}>
|
||||
<script define:vars={{ toolsData: data.tools, tagFrequency, sortedTags }}>
|
||||
// Store tools data globally for filtering
|
||||
window.toolsData = toolsData;
|
||||
|
||||
@@ -155,19 +124,99 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const domainSelect = document.getElementById('domain-select');
|
||||
const phaseSelect = document.getElementById('phase-select');
|
||||
const phaseButtons = document.querySelectorAll('.phase-button');
|
||||
const proprietaryCheckbox = document.getElementById('include-proprietary');
|
||||
const tagCloudItems = document.querySelectorAll('.tag-cloud-item');
|
||||
const tagCloud = document.getElementById('tag-cloud');
|
||||
const tagCloudToggle = document.getElementById('tag-cloud-toggle');
|
||||
const viewToggles = document.querySelectorAll('.view-toggle');
|
||||
|
||||
// Track selected tags
|
||||
// Track selected tags and phase
|
||||
let selectedTags = new Set();
|
||||
let selectedPhase = '';
|
||||
let isTagCloudExpanded = false;
|
||||
|
||||
// Initialize tag cloud state
|
||||
function initTagCloud() {
|
||||
const visibleCount = 12; // Show first 12 tags initially
|
||||
tagCloudItems.forEach((item, index) => {
|
||||
if (index >= visibleCount) {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Toggle tag cloud expansion
|
||||
function toggleTagCloud() {
|
||||
isTagCloudExpanded = !isTagCloudExpanded;
|
||||
const visibleCount = 12;
|
||||
|
||||
if (isTagCloudExpanded) {
|
||||
tagCloud.classList.add('expanded');
|
||||
tagCloudToggle.textContent = 'Show Less';
|
||||
tagCloudToggle.setAttribute('data-expanded', 'true');
|
||||
|
||||
// Show all filtered tags
|
||||
tagCloudItems.forEach(item => {
|
||||
if (!item.classList.contains('hidden')) {
|
||||
item.style.display = 'inline-flex';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
tagCloud.classList.remove('expanded');
|
||||
tagCloudToggle.textContent = 'Show More';
|
||||
tagCloudToggle.setAttribute('data-expanded', 'false');
|
||||
|
||||
// Show only first visible tags
|
||||
let visibleIndex = 0;
|
||||
tagCloudItems.forEach(item => {
|
||||
if (!item.classList.contains('hidden')) {
|
||||
if (visibleIndex < visibleCount) {
|
||||
item.style.display = 'inline-flex';
|
||||
visibleIndex++;
|
||||
} else {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Filter tag cloud based on search input
|
||||
function filterTagCloud() {
|
||||
const searchTerm = searchInput.value.toLowerCase();
|
||||
let visibleCount = 0;
|
||||
const maxVisibleWhenCollapsed = 12;
|
||||
|
||||
tagCloudItems.forEach(item => {
|
||||
const tagName = item.getAttribute('data-tag').toLowerCase();
|
||||
const shouldShow = tagName.includes(searchTerm);
|
||||
|
||||
if (shouldShow) {
|
||||
item.classList.remove('hidden');
|
||||
if (isTagCloudExpanded || visibleCount < maxVisibleWhenCollapsed) {
|
||||
item.style.display = 'inline-flex';
|
||||
visibleCount++;
|
||||
} else {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
item.classList.add('hidden');
|
||||
item.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Update toggle button visibility
|
||||
const hasHiddenTags = Array.from(tagCloudItems).some(item =>
|
||||
!item.classList.contains('hidden') && item.style.display === 'none'
|
||||
);
|
||||
tagCloudToggle.style.display = hasHiddenTags ? 'block' : 'none';
|
||||
}
|
||||
|
||||
// Filter function
|
||||
function filterTools() {
|
||||
const searchTerm = searchInput.value.toLowerCase();
|
||||
const selectedDomain = domainSelect.value;
|
||||
const selectedPhase = phaseSelect.value;
|
||||
const includeProprietary = proprietaryCheckbox.checked;
|
||||
|
||||
const filtered = window.toolsData.filter(tool => {
|
||||
@@ -230,6 +279,24 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
filterTools();
|
||||
}
|
||||
|
||||
// Handle phase button clicks
|
||||
function handlePhaseClick(button) {
|
||||
const phase = button.getAttribute('data-phase');
|
||||
|
||||
if (selectedPhase === phase) {
|
||||
// Deselect if already selected
|
||||
selectedPhase = '';
|
||||
button.classList.remove('active');
|
||||
} else {
|
||||
// Select new phase
|
||||
phaseButtons.forEach(btn => btn.classList.remove('active'));
|
||||
selectedPhase = phase;
|
||||
button.classList.add('active');
|
||||
}
|
||||
|
||||
filterTools();
|
||||
}
|
||||
|
||||
// View toggle handler
|
||||
function handleViewToggle(view) {
|
||||
viewToggles.forEach(btn => {
|
||||
@@ -255,24 +322,45 @@ const sortedTags = Object.entries(tagFrequency)
|
||||
filterTools();
|
||||
}
|
||||
|
||||
// Attach event listeners
|
||||
searchInput.addEventListener('input', filterTools);
|
||||
// Clear all filters function
|
||||
function clearAllFilters() {
|
||||
searchInput.value = '';
|
||||
domainSelect.value = '';
|
||||
selectedPhase = '';
|
||||
phaseButtons.forEach(btn => btn.classList.remove('active'));
|
||||
clearTagFilters();
|
||||
filterTagCloud();
|
||||
}
|
||||
|
||||
// Event listeners
|
||||
searchInput.addEventListener('input', () => {
|
||||
filterTagCloud();
|
||||
filterTools();
|
||||
});
|
||||
|
||||
domainSelect.addEventListener('change', filterTools);
|
||||
phaseSelect.addEventListener('change', filterTools);
|
||||
proprietaryCheckbox.addEventListener('change', filterTools);
|
||||
tagCloudToggle.addEventListener('click', toggleTagCloud);
|
||||
|
||||
tagCloudItems.forEach(item => {
|
||||
item.addEventListener('click', () => handleTagClick(item));
|
||||
});
|
||||
|
||||
phaseButtons.forEach(btn => {
|
||||
btn.addEventListener('click', () => handlePhaseClick(btn));
|
||||
});
|
||||
|
||||
viewToggles.forEach(btn => {
|
||||
btn.addEventListener('click', () => handleViewToggle(btn.getAttribute('data-view')));
|
||||
});
|
||||
|
||||
// Expose clear function globally for potential use
|
||||
// Expose functions globally for potential use
|
||||
window.clearTagFilters = clearTagFilters;
|
||||
window.clearAllFilters = clearAllFilters;
|
||||
|
||||
// Initial filter - this ensures the initial state matches the checkbox state
|
||||
// Initialize
|
||||
initTagCloud();
|
||||
filterTagCloud();
|
||||
filterTools();
|
||||
});
|
||||
</script>
|
||||
@@ -135,6 +135,12 @@ domains.forEach((domain: any) => {
|
||||
</div>
|
||||
|
||||
<script define:vars={{ toolsData: tools, collaborationTools, domainTools }}>
|
||||
// Helper function to get selected phase from active button
|
||||
function getSelectedPhase() {
|
||||
const activePhaseButton = document.querySelector('.phase-button.active');
|
||||
return activePhaseButton ? activePhaseButton.getAttribute('data-phase') : '';
|
||||
}
|
||||
|
||||
// Tool details functions
|
||||
window.showToolDetails = function(toolName) {
|
||||
const tool = toolsData.find(t => t.name === toolName);
|
||||
@@ -220,7 +226,8 @@ domains.forEach((domain: any) => {
|
||||
const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');
|
||||
|
||||
if (currentView === 'matrix') {
|
||||
const selectedPhase = document.getElementById('phase-select')?.value;
|
||||
// Get selected phase from active button instead of dropdown
|
||||
const selectedPhase = getSelectedPhase();
|
||||
|
||||
// Handle collaboration tools section
|
||||
const collaborationSection = document.getElementById('collaboration-tools-section');
|
||||
|
||||
Reference in New Issue
Block a user