overcuriousity b515a45e1e cleanup
2025-08-05 22:09:46 +02:00

500 lines
18 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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 AIQueryInterface from '../components/AIQueryInterface.astro';
import TargetedScenarios from '../components/TargetedScenarios.astro';
import { getToolsData } from '../utils/dataService.js';
const data = await getToolsData();
const tools = data.tools;
const phases = data.phases;
---
<BaseLayout title="~/">
<section class="approach-hero">
<div class="approach-content">
<h1>ForensicPathways</h1>
<p class="hero-tagline">Das richtige Werkzeug zur richtigen Zeit</p>
<p class="hero-subtitle">
Systematische digitale Forensik nach bewährter NIST SP 800-86 Methodik.<br>
Wählen Sie Ihren Ansatz für die Werkzeugauswahl:
</p>
<div class="ai-hero-spotlight">
<div class="ai-spotlight-content">
<div class="ai-spotlight-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M9 11H5a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7a2 2 0 0 0-2-2h-4"/>
<path d="M9 11V7a3 3 0 0 1 6 0v4"/>
<circle cx="12" cy="12" r="2"/>
</svg>
</div>
<div class="ai-spotlight-text">
<h3>Forensic AI-Beratung</h3>
<p>Analyse des Untersuchungsszenarios mit Empfehlungen zum Vorgehen</p>
</div>
</div>
<button id="ai-query-btn" class="btn btn-accent btn-lg ai-primary-btn">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M9 11H5a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7a2 2 0 0 0-2-2h-4"/>
<path d="M9 11V7a3 3 0 0 1 6 0v4"/>
</svg>
KI-Beratung starten
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="ml-2">
<line x1="7" y1="17" x2="17" y2="7"/>
<polyline points="7,7 17,7 17,17"/>
</svg>
</button>
<div class="ai-features-mini">
<span class="badge badge-secondary">Workflow-Empfehlungen</span>
<span class="badge badge-secondary">Transparenz</span>
<span class="badge badge-secondary">Sofortige Analyse</span>
</div>
</div>
<div class="approach-selector">
<div class="approach-card methodology" onclick="selectApproach('methodology')">
<div class="approach-header">
<div class="approach-icon">🔍</div>
<h3>Vollständige Ermittlung</h3>
</div>
<p class="approach-description">
Systematisches Vorgehen durch alle vier NIST-Phasen einer forensischen Untersuchung
</p>
<ul class="approach-features">
<li>Methodische Schritt-für-Schritt Anleitung</li>
<li>Vollständige Dokumentationskette</li>
<li>Rechtssichere Beweisführung</li>
<li>Ideal für komplexe Fälle</li>
</ul>
</div>
<div class="approach-card targeted" onclick="selectApproach('targeted')">
<div class="approach-header">
<div class="approach-icon">🎯</div>
<h3>Gezieltes Problem lösen</h3>
</div>
<p class="approach-description">
Direkter Zugang zu spezifischen Tools und Methoden für bekannte Anforderungen
</p>
<ul class="approach-features">
<li>Schnelle Tool-Suche</li>
<li>Spezifische Problemlösungen</li>
<li>Erfahrene Anwender</li>
<li>Effizient für Einzelaufgaben</li>
</ul>
</div>
</div>
<div class="approach-actions">
<p class="approach-info">
<span class="info-icon"></span>
Die lila gekennzeichneten Einträge sind über das Single-Sign-On der CC24-Cloud direkt zugänglich.
Teilnehmer der Seminargruppe CC24-w1 (oder andere Berechtigte) können die gehostete Infrastruktur nutzen.
<a href="/about#support">Kontakt bei Problemen</a>
</p>
<div class="quick-actions">
<a href="/about" class="btn btn-secondary">
<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 16v-4"></path>
<path d="M12 8h.01"></path>
</svg>
Infos, SSO & Zugang
</a>
<a href="/contribute" class="btn" style="background-color: var(--color-warning); color: white; border-color: var(--color-warning);" data-contribute-button="new">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
<circle cx="8.5" cy="7" r="4"/>
<line x1="20" y1="8" x2="20" y2="14"/>
<line x1="23" y1="11" x2="17" y2="11"/>
</svg>
Beitragen
</a>
<button onclick="window.scrollToElementById('filters-section')" class="btn btn-secondary">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path>
<polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline>
<line x1="12" y1="22.08" x2="12" y2="12"></line>
</svg>
Direkt zur Suche
</a>
</div>
</div>
</div>
</section>
<!-- NIST Methodology Section -->
<section id="methodology-section" class="methodology-section">
<div class="methodology-header">
<h3>NIST SP 800-86 Forensische Methodik</h3>
<p class="methodology-subtitle">
Wählen Sie eine Phase aus dem bewährten Vier-Phasen-Modell
</p>
</div>
<div class="nist-workflow">
{phases.map((phase: any, index: number) => {
const phaseTools = tools.filter((tool: any) =>
tool.phases && tool.phases.includes(phase.id)
);
return (
<div class={`phase-card phase-${phase.id}`} onclick={`selectPhase('${phase.id}')`}>
<div class="phase-number">{index + 1}</div>
<div class="phase-title">{phase.name}</div>
<p class="phase-description">
{phase.description}
</p>
<span class="tool-count">{phaseTools.length} Tools</span>
</div>
);
})}
</div>
<div class="methodology-tip">
<p>
<strong>Tipp:</strong> Für komplexe Ermittlungen empfiehlt sich das sequenzielle Durchlaufen aller Phasen.
Jede Phase baut methodisch auf der vorherigen auf.
</p>
</div>
</section>
<TargetedScenarios />
<section id="filters-section" class="section">
<div class="content-center-lg">
<h3 style="color: var(--color-text); margin-bottom: 0.5rem;">Alle verfügbaren Werkzeuge durchsuchen</h3>
<p style="color: var(--color-text-secondary); margin: 0;">
Nutzen Sie die erweiterten Filter und Kategorien für eine detaillierte Suche
</p>
</div>
<ToolFilters data={data} />
</section>
<AIQueryInterface />
<section id="tools-grid" style="padding-bottom: 2rem;">
<div class="grid-auto-fit" id="tools-container">
{tools.map((tool: any) => (
<ToolCard tool={tool} />
))}
</div>
<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>
<ToolMatrix data={data} />
</BaseLayout>
<script define:vars={{ toolsData: data.tools, phases: data.phases }}>
window.toolsData = toolsData;
window.selectApproach = function(approach) {
console.log(`Selected approach: ${approach}`);
const aiResults = document.getElementById('ai-results');
if (aiResults) aiResults.style.display = 'none';
document.querySelectorAll('.approach-card').forEach(card => {
card.classList.remove('selected');
});
const selectedCard = document.querySelector(`.approach-card.${approach}`);
if (selectedCard) selectedCard.classList.add('selected');
if (approach === 'methodology') {
const methodologySection = document.getElementById('methodology-section');
if (methodologySection) {
methodologySection.classList.add('active');
window.scrollToElementById('methodology-section');
}
} else if (approach === 'targeted') {
const targetedSection = document.getElementById('targeted-section');
if (targetedSection) {
targetedSection.classList.add('active');
window.scrollToElementById('targeted-section');
}
}
};
window.selectPhase = function(phase) {
console.log(`Selected NIST phase: ${phase}`);
document.querySelectorAll('.phase-card').forEach(card => {
card.classList.remove('active');
});
const selectedCard = document.querySelector(`.phase-card.phase-${phase}`);
if (selectedCard) {
selectedCard.classList.add('active');
}
const existingPhaseButton = document.querySelector(`[data-phase="${phase}"]`);
if (existingPhaseButton && !existingPhaseButton.classList.contains('active')) {
existingPhaseButton.click();
}
const gridToggle = document.querySelector('.view-toggle[data-view="grid"]');
if (gridToggle && !gridToggle.classList.contains('active')) {
gridToggle.click();
}
window.scrollToElementById('tools-grid');
};
document.addEventListener('DOMContentLoaded', () => {
const toolsContainer = document.getElementById('tools-container');
const toolsGrid = document.getElementById('tools-grid');
const matrixContainer = document.getElementById('matrix-container');
const aiInterface = document.getElementById('ai-interface');
const filtersSection = document.getElementById('filters-section');
const noResults = document.getElementById('no-results');
const aiQueryBtn = document.getElementById('ai-query-btn');
if (!toolsContainer || !toolsGrid || !matrixContainer || !noResults || !aiInterface || !filtersSection) {
console.error('Required DOM elements not found');
return;
}
if (aiQueryBtn) {
aiQueryBtn.addEventListener('click', () => {
aiQueryBtn.classList.add('activated');
setTimeout(() => aiQueryBtn.classList.remove('activated'), 400);
switchToView('ai');
window.dispatchEvent(new CustomEvent('viewChanged', { detail: 'ai' }));
if (window.scrollToElementById) {
window.scrollToElementById('ai-interface');
} else {
aiInterface.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
}
function switchToView(view) {
const toolsGrid = document.getElementById('tools-grid');
const matrixContainer = document.getElementById('matrix-container');
const aiInterface = document.getElementById('ai-interface');
const filtersSection = document.getElementById('filters-section');
const noResults = document.getElementById('no-results');
if (toolsGrid) toolsGrid.style.display = 'none';
if (matrixContainer) matrixContainer.style.display = 'none';
if (aiInterface) aiInterface.style.display = 'none';
if (filtersSection) filtersSection.style.display = 'none';
if (noResults) noResults.style.display = 'none';
switch (view) {
case 'grid':
if (toolsGrid) toolsGrid.style.display = 'block';
if (filtersSection) filtersSection.style.display = 'block';
break;
case 'matrix':
if (matrixContainer) matrixContainer.style.display = 'block';
if (filtersSection) filtersSection.style.display = 'block';
break;
case 'ai':
if (aiInterface) aiInterface.style.display = 'block';
break;
}
}
function hideFilterControls() {
const filterSections = document.querySelectorAll('.filter-section');
filterSections.forEach((section, index) => {
if (index < filterSections.length - 1) {
section.style.display = 'none';
}
});
}
function showFilterControls() {
const filterSections = document.querySelectorAll('.filter-section');
const searchInput = document.getElementById('search-input');
const tagCloud = document.querySelector('.tag-cloud');
const tagControls = document.querySelector('.tag-controls');
const checkboxWrappers = document.querySelectorAll('.checkbox-wrapper');
const allInputs = filtersSection.querySelectorAll('input, select, textarea');
filterSections.forEach(section => section.style.display = 'block');
if (searchInput) searchInput.style.display = 'block';
if (tagCloud) tagCloud.style.display = 'flex';
if (tagControls) tagControls.style.display = 'flex';
allInputs.forEach(input => input.style.display = 'block');
checkboxWrappers.forEach(wrapper => wrapper.style.display = 'flex');
}
window.navigateToGrid = function(toolName) {
console.log('Navigating to grid for tool:', toolName);
switchToView('grid');
setTimeout(() => {
if (window.clearAllFilters) {
window.clearAllFilters();
}
setTimeout(() => {
const toolCards = document.querySelectorAll('.tool-card');
let targetCard = null;
toolCards.forEach(card => {
const cardTitle = card.querySelector('h3');
if (cardTitle) {
const titleText = cardTitle.textContent?.replace(/[^\w\s\-\.]/g, '').trim();
if (titleText === toolName) {
targetCard = card;
}
}
});
if (targetCard) {
console.log('Found target card, scrolling...');
window.scrollToElement(targetCard, { block: 'center' });
targetCard.style.animation = 'highlight-flash 2s ease-out';
setTimeout(() => {
if (targetCard) {
targetCard.style.animation = '';
}
}, 2000);
} else {
console.warn('Tool card not found in grid:', toolName);
window.scrollToElementById('tools-grid');
}
}, 300);
}, 200);
};
window.navigateToMatrix = function(toolName) {
console.log('Navigating to matrix for tool:', toolName);
switchToView('matrix');
setTimeout(() => {
const toolChips = document.querySelectorAll('.tool-chip');
let firstMatch = null;
let matchCount = 0;
toolChips.forEach(chip => {
const chipText = chip.textContent?.replace(/📖/g, '').replace(/[^\w\s\-\.]/g, '').trim();
if (chipText === toolName) {
chip.style.animation = 'highlight-flash 2s ease-out';
matchCount++;
if (!firstMatch) {
firstMatch = chip;
}
setTimeout(() => {
chip.style.animation = '';
}, 8000);
}
});
if (firstMatch) {
console.log(`Found ${matchCount} occurrences of tool, highlighting all and scrolling to first`);
window.scrollToElement(firstMatch);
} else {
console.warn('Tool chip not found in matrix:', toolName);
window.scrollToElementById('matrix-container');
}
}, 500);
};
function handleSharedURL() {
const urlParams = new URLSearchParams(window.location.search);
const toolParam = urlParams.get('tool');
const viewParam = urlParams.get('view');
const modalParam = urlParams.get('modal');
if (!toolParam) {
if (viewParam === 'ai') {
switchToView('ai');
}
return;
}
const tool = window.findToolByIdentifier(window.toolsData, toolParam);
if (!tool) {
console.warn('Shared tool not found:', toolParam);
return;
}
const cleanUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
window.history.replaceState({}, document.title, cleanUrl);
setTimeout(() => {
switch (viewParam) {
case 'grid':
window.navigateToGrid(tool.name);
break;
case 'matrix':
window.navigateToMatrix(tool.name);
break;
case 'modal':
if (modalParam === 'secondary') {
window.showToolDetails(tool.name, 'secondary');
} else {
window.showToolDetails(tool.name, 'primary');
}
break;
default:
window.navigateToGrid(tool.name);
}
}, 100);
}
window.addEventListener('toolsFiltered', (event) => {
const filtered = event.detail;
const currentView = document.querySelector('.view-toggle.active')?.getAttribute('data-view');
if (currentView === 'matrix' || currentView === 'ai') {
return;
}
const allToolCards = document.querySelectorAll('.tool-card');
const filteredNames = new Set(filtered.map(tool => tool.name.toLowerCase()));
let visibleCount = 0;
allToolCards.forEach(card => {
const toolName = card.getAttribute('data-tool-name');
if (filteredNames.has(toolName)) {
card.style.display = 'block';
visibleCount++;
} else {
card.style.display = 'none';
}
});
if (visibleCount === 0) {
noResults.style.display = 'block';
} else {
noResults.style.display = 'none';
}
});
window.addEventListener('viewChanged', (event) => {
const view = event.detail;
switchToView(view);
});
window.switchToAIView = () => switchToView('ai');
handleSharedURL();
});
</script>