2025-07-27 12:56:37 +02:00

432 lines
16 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 { getToolsData } from '../utils/dataService.js';
const data = await getToolsData();
const tools = data.tools;
---
<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="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 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 zu SSO & Zugang
</a>
<button id="ai-query-btn" class="btn btn-accent">
<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
</button>
<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>
<a href="#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 durchsuchen
</a>
</div>
</div>
</div>
</section>
<section id="filters-section" style="padding: 2rem 0;">
<div style="text-align: center; margin-bottom: 2rem;">
<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 }}>
window.toolsData = toolsData;
// Approach selection functionality
window.selectApproach = function(approach) {
console.log(`Selected approach: ${approach}`);
// Hide any existing results
const aiResults = document.getElementById('ai-results');
if (aiResults) aiResults.style.display = 'none';
// Visual feedback for selection
document.querySelectorAll('.approach-card').forEach(card => {
card.classList.remove('selected');
});
document.querySelector(`.approach-card.${approach}`).classList.add('selected');
if (approach === 'methodology') {
// Show NIST methodology section (implemented in Phase 2)
const methodologySection = document.getElementById('methodology-section');
if (methodologySection) {
methodologySection.classList.add('active');
methodologySection.scrollIntoView({ behavior: 'smooth', block: 'start' });
} else {
// For now, show a placeholder message
alert('NIST-Methodologie wird in Phase 2 implementiert. Verwenden Sie vorerst die Standard-Werkzeugauswahl unten.');
document.getElementById('filters-section').scrollIntoView({ behavior: 'smooth' });
}
} else if (approach === 'targeted') {
// Show targeted scenarios section (implemented in Phase 3)
const targetedSection = document.getElementById('targeted-section');
if (targetedSection) {
targetedSection.classList.add('active');
targetedSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
} else {
// For now, show a placeholder message
alert('Gezielte Szenarien werden in Phase 3 implementiert. Verwenden Sie vorerst die Standard-Werkzeugauswahl unten.');
document.getElementById('filters-section').scrollIntoView({ behavior: 'smooth' });
}
}
};
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', async () => {
if (typeof window.requireClientAuth === 'function') {
await window.requireClientAuth(() => switchToView('ai'), `${window.location.pathname}?view=ai`, 'ai');
} else {
console.warn('[AUTH] requireClientAuth not available');
switchToView('ai');
}
});
}
function switchToView(view) {
toolsGrid.style.display = 'none';
matrixContainer.style.display = 'none';
aiInterface.style.display = 'none';
filtersSection.style.display = 'none';
const viewToggles = document.querySelectorAll('.view-toggle');
viewToggles.forEach(btn => {
btn.classList.toggle('active', btn.getAttribute('data-view') === view);
});
switch (view) {
case 'ai':
aiInterface.style.display = 'block';
filtersSection.style.display = 'block';
hideFilterControls();
if (window.restoreAIResults) {
window.restoreAIResults();
}
const aiInput = document.getElementById('ai-query-input');
if (aiInput) {
setTimeout(() => aiInput.focus(), 100);
}
break;
case 'matrix':
matrixContainer.style.display = 'block';
filtersSection.style.display = 'block';
showFilterControls();
break;
default:
toolsGrid.style.display = 'block';
filtersSection.style.display = 'block';
showFilterControls();
break;
}
if (window.location.search) {
window.history.replaceState({}, '', window.location.pathname);
}
}
function hideFilterControls() {
const elements = [
'.domain-phase-container',
'#search-input',
'.tag-cloud',
'.tag-header',
'.checkbox-wrapper'
];
elements.forEach(selector => {
const element = document.querySelector(selector);
if (element) element.style.display = 'none';
});
const allInputs = filtersSection.querySelectorAll('input, select, textarea');
allInputs.forEach(input => input.style.display = 'none');
}
function showFilterControls() {
const domainPhaseContainer = document.querySelector('.domain-phase-container');
const searchInput = document.getElementById('search-input');
const tagCloud = document.querySelector('.tag-cloud');
const tagHeader = document.querySelector('.tag-header');
const checkboxWrappers = document.querySelectorAll('.checkbox-wrapper');
const allInputs = filtersSection.querySelectorAll('input, select, textarea');
if (domainPhaseContainer) domainPhaseContainer.style.display = 'grid';
if (searchInput) searchInput.style.display = 'block';
if (tagCloud) tagCloud.style.display = 'flex';
if (tagHeader) tagHeader.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...');
targetCard.scrollIntoView({ behavior: 'smooth', 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);
}
}, 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`);
firstMatch.scrollIntoView({ behavior: 'smooth', block: 'center' });
} else {
console.warn('Tool chip not found in matrix:', toolName);
}
}, 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>