adjust style

This commit is contained in:
overcuriousity
2025-07-14 21:31:20 +02:00
parent 92dcd2ab74
commit 0667180da5
3 changed files with 457 additions and 110 deletions

View File

@@ -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>

View File

@@ -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');