171 lines
6.4 KiB
Plaintext
171 lines
6.4 KiB
Plaintext
---
|
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
|
import ToolCard from '../components/ToolCard.astro';
|
|
import ToolFilters from '../components/ToolFilters.astro';
|
|
import ToolMatrix from '../components/ToolMatrix.astro';
|
|
import { promises as fs } from 'fs';
|
|
import { load } from 'js-yaml';
|
|
import path from 'path';
|
|
|
|
// Load tools data
|
|
const yamlPath = path.join(process.cwd(), 'src/data/tools.yaml');
|
|
const yamlContent = await fs.readFile(yamlPath, 'utf8');
|
|
const data = load(yamlContent) as any;
|
|
const tools = data.tools;
|
|
---
|
|
|
|
<BaseLayout title="Home">
|
|
<!-- Hero Section -->
|
|
<section style="text-align: center; padding: 3rem 0; border-bottom: 1px solid var(--color-border);">
|
|
<h1 style="margin-bottom: 1rem;">DFIR Tools Hub</h1>
|
|
<p class="text-muted" style="font-size: 1.125rem; max-width: 800px; margin: 0 auto;">
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
|
|
</p>
|
|
</section>
|
|
|
|
<!-- Filters Section -->
|
|
<section style="padding: 2rem 0;">
|
|
<ToolFilters />
|
|
</section>
|
|
|
|
<!-- Tools Grid -->
|
|
<section id="tools-grid" style="padding-bottom: 2rem;">
|
|
<div class="grid grid-cols-3 gap-4" id="tools-container">
|
|
{tools.map((tool: any) => (
|
|
<ToolCard tool={tool} />
|
|
))}
|
|
</div>
|
|
|
|
<!-- No results message -->
|
|
<div id="no-results" style="display: none; text-align: center; padding: 4rem 0;">
|
|
<p class="text-muted" style="font-size: 1.125rem;">No tools found matching your criteria.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Matrix View -->
|
|
<ToolMatrix />
|
|
</BaseLayout>
|
|
|
|
<script>
|
|
// Handle view changes and filtering
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const toolsContainer = document.getElementById('tools-container');
|
|
const toolsGrid = document.getElementById('tools-grid');
|
|
const matrixContainer = document.getElementById('matrix-container');
|
|
const noResults = document.getElementById('no-results');
|
|
|
|
// Guard against null elements
|
|
if (!toolsContainer || !toolsGrid || !matrixContainer || !noResults) {
|
|
console.error('Required DOM elements not found');
|
|
return;
|
|
}
|
|
|
|
// Initial tools HTML
|
|
const initialToolsHTML = toolsContainer.innerHTML;
|
|
|
|
// Handle filtered results
|
|
window.addEventListener('toolsFiltered', (event: Event) => {
|
|
const customEvent = event as CustomEvent;
|
|
const filtered = customEvent.detail;
|
|
const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');
|
|
|
|
if (currentView === 'matrix') {
|
|
// Matrix view handles its own rendering
|
|
return;
|
|
}
|
|
|
|
// Clear container
|
|
toolsContainer.innerHTML = '';
|
|
|
|
if (filtered.length === 0) {
|
|
noResults.style.display = 'block';
|
|
} else {
|
|
noResults.style.display = 'none';
|
|
|
|
// Render filtered tools
|
|
filtered.forEach((tool: any) => {
|
|
const toolCard = createToolCard(tool);
|
|
toolsContainer.appendChild(toolCard);
|
|
});
|
|
}
|
|
});
|
|
|
|
// Handle view changes
|
|
window.addEventListener('viewChanged', (event: Event) => {
|
|
const customEvent = event as CustomEvent;
|
|
const view = customEvent.detail;
|
|
|
|
if (view === 'matrix') {
|
|
toolsGrid.style.display = 'none';
|
|
matrixContainer.style.display = 'block';
|
|
} else {
|
|
toolsGrid.style.display = 'block';
|
|
matrixContainer.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
// Create tool card element
|
|
function createToolCard(tool: any): HTMLElement {
|
|
const cardDiv = document.createElement('div');
|
|
const cardClass = tool.isHosted ? 'card card-hosted' : (tool.license !== 'Proprietary' ? 'card card-oss' : 'card');
|
|
cardDiv.className = cardClass;
|
|
|
|
cardDiv.innerHTML = `
|
|
<div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 0.75rem;">
|
|
<h3 style="margin: 0;">${tool.name}</h3>
|
|
<div style="display: flex; gap: 0.5rem;">
|
|
${tool.isHosted ? '<span class="badge badge-primary">Self-Hosted</span>' : ''}
|
|
${tool.license !== 'Proprietary' ? '<span class="badge badge-success">Open Source</span>' : ''}
|
|
</div>
|
|
</div>
|
|
|
|
<p class="text-muted" style="font-size: 0.875rem; margin-bottom: 1rem;">
|
|
${tool.description}
|
|
</p>
|
|
|
|
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem;">
|
|
<div style="display: flex; align-items: center; gap: 0.25rem;">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
<line x1="9" y1="9" x2="15" y2="9"></line>
|
|
<line x1="9" y1="15" x2="15" y2="15"></line>
|
|
</svg>
|
|
<span class="text-muted" style="font-size: 0.75rem;">
|
|
${tool.platforms.join(', ')}
|
|
</span>
|
|
</div>
|
|
|
|
<div style="display: flex; align-items: center; gap: 0.25rem;">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"></circle>
|
|
<path d="M12 6v6l4 2"></path>
|
|
</svg>
|
|
<span class="text-muted" style="font-size: 0.75rem;">
|
|
${tool.skillLevel}
|
|
</span>
|
|
</div>
|
|
|
|
<div style="display: flex; align-items: center; gap: 0.25rem;">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
|
|
<polyline points="14 2 14 8 20 8"></polyline>
|
|
</svg>
|
|
<span class="text-muted" style="font-size: 0.75rem;">
|
|
${tool.license}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="display: flex; flex-wrap: wrap; gap: 0.25rem; margin-bottom: 1rem;">
|
|
${tool.tags.map((tag: string) => `<span class="tag">${tag}</span>`).join('')}
|
|
</div>
|
|
|
|
<a href="${tool.url}" target="_blank" rel="noopener noreferrer" class="btn btn-primary" style="width: 100%;">
|
|
${tool.isHosted ? 'Access Service' : 'Visit Website'}
|
|
</a>
|
|
`;
|
|
|
|
return cardDiv;
|
|
}
|
|
});
|
|
</script> |