localization

This commit is contained in:
overcuriousity 2025-07-25 00:13:29 +02:00
parent e2e5fe1641
commit 1e7c1a2468
2 changed files with 66 additions and 76 deletions

View File

@ -14,7 +14,7 @@ if (authResult instanceof Response) {
const { authenticated, userEmail, userId } = authResult; const { authenticated, userEmail, userId } = authResult;
--- ---
<BaseLayout title="Contribute" description="Contribute tools, methods, concepts, and knowledge articles to CC24-Guide"> <BaseLayout title="Contribute" description="Inhalte zum CC24-Guide beitragen">
<section style="padding: 2rem 0;"> <section style="padding: 2rem 0;">
<!-- Header --> <!-- Header -->
<div style="text-align: center; margin-bottom: 3rem; padding: 2rem; background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-accent) 100%); color: white; border-radius: 1rem; border: 1px solid var(--color-border);"> <div style="text-align: center; margin-bottom: 3rem; padding: 2rem; background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-accent) 100%); color: white; border-radius: 1rem; border: 1px solid var(--color-border);">
@ -25,15 +25,15 @@ const { authenticated, userEmail, userId } = authResult;
<line x1="20" y1="8" x2="20" y2="14"/> <line x1="20" y1="8" x2="20" y2="14"/>
<line x1="23" y1="11" x2="17" y2="11"/> <line x1="23" y1="11" x2="17" y2="11"/>
</svg> </svg>
Contribute to CC24-Guide Zum CC24-Guide beitragen
</h1> </h1>
<p style="margin: 0; opacity: 0.9; line-height: 1.6; font-size: 1.125rem;"> <p style="margin: 0; opacity: 0.9; line-height: 1.6; font-size: 1.125rem;">
Help expand our DFIR knowledge base by contributing tools, methods, concepts, and detailed articles. Habt ihr Ideen/Ergänzungen zu den dargestellten Tools/Methoden/Konzepten? Oder habt ihr einen umfangreicheren Eintrag für unsere Knowledgebase?
All contributions are reviewed before being merged into the main database. Hier habt ihr die Möglichkeit, direkt beizutragen!
</p> </p>
{userEmail && ( {userEmail && (
<p style="margin-top: 1rem; opacity: 0.8; font-size: 0.9rem;"> <p style="margin-top: 1rem; opacity: 0.8; font-size: 0.9rem;">
Logged in as: <strong>{userEmail}</strong> Angemeldet als: <strong>{userEmail}</strong>
</p> </p>
)} )}
</div> </div>
@ -61,23 +61,23 @@ const { authenticated, userEmail, userId } = authResult;
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/> <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
</svg> </svg>
</div> </div>
<h3 style="margin: 0; color: var(--color-primary); font-size: 1.25rem;">Tools, Methods & Concepts</h3> <h3 style="margin: 0; color: var(--color-primary); font-size: 1.25rem;">Software, Methoden oder Konzepte</h3>
</div> </div>
<p style="margin-bottom: 1.5rem; line-height: 1.6;"> <p style="margin-bottom: 1.5rem; line-height: 1.6;">
Add new software tools, forensic methodologies, or fundamental concepts to our database. Ergänzt Software/Tools, forensische Methoden und relevante Konzepte zu unserer Datenbank.
Includes detailed forms for metadata, licensing, platforms, and categorization. Füllt einfach ein kurzes Formular aus!
</p> </p>
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;"> <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;">
<span class="badge" style="background-color: var(--color-primary); color: white;">Software Tools</span> <span class="badge" style="background-color: var(--color-primary); color: white;">Software/Tools</span>
<span class="badge" style="background-color: var(--color-method); color: white;">Methods</span> <span class="badge" style="background-color: var(--color-method); color: white;">Methoden</span>
<span class="badge" style="background-color: var(--color-concept); color: white;">Concepts</span> <span class="badge" style="background-color: var(--color-concept); color: white;">Konzepte</span>
</div> </div>
<div style="margin-top:auto; display:flex; gap:1rem;"> <div style="margin-top:auto; display:flex; gap:1rem;">
<a href="/contribute/tool" class="btn btn-primary" style="flex: 1;">Add New Entry</a> <a href="/contribute/tool" class="btn btn-primary" style="flex: 1;">Neuer Eintrag</a>
<a href="/contribute/tool?mode=browse" class="btn btn-secondary" style="flex: 1;">Edit Existing</a> <a href="/contribute/tool?mode=browse" class="btn btn-secondary" style="flex: 1;">Existierenden Bearbeiten</a>
</div> </div>
</div> </div>
@ -96,24 +96,24 @@ const { authenticated, userEmail, userId } = authResult;
<polyline points="10 9 9 9 8 9"/> <polyline points="10 9 9 9 8 9"/>
</svg> </svg>
</div> </div>
<h3 style="margin: 0; color: var(--color-accent); font-size: 1.25rem;">Knowledgebase Articles</h3> <h3 style="margin: 0; color: var(--color-accent); font-size: 1.25rem;">Knowledgebase-Artikel</h3>
</div> </div>
<p style="margin-bottom: 1.5rem; line-height: 1.6;"> <p style="margin-bottom: 1.5rem; line-height: 1.6;">
Write detailed guides, tutorials, configuration instructions, and best practices. Wenn ihr einen umfangreicheren Beitrag zu einem Tool, einer Methode oder einem Kozept habt, könnt ihr ihn hier einreichen.
Features a markdown editor with live preview and media upload capabilities. Dazu müsst ihr ein kurzes Formular ausfüllen, zusätzlich könnt ihr Dateien einreichen.
</p> </p>
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;"> <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;">
<span class="badge badge-secondary">Installation Guides</span> <span class="badge badge-secondary">Installationsanleitungen</span>
<span class="badge badge-secondary">Tutorials</span> <span class="badge badge-secondary">Tutorials</span>
<span class="badge badge-secondary">Best Practices</span> <span class="badge badge-secondary">Best Practices</span>
<span class="badge badge-secondary">Case Studies</span> <span class="badge badge-secondary">Fallstudien</span>
</div> </div>
<div style="margin-top:auto; display:flex; gap:1rem;"> <div style="margin-top:auto; display:flex; gap:1rem;">
<a href="/contribute/knowledgebase" class="btn btn-accent" style="flex: 1;">Write Article</a> <a href="/contribute/knowledgebase" class="btn btn-accent" style="flex: 1;">Beitrag einreichen</a>
<a href="/knowledgebase" class="btn btn-secondary" style="flex: 1;">View Articles</a> <a href="/knowledgebase" class="btn btn-secondary" style="flex: 1;">Beiträge ansehen</a>
</div> </div>
</div> </div>
@ -129,19 +129,19 @@ const { authenticated, userEmail, userId } = authResult;
<line x1="12" y1="16" x2="12.01" y2="16"/> <line x1="12" y1="16" x2="12.01" y2="16"/>
</svg> </svg>
</div> </div>
<h3 style="margin: 0; color: var(--color-warning); font-size: 1.25rem;">Issues & Improvements</h3> <h3 style="margin: 0; color: var(--color-warning); font-size: 1.25rem;">Probleme & Verbesserungen</h3>
</div> </div>
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 2rem; align-items: center;"> <div style="display: grid; grid-template-columns: 2fr 1fr; gap: 2rem; align-items: center;">
<div style="display:flex; flex-direction:column;"> <div style="display:flex; flex-direction:column;">
<p style="margin-bottom: 1rem; line-height: 1.6;"> <p style="margin-bottom: 1rem; line-height: 1.6;">
Found incorrect information, broken links, or have suggestions for improvements? Ist euch ein Bug oder eine fehlerhafte Information aufgefallen? Auch wenn es nur Kleinigkeiten sind - hier könnt ihr sie einreichen.
Report issues directly in our Git repository or suggest enhancements to existing entries. Erstellt direkt einen Issue in unserem Git.
</p> </p>
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem;"> <div style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
<span class="badge" style="background-color: var(--color-warning); color: white;">Bug Reports</span> <span class="badge" style="background-color: var(--color-warning); color: white;">Bug Reports</span>
<span class="badge" style="background-color: var(--color-warning); color: white;">Corrections</span> <span class="badge" style="background-color: var(--color-warning); color: white;">Korrekturen</span>
<span class="badge" style="background-color: var(--color-warning); color: white;">Suggestions</span> <span class="badge" style="background-color: var(--color-warning); color: white;">Vorschläge</span>
</div> </div>
</div> </div>
<div style="display: flex; flex-direction: column; gap: 1rem;"> <div style="display: flex; flex-direction: column; gap: 1rem;">
@ -151,7 +151,7 @@ const { authenticated, userEmail, userId } = authResult;
<polyline points="15 3 21 3 21 9"/> <polyline points="15 3 21 3 21 9"/>
<line x1="10" y1="14" x2="21" y2="3"/> <line x1="10" y1="14" x2="21" y2="3"/>
</svg> </svg>
Report Issue Problem melden
</a> </a>
</div> </div>
</div> </div>
@ -165,39 +165,40 @@ const { authenticated, userEmail, userId } = authResult;
<!-- Guidelines --> <!-- Guidelines -->
<div class="card" style="margin-bottom: 2rem;"> <div class="card" style="margin-bottom: 2rem;">
<h3 style="margin-bottom: 1.5rem; color: var(--color-text);">Contribution Guidelines</h3> <h3 style="margin-bottom: 1.5rem; color: var(--color-text);">Richtlinien</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.5rem;">
<div> <div>
<h4 style="margin-bottom: 0.75rem; color: var(--color-primary);">Quality Standards</h4> <h4 style="margin-bottom: 0.75rem; color: var(--color-primary);">Qualitätsstandards</h4>
<ul style="margin: 0; padding-left: 1.5rem; line-height: 1.6;"> <ul style="margin: 0; padding-left: 1.5rem; line-height: 1.6;">
<li>Provide accurate and up-to-date information</li> <li>Informationen sollten stets korrekt und up-to-date sein</li>
<li>Use clear, professional language</li> <li>Nutzt klare, verständliche Sprache</li>
<li>Include relevant tags and categorization</li> <li>Nutzt passende Tags und Kategorisierungen</li>
<li>Verify all URLs and links work correctly</li> <li>Verifiziert, ob alle Links funktionieren</li>
<li>Test installation and configuration steps</li> <li>Testet die Tools/Methoden oder Installationsanleitungen nach Möglichkeit vorher aus</li>
<li>Stellt auf keinen Fall Informationen ein, die nicht öffentlich sein dürfen. Alles wird unter BSD-3-Clause-Veröffentlicht.</li>
</ul> </ul>
</div> </div>
<div> <div>
<h4 style="margin-bottom: 0.75rem; color: var(--color-accent);">Review Process</h4> <h4 style="margin-bottom: 0.75rem; color: var(--color-accent);">QS</h4>
<ul style="margin: 0; padding-left: 1.5rem; line-height: 1.6;"> <ul style="margin: 0; padding-left: 1.5rem; line-height: 1.6;">
<li>All contributions are submitted as pull requests</li> <li>Alle Beiträge werden transparent als Pull Requests in unserem Git veröffentlicht</li>
<li>Automated validation checks run on submissions</li> <li>Die Inforamtionen werden teilweise automatisiert validiert</li>
<li>Manual review by CC24 team members</li> <li>Manuelle Prüfung innerhalb des Git-Review-Prozesses durch Maintainer</li>
<li>Feedback provided through PR comments</li> <li>Feedback durch PR-Kommentare, ggf. auch direkt</li>
<li>Merge after approval and testing</li> <li>Der PR wird dann zeitnah veröffentlicht und ist beim nächsten Serverupdate verfügbar</li>
</ul> </ul>
</div> </div>
<div> <div>
<h4 style="margin-bottom: 0.75rem; color: var(--color-warning);">Best Practices</h4> <h4 style="margin-bottom: 0.75rem; color: var(--color-warning);">Best Practices</h4>
<ul style="margin: 0; padding-left: 1.5rem; line-height: 1.6;"> <ul style="margin: 0; padding-left: 1.5rem; line-height: 1.6;">
<li>Search existing entries before adding duplicates</li> <li>Vermeidet Duplokate</li>
<li>Use consistent naming and categorization</li> <li>Versucht, konsistent bei der Benennung, Kategorisierung und Tags zu sein</li>
<li>Provide detailed descriptions and use cases</li> <li>Schreibt detaillierte Beschreibungen</li>
<li>Include screenshots for complex procedures</li> <li>Inkludiert Screenshots bei komplizierten Guides</li>
<li>Credit original sources and authors</li> <li>Nennt eure Primärquellen</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -24,7 +24,7 @@ const editToolName = Astro.url.searchParams.get('edit');
const editTool = editToolName ? existingTools.find(tool => tool.name === editToolName) : null; const editTool = editToolName ? existingTools.find(tool => tool.name === editToolName) : null;
const isEdit = !!editTool; const isEdit = !!editTool;
const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool'; const title = isEdit ? `Edit ${editTool?.name}` : 'Beitrag erstellen';
--- ---
<BaseLayout title={title} description="Contribute tools, methods, and concepts to the CC24-Guide database"> <BaseLayout title={title} description="Contribute tools, methods, and concepts to the CC24-Guide database">
@ -39,12 +39,12 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
<line x1="16" y1="17" x2="8" y2="17"/> <line x1="16" y1="17" x2="8" y2="17"/>
<polyline points="10 9 9 9 8 9"/> <polyline points="10 9 9 9 8 9"/>
</svg> </svg>
{isEdit ? `Edit Tool: ${editTool?.name}` : 'Contribute New Tool'} {isEdit ? `Eintrag editieren: ${editTool?.name}` : 'Beitragen - Formular'}
</h1> </h1>
<p style="margin: 0; opacity: 0.9; line-height: 1.5;"> <p style="margin: 0; opacity: 0.9; line-height: 1.5;">
{isEdit {isEdit
? 'Update the information for this tool, method, or concept. Your changes will be submitted as a pull request for review.' ? 'Überarbeitet die Informationen zu diesem Tool, Methode oder Konzept. Deine Änderungen werden als Pull-Request eingereicht.'
: 'Submit a new tool, method, or concept to the CC24-Guide database. Your contribution will be reviewed before being added.' : 'Erstellt ein neues Tool, Methode, oder Konzept in der CC24-Guide Datenbank. Dein Beitrag wird als Pull-Request eingereicht.'
} }
</p> </p>
</div> </div>
@ -57,16 +57,16 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
<!-- Tool Type Selection --> <!-- Tool Type Selection -->
<div> <div>
<label for="tool-type" style="display: block; margin-bottom: 0.5rem; font-weight: 600;"> <label for="tool-type" style="display: block; margin-bottom: 0.5rem; font-weight: 600;">
Tool Type <span style="color: var(--color-error);">*</span> Beitragstyp <span style="color: var(--color-error);">*</span>
</label> </label>
<select id="tool-type" name="type" required style="max-width: 300px;"> <select id="tool-type" name="type" required style="max-width: 300px;">
<option value="">Select type...</option> <option value="">Auswählen...</option>
<option value="software" selected={editTool?.type === 'software'}>Software</option> <option value="software" selected={editTool?.type === 'software'}>Software</option>
<option value="method" selected={editTool?.type === 'method'}>Method</option> <option value="method" selected={editTool?.type === 'method'}>Methode</option>
<option value="concept" selected={editTool?.type === 'concept'}>Concept</option> <option value="concept" selected={editTool?.type === 'concept'}>Konzept</option>
</select> </select>
<div class="field-help" style="font-size: 0.8125rem; color: var(--color-text-secondary); margin-top: 0.25rem;"> <div class="field-help" style="font-size: 0.8125rem; color: var(--color-text-secondary); margin-top: 0.25rem;">
Software: Applications and tools • Method: Procedures and methodologies • Concept: Fundamental knowledge Software: Anwendungen und Tools • Methode: Prozeduren und Workflows • Konzept: Gruundlagenwissen
</div> </div>
</div> </div>
@ -79,7 +79,7 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
</label> </label>
<input type="text" id="tool-name" name="name" required maxlength="100" <input type="text" id="tool-name" name="name" required maxlength="100"
value={editTool?.name || ''} value={editTool?.name || ''}
placeholder="e.g., Autopsy, Live Response Methodology, Regular Expressions" /> placeholder="z.B., Autopsy, Live Response im Active Directory, Regular Expressions" />
<div id="name-error" class="field-error" style="display: none;"></div> <div id="name-error" class="field-error" style="display: none;"></div>
</div> </div>
@ -92,7 +92,7 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
value={editTool?.icon || ''} value={editTool?.icon || ''}
placeholder="📦 🔧 📋 (optional, single emoji recommended)" /> placeholder="📦 🔧 📋 (optional, single emoji recommended)" />
<div class="field-help"> <div class="field-help">
Choose an emoji that represents your tool/method/concept. Leave blank if unsure. Wählt ein Emoji, das euer Tool/Methode/Konzept repräsentiert. Kann auch freigelassen werden.
</div> </div>
</div> </div>
</div> </div>
@ -100,13 +100,13 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
<!-- Description --> <!-- Description -->
<div> <div>
<label for="tool-description" style="display: block; margin-bottom: 0.5rem; font-weight: 600;"> <label for="tool-description" style="display: block; margin-bottom: 0.5rem; font-weight: 600;">
Description <span style="color: var(--color-error);">*</span> Beschreibung <span style="color: var(--color-error);">*</span>
</label> </label>
<textarea id="tool-description" name="description" required <textarea id="tool-description" name="description" required
rows="4" minlength="10" maxlength="1000" rows="4" minlength="10" maxlength="1000"
placeholder="Provide a clear, concise description of what this tool/method/concept is and what it does...">{editTool?.description || ''}</textarea> placeholder="Schreibt eine klare, kurze Beschreibung (2-5 Sätze) mit dem, was euer Tool/Methode/Konzept macht.">{editTool?.description || ''}</textarea>
<div style="display: flex; justify-content: space-between; margin-top: 0.25rem;"> <div style="display: flex; justify-content: space-between; margin-top: 0.25rem;">
<div class="field-help">Be specific about functionality, use cases, and key features.</div> <div class="field-help">Seid spezifisch hinsichtlich use-case, Funktionalität und Schlüsselfeatures.</div>
<div id="description-count" style="font-size: 0.75rem; color: var(--color-text-secondary);">0/1000</div> <div id="description-count" style="font-size: 0.75rem; color: var(--color-text-secondary);">0/1000</div>
</div> </div>
<div id="description-error" class="field-error" style="display: none;"></div> <div id="description-error" class="field-error" style="display: none;"></div>
@ -117,25 +117,15 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
<!-- Main URL --> <!-- Main URL -->
<div> <div>
<label for="tool-url" style="display: block; margin-bottom: 0.5rem; font-weight: 600;"> <label for="tool-url" style="display: block; margin-bottom: 0.5rem; font-weight: 600;">
Main URL <span style="color: var(--color-error);">*</span> Hauptlink <span style="color: var(--color-error);">*</span>
</label> </label>
<input type="url" id="tool-url" name="url" required <input type="url" id="tool-url" name="url" required
value={editTool?.url || ''} value={editTool?.url || ''}
placeholder="https://example.com" /> placeholder="https://example.com" />
<div class="field-help">Homepage, documentation, or primary resource link</div> <div class="field-help">Homepage, Dokumentation, oder Primärquelle</div>
<div id="url-error" class="field-error" style="display: none;"></div> <div id="url-error" class="field-error" style="display: none;"></div>
</div> </div>
<!-- Project URL (CC24 Server) -->
<div id="project-url-field" style="display: none;">
<label for="project-url" style="display: block; margin-bottom: 0.5rem; font-weight: 600;">
CC24 Server URL
</label>
<input type="url" id="project-url" name="projectUrl"
value={editTool?.projectUrl || ''}
placeholder="https://tool.cc24.dev" />
<div class="field-help">Internal CC24 server URL (if hosted)</div>
</div>
</div> </div>
<!-- Categories --> <!-- Categories -->
@ -143,7 +133,7 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
<!-- Domains --> <!-- Domains -->
<div> <div>
<label for="tool-domains" style="display: block; margin-bottom: 0.5rem; font-weight: 600;"> <label for="tool-domains" style="display: block; margin-bottom: 0.5rem; font-weight: 600;">
Forensic Domains Forensische Domänen
</label> </label>
<select id="tool-domains" name="domains" multiple size="4"> <select id="tool-domains" name="domains" multiple size="4">
{domains.map(domain => ( {domains.map(domain => (
@ -153,13 +143,13 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
</option> </option>
))} ))}
</select> </select>
<div class="field-help">Hold Ctrl/Cmd to select multiple. Leave empty for domain-agnostic.</div> <div class="field-help">Strg gedrückt halten, um mehrere zu selektieren. Freilassen, wenn es zu keiner Domäne passt.</div>
</div> </div>
<!-- Phases --> <!-- Phases -->
<div> <div>
<label for="tool-phases" style="display: block; margin-bottom: 0.5rem; font-weight: 600;"> <label for="tool-phases" style="display: block; margin-bottom: 0.5rem; font-weight: 600;">
Investigation Phases Ermittlungsphasen
</label> </label>
<select id="tool-phases" name="phases" multiple size="4"> <select id="tool-phases" name="phases" multiple size="4">
{phases.map(phase => ( {phases.map(phase => (
@ -175,7 +165,7 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
</option> </option>
))} ))}
</select> </select>
<div class="field-help">Select applicable investigation phases</div> <div class="field-help">Zutreffende auswählen</div>
</div> </div>
</div> </div>
@ -185,7 +175,7 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
<!-- Platforms --> <!-- Platforms -->
<div> <div>
<label for="tool-platforms" style="display: block; margin-bottom: 0.5rem; font-weight: 600;"> <label for="tool-platforms" style="display: block; margin-bottom: 0.5rem; font-weight: 600;">
Platforms <span id="platforms-required" style="color: var(--color-error);">*</span> Plattformen <span id="platforms-required" style="color: var(--color-error);">*</span>
</label> </label>
<div id="platforms-checkboxes" style="display: grid; gap: 0.25rem; font-size: 0.875rem;"> <div id="platforms-checkboxes" style="display: grid; gap: 0.25rem; font-size: 0.875rem;">
{['Windows', 'macOS', 'Linux', 'Web', 'Mobile', 'Cross-platform'].map(platform => ( {['Windows', 'macOS', 'Linux', 'Web', 'Mobile', 'Cross-platform'].map(platform => (
@ -415,7 +405,6 @@ const title = isEdit ? `Edit ${editTool?.name}` : 'Contribute New Tool';
domainAgnosticSoftware, domainAgnosticSoftware,
existingConcepts: existingTools.filter(t => t.type === 'concept') existingConcepts: existingTools.filter(t => t.type === 'concept')
}}> }}>
// REPLACE the JavaScript section at the bottom of tool.astro with this:
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('contribution-form'); const form = document.getElementById('contribution-form');