From a6b51187b7f1e8b696e369fd29676de442376107 Mon Sep 17 00:00:00 2001 From: overcuriousity Date: Mon, 21 Jul 2025 22:31:43 +0200 Subject: [PATCH] sharing mechanic with eye-watering animation --- .../{shareButton.astro => ShareButton.astro} | 0 src/components/ToolCard.astro | 1 - src/components/ToolMatrix.astro | 290 ++++++++- src/data/tools.yaml.example | 206 ++++++ src/pages/index.astro | 614 +++++++++++------- src/styles/global.css | 145 ++++- 6 files changed, 983 insertions(+), 273 deletions(-) rename src/components/{shareButton.astro => ShareButton.astro} (100%) create mode 100644 src/data/tools.yaml.example diff --git a/src/components/shareButton.astro b/src/components/ShareButton.astro similarity index 100% rename from src/components/shareButton.astro rename to src/components/ShareButton.astro diff --git a/src/components/ToolCard.astro b/src/components/ToolCard.astro index 5da266b..75507cf 100644 --- a/src/components/ToolCard.astro +++ b/src/components/ToolCard.astro @@ -21,7 +21,6 @@ export interface Props { const { tool } = Astro.props; - // Check types const isMethod = tool.type === 'method'; const isConcept = tool.type === 'concept'; diff --git a/src/components/ToolMatrix.astro b/src/components/ToolMatrix.astro index 88367f8..a2ace61 100644 --- a/src/components/ToolMatrix.astro +++ b/src/components/ToolMatrix.astro @@ -1,5 +1,7 @@ --- import { getToolsData } from '../utils/dataService.js'; +import ShareButton from './ShareButton.astro'; + // Load tools data @@ -146,12 +148,17 @@ domains.forEach((domain: any) => {

Tool Name

- +
+ + +

@@ -169,12 +176,17 @@ domains.forEach((domain: any) => {

Tool Name

- +
+ + +

@@ -266,6 +278,201 @@ domains.forEach((domain: any) => { } } + // ===== SHARING FUNCTIONALITY ===== + + // Create tool slug from name (same logic as ShareButton.astro) + function createToolSlug(toolName) { + return toolName.toLowerCase() + .replace(/[^a-z0-9\s-]/g, '') // Remove special characters + .replace(/\s+/g, '-') // Replace spaces with hyphens + .replace(/-+/g, '-') // Remove duplicate hyphens + .replace(/^-|-$/g, ''); // Remove leading/trailing hyphens + } + + // Find tool by name or slug + function findTool(identifier) { + return toolsData.find(tool => + tool.name === identifier || + createToolSlug(tool.name) === identifier.toLowerCase() + ); + } + + // Generate share URLs + function generateShareURL(toolName, view, modal = null) { + const toolSlug = createToolSlug(toolName); + const baseUrl = window.location.origin + window.location.pathname; + const params = new URLSearchParams(); + params.set('tool', toolSlug); + params.set('view', view); + if (modal) { + params.set('modal', modal); + } + return `${baseUrl}?${params.toString()}`; + } + + // Copy to clipboard with feedback + async function copyToClipboard(text, button) { + try { + await navigator.clipboard.writeText(text); + + // Show feedback + const originalHTML = button.innerHTML; + button.innerHTML = ' Kopiert!'; + button.style.color = 'var(--color-accent)'; + + setTimeout(() => { + button.innerHTML = originalHTML; + button.style.color = ''; + }, 2000); + } catch (err) { + // Fallback for older browsers + const textArea = document.createElement('textarea'); + textArea.value = text; + document.body.appendChild(textArea); + textArea.select(); + document.execCommand('copy'); + document.body.removeChild(textArea); + + // Show feedback + const originalHTML = button.innerHTML; + button.innerHTML = 'Kopiert!'; + setTimeout(() => { + button.innerHTML = originalHTML; + }, 2000); + } + } + + // Show share dialog + window.showShareDialog = function(shareButton) { + const toolName = shareButton.getAttribute('data-tool-name'); + const context = shareButton.getAttribute('data-context'); + + // Create modal backdrop + let backdrop = document.getElementById('share-modal-backdrop'); + if (!backdrop) { + backdrop = document.createElement('div'); + backdrop.id = 'share-modal-backdrop'; + backdrop.style.cssText = ` + position: fixed; top: 0; left: 0; right: 0; bottom: 0; + background: rgba(0, 0, 0, 0.5); z-index: 9999; + display: flex; align-items: center; justify-content: center; + opacity: 0; transition: opacity 0.2s ease; + `; + document.body.appendChild(backdrop); + } + + // Create share dialog + const dialog = document.createElement('div'); + dialog.style.cssText = ` + background: var(--color-bg); border: 1px solid var(--color-border); + border-radius: 0.75rem; padding: 1.5rem; max-width: 400px; width: 90%; + box-shadow: var(--shadow-lg); transform: scale(0.9); transition: transform 0.2s ease; + `; + + dialog.innerHTML = ` +
+

+ + + + + ${toolName} teilen +

+ +
+ +
+ + + + + +
+ `; + + backdrop.appendChild(dialog); + + // Show with animation + requestAnimationFrame(() => { + backdrop.style.opacity = '1'; + dialog.style.transform = 'scale(1)'; + }); + + // Event handlers + const closeDialog = () => { + backdrop.style.opacity = '0'; + dialog.style.transform = 'scale(0.9)'; + setTimeout(() => { + if (backdrop.parentNode) { + document.body.removeChild(backdrop); + } + }, 200); + }; + + backdrop.addEventListener('click', (e) => { + if (e.target === backdrop) closeDialog(); + }); + + document.getElementById('close-share-dialog').addEventListener('click', closeDialog); + + // Share option handlers + dialog.querySelectorAll('.share-option-btn').forEach(btn => { + btn.addEventListener('mouseover', () => { + btn.style.backgroundColor = 'var(--color-bg-secondary)'; + btn.style.borderColor = 'var(--color-primary)'; + }); + + btn.addEventListener('mouseout', () => { + btn.style.backgroundColor = 'var(--color-bg)'; + btn.style.borderColor = 'var(--color-border)'; + }); + + btn.addEventListener('click', () => { + const url = btn.getAttribute('data-url'); + copyToClipboard(url, btn); + }); + }); + }; + // Make functions globally available window.toggleDomainAgnosticSection = toggleDomainAgnosticSection; @@ -372,10 +579,23 @@ domains.forEach((domain: any) => { return `${conceptName}`; }).join(''); + // Check if mobile device + const isMobile = window.innerWidth <= 768; + const collapseOnMobile = isMobile && relatedConcepts.length > 2; + tagsHTML += `
- Verwandte Konzepte: -
+
+ Verwandte Konzepte: + ${collapseOnMobile ? ` + + ` : ''} +
+
${conceptLinks}
@@ -436,6 +656,30 @@ domains.forEach((domain: any) => { elements.links.innerHTML = linksHTML; + // ===== POPULATE SHARE BUTTON ===== + const shareButtonContainer = document.getElementById(`share-button-${modalType}`); + if (shareButtonContainer) { + const toolSlug = createToolSlug(tool.name); + shareButtonContainer.innerHTML = ` + + `; + shareButtonContainer.style.display = 'block'; + } + // Show modals and update layout const overlay = document.getElementById('modal-overlay'); const primaryModal = document.getElementById('tool-details-primary'); @@ -460,14 +704,28 @@ domains.forEach((domain: any) => { const secondaryModal = document.getElementById('tool-details-secondary'); if (modalType === 'both' || modalType === 'all') { - if (primaryModal) primaryModal.classList.remove('active'); - if (secondaryModal) secondaryModal.classList.remove('active'); + if (primaryModal) { + primaryModal.classList.remove('active'); + // Hide share button + const shareButtonPrimary = document.getElementById('share-button-primary'); + if (shareButtonPrimary) shareButtonPrimary.style.display = 'none'; + } + if (secondaryModal) { + secondaryModal.classList.remove('active'); + // Hide share button + const shareButtonSecondary = document.getElementById('share-button-secondary'); + if (shareButtonSecondary) shareButtonSecondary.style.display = 'none'; + } if (overlay) overlay.classList.remove('active'); document.body.classList.remove('modals-side-by-side'); } else if (modalType === 'primary' && primaryModal) { primaryModal.classList.remove('active'); + const shareButtonPrimary = document.getElementById('share-button-primary'); + if (shareButtonPrimary) shareButtonPrimary.style.display = 'none'; } else if (modalType === 'secondary' && secondaryModal) { secondaryModal.classList.remove('active'); + const shareButtonSecondary = document.getElementById('share-button-secondary'); + if (shareButtonSecondary) shareButtonSecondary.style.display = 'none'; } // Check if any modal is still active diff --git a/src/data/tools.yaml.example b/src/data/tools.yaml.example new file mode 100644 index 0000000..b3198e8 --- /dev/null +++ b/src/data/tools.yaml.example @@ -0,0 +1,206 @@ +# This is a minimal example file of the real knowledgebase in ./src/data/tools.yaml + - name: Rapid Incident Response Triage on macOS + icon: 📋 + type: method + description: >- + Spezialisierte Methodik für die schnelle Incident Response auf + macOS-Systemen mit Fokus auf die Sammlung kritischer forensischer + Artefakte in unter einer Stunde. Adressiert die Lücke zwischen + Windows-zentrierten IR-Prozessen und macOS-spezifischen + Sicherheitsarchitekturen. Nutzt Tools wie Aftermath für effiziente + Datensammlung ohne zeitaufwändige Full-Disk-Images. Besonders wertvoll für + Unternehmensumgebungen mit gemischten Betriebssystem-Landschaften. + domains: + - incident-response + - law-enforcement + - malware-analysis + phases: + - data-collection + - examination + platforms: [] + related_concepts: null + domain-agnostic-software: null + skillLevel: intermediate + accessType: null + url: >- + https://www.sans.org/white-papers/rapid-incident-response-on-macos-actionable-insights-under-hour/ + projectUrl: null + license: null + knowledgebase: null + tags: + - macos + - rapid-response + - triage + - incident-response + - aftermath + - enterprise + - methodology + - apple + - name: Aftermath + icon: 📦 + type: software + description: >- + Jamf's Open-Source-Tool für die schnelle Sammlung forensischer Artefakte + auf macOS-Systemen. Sammelt kritische Daten wie Prozessinformationen, + Netzwerkverbindungen, Dateisystem-Metadaten und Systemkonfigurationen ohne + Full-Disk-Imaging. Speziell entwickelt für die Rapid-Response-Triage in + Enterprise-Umgebungen mit macOS-Geräten. Normalisiert Zeitstempel und + erstellt durchsuchbare Ausgabeformate für effiziente Analyse. + domains: + - incident-response + - law-enforcement + - malware-analysis + phases: + - data-collection + - examination + platforms: + - macOS + related_concepts: null + domain-agnostic-software: null + skillLevel: intermediate + accessType: download + url: https://github.com/jamf/aftermath/ + projectUrl: '' + license: Apache 2.0 + knowledgebase: false + tags: + - macos + - incident-response + - triage + - artifact-collection + - rapid-response + - jamf + - enterprise + - commandline + - name: Regular Expressions (Regex) + icon: 🔤 + type: concept + description: >- + Pattern matching language for searching, extracting, and manipulating + text. Essential for log analysis, malware signature creation, and data + extraction from unstructured sources. Forms the backbone of many forensic + tools and custom scripts. + domains: + - incident-response + - malware-analysis + - network-forensics + - fraud-investigation + phases: + - examination + - analysis + platforms: [] + related_concepts: null + domain-agnostic-software: null + skillLevel: intermediate + accessType: null + url: https://regexr.com/ + projectUrl: null + license: null + knowledgebase: true + tags: + - pattern-matching + - text-processing + - log-analysis + - string-manipulation + - search-algorithms + - name: SQL Query Fundamentals + icon: 🗃️ + type: concept + description: >- + Structured Query Language for database interrogation and analysis. + Critical for examining application databases, SQLite artifacts from + mobile devices, and browser history databases. Enables complex + correlation and filtering of large datasets. + domains: + - incident-response + - mobile-forensics + - fraud-investigation + - cloud-forensics + phases: + - examination + - analysis + platforms: [] + related_concepts: null + domain-agnostic-software: null + skillLevel: intermediate + accessType: null + url: https://www.w3schools.com/sql/ + projectUrl: null + license: null + knowledgebase: false + tags: + - database-analysis + - query-language + - data-correlation + - mobile-artifacts + - browser-forensics + - name: Hash Functions & Digital Signatures + icon: 🔐 + type: concept + description: >- + Cryptographic principles for data integrity verification and + authentication. Fundamental for evidence preservation, malware + identification, and establishing chain of custody. Understanding of MD5, + SHA, and digital signature validation. + domains: + - incident-response + - law-enforcement + - malware-analysis + - cloud-forensics + phases: + - data-collection + - examination + platforms: [] + related_concepts: null + domain-agnostic-software: null + skillLevel: advanced + accessType: null + url: https://en.wikipedia.org/wiki/Cryptographic_hash_function + projectUrl: null + license: null + knowledgebase: false + tags: + - cryptography + - data-integrity + - evidence-preservation + - malware-identification + - chain-of-custody +domains: + - id: incident-response + name: Incident Response & Breach-Untersuchung + - id: law-enforcement + name: Strafverfolgung & Kriminalermittlung + - id: malware-analysis + name: Malware-Analyse & Reverse Engineering + - id: fraud-investigation + name: Betrugs- & Finanzkriminalität + - id: network-forensics + name: Netzwerk-Forensik & Traffic-Analyse + - id: mobile-forensics + name: Mobile Geräte & App-Forensik + - id: cloud-forensics + name: Cloud & Virtuelle Umgebungen + - id: ics-forensics + name: Industrielle Kontrollsysteme (ICS/SCADA) +phases: + - id: data-collection + name: Datensammlung + description: Imaging, Acquisition, Remote Collection Tools + - id: examination + name: Auswertung + description: Parsing, Extraction, Initial Analysis Tools + - id: analysis + name: Analyse + description: Deep Analysis, Correlation, Visualization Tools + - id: reporting + name: Bericht & Präsentation + description: >- + Documentation, Visualization, Presentation Tools (z.B. QGIS für Geodaten, + Timeline-Tools) +domain-agnostic-software: + - id: collaboration-general + name: Übergreifend & Kollaboration + description: Cross-cutting tools and collaboration platforms + - id: specific-os + name: Betriebssysteme + description: Operating Systems which focus on forensics diff --git a/src/pages/index.astro b/src/pages/index.astro index f16970f..d9b0c4f 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -93,15 +93,31 @@ const tools = data.tools; \ No newline at end of file diff --git a/src/styles/global.css b/src/styles/global.css index 560042b..c69d515 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -240,6 +240,25 @@ nav { background-color: var(--color-bg-tertiary); } +/* Icon Button */ +.btn-icon { + background: none; + border: none; + color: var(--color-text-secondary); + cursor: pointer; + padding: 0.25rem; + border-radius: 0.25rem; + transition: var(--transition-fast); + display: inline-flex; + align-items: center; + justify-content: center; +} + +.btn-icon:hover { + color: var(--color-text); + background-color: var(--color-bg-secondary); +} + .btn-accent { background-color: var(--color-accent); color: white; @@ -392,6 +411,8 @@ input[type="checkbox"] { line-height: 1; } + + .metadata-item { display: flex; align-items: center; @@ -647,7 +668,7 @@ input[type="checkbox"] { padding: 2rem; max-width: 600px; width: 90%; - max-height: 100vh; + max-height: 85vh; overflow-y: auto; z-index: 1000; box-shadow: var(--shadow-lg); @@ -1197,6 +1218,13 @@ Collaboration Section Collapse */ margin-bottom: 0.75rem; } +/* Enhanced highlight flash for different contexts */ +.tool-card.highlight-flash, +.tool-chip.highlight-flash, +.tool-recommendation.highlight-flash { + animation: highlight-flash 2s ease-out; +} + .pros-cons-section { animation: fadeIn 0.4s ease-in; } @@ -1309,11 +1337,76 @@ footer { } } -@keyframes highlight-flash { - 0% { background-color: rgb(37 99 235 / 10%); } - 100% { background-color: transparent; } -} +/*Perfect! Here's the absolutely brutal, eye-melting version:*/ +@keyframes highlight-flash { + 0% { + background-color: rgb(57 255 20 / 60%); + box-shadow: 0 0 0 8px rgb(255 20 147 / 50%), 0 0 20px rgb(57 255 20 / 80%); + transform: scale(1.12) rotate(2deg); + border: 3px solid rgb(255 255 0); + } + 12.5% { + background-color: rgb(255 20 147 / 70%); + box-shadow: 0 0 0 15px rgb(0 191 255 / 60%), 0 0 30px rgb(255 20 147 / 90%); + transform: scale(1.18) rotate(-3deg); + border: 3px solid rgb(57 255 20); + } + 25% { + background-color: rgb(0 191 255 / 65%); + box-shadow: 0 0 0 12px rgb(191 0 255 / 55%), 0 0 25px rgb(0 191 255 / 85%); + transform: scale(1.15) rotate(1deg); + border: 3px solid rgb(255 20 147); + } + 37.5% { + background-color: rgb(191 0 255 / 75%); + box-shadow: 0 0 0 18px rgb(255 255 0 / 65%), 0 0 35px rgb(191 0 255 / 95%); + transform: scale(1.20) rotate(-2deg); + border: 3px solid rgb(0 191 255); + } + 50% { + background-color: rgb(255 255 0 / 80%); + box-shadow: 0 0 0 10px rgb(57 255 20 / 70%), 0 0 40px rgb(255 255 0 / 100%); + transform: scale(1.16) rotate(3deg); + border: 3px solid rgb(191 0 255); + } + 62.5% { + background-color: rgb(255 69 0 / 70%); + box-shadow: 0 0 0 16px rgb(255 20 147 / 60%), 0 0 30px rgb(255 69 0 / 90%); + transform: scale(1.22) rotate(-1deg); + border: 3px solid rgb(255 255 0); + } + 75% { + background-color: rgb(255 20 147 / 65%); + box-shadow: 0 0 0 14px rgb(0 191 255 / 50%), 0 0 45px rgb(255 20 147 / 85%); + transform: scale(1.14) rotate(2deg); + border: 3px solid rgb(57 255 20); + } + 87.5% { + background-color: rgb(57 255 20 / 75%); + box-shadow: 0 0 0 20px rgb(191 0 255 / 65%), 0 0 35px rgb(57 255 20 / 95%); + transform: scale(1.25) rotate(-3deg); + border: 3px solid rgb(255 69 0); + } + 100% { + background-color: transparent; + box-shadow: none; + transform: scale(1) rotate(0deg); + border: none; + } +} +/* +This monstrosity includes: + +Neon rainbow cycling: Bright green → Hot pink → Electric blue → Neon purple → Nuclear yellow → Orange-red +Double shadows: Inner colored shadow + outer glow effect +Aggressive scaling: Up to 1.25x size +Rotation wobble: Cards wiggle back and forth +Strobing borders: Bright colored borders that change with each keyframe +8 keyframes: More frequent color/effect changes +Higher opacity: More saturated colors (up to 100% on yellow) + +This will literally assault the user's retinas. They'll need sunglasses to look at their shared tools! 🌈💥👁️‍🗨️*/ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } @@ -1404,6 +1497,12 @@ footer { width: 90vw; max-height: 35vh; } + .tool-details { + max-height: 80vh; + padding: 1.5rem; + width: 95%; + max-width: none; + } } @media (width <= 640px) { @@ -1488,6 +1587,11 @@ footer { font-size: 0.75rem; padding: 0.25rem 0.375rem; } + .tool-details { + max-height: 75vh; + padding: 1rem; + border-radius: 0.25rem; + } } @@ -1577,4 +1681,35 @@ footer { border: none; border-top: 1px solid var(--color-border); margin: 2rem 0; +} + +/* Share Button Styles */ +.share-btn { + background: none; + border: none; + color: var(--color-text-secondary); + cursor: pointer; + padding: 0.25rem; + border-radius: 0.25rem; + transition: var(--transition-fast); + display: inline-flex; + align-items: center; + justify-content: center; +} + +.share-btn:hover { + color: var(--color-primary); + background-color: var(--color-bg-secondary); +} + +.share-btn--small { + padding: 0.125rem; +} + +.share-btn--medium { + padding: 0.375rem; +} + +.share-btn svg { + flex-shrink: 0; } \ No newline at end of file