Navigation Script generate-navigation.js - So funktioniert's
Wie das Script alle Navigationen, Header, Footer und Sidebars automatisch generiert – Schritt für Schritt.
Was macht das Script?
Das
generate-navigation.js
Script ist das Herzstück der automatischen Navigation auf DevPanicZone. Es durchsucht alle
Tutorial-Dateien und erstellt automatisch:
- Header & Footer auf allen Seiten
- Main Navigation (Dropdown-Menü mit allen Kategorien)
- Breadcrumbs (Navigationspfad: Home › Kategorie › Tutorial)
- Prev/Next Navigation (Vorheriges/Nächstes Tutorial)
- Sidebar TOC (Inhaltsverzeichnis aus Überschriften)
- Sidebar Tutorial-Liste (Alle Tutorials der Kategorie)
- Tutorial-Buttons (Übersicht auf Kategorieseiten)
Stell dir vor, du müsstest bei jedem neuen Tutorial ALLE anderen Tutorial-Seiten manuell
aktualisieren! Das Script macht das automatisch mit einem einzigen Befehl:
npm run build
Aufbau des Scripts
Das Script ist in logische Abschnitte unterteilt. Lass uns jeden einzelnen durchgehen!
1. Konfiguration & Setup
Ganz am Anfang werden die wichtigsten Einstellungen definiert:
const fs = require('fs');
const path = require('path');
const { JSDOM } = require('jsdom');
// Pfade vom scripts/ Ordner aus
const tutorialsDir = path.join(__dirname, '..', 'tutorials');
const assetsDir = path.join(__dirname, '..', 'assets');
// Blacklist: Diese Ordner werden ignoriert
const BLACKLIST_FOLDERS = ['noupload', 'node_modules', '.git', 'assets'];
Was passiert hier?
-
fs→ Zum Lesen und Schreiben von Dateien -
path→ Zum Arbeiten mit Dateipfaden -
JSDOM→ Zum Parsen und Manipulieren von HTML
-
tutorialsDir→ Zeigt auf den/tutorialsOrdner -
BLACKLIST_FOLDERS→ Ordner, die das Script ignorieren soll
Das Script liegt in
/scripts/generate-navigation.js
. Um auf
/tutorials
zu kommen, muss es einen Ordner HOCH
..
und dann in den
tutorials
Ordner.
2. Deine Konfiguration
Diese Konstanten definierst DU - sie steuern, wie die Navigationen aussehen:
// Kategorie-Namen für Main-Navigation
const CATEGORY_NAMES = {
'html': 'HTML',
'css': 'CSS',
'javascript': 'JavaScript'
};
// Reihenfolge der Tutorials
const TUTORIAL_ORDER = {
'tutorials/html/html-basics': [
'html-basics.html',
'html-grundgeruest.html'
]
};
// Eigene Titel für Links
const CUSTOM_TITLES = {
'tutorials/html/html-basics/html-basics.html': 'Was ist HTML?'
};
Das bedeutet:
-
CATEGORY_NAMES→ Welche Kategorien im Dropdown erscheinen -
TUTORIAL_ORDER→ In welcher Reihenfolge Tutorials erscheinen (wichtig für Prev/Next!) -
CUSTOM_TITLES→ Alternative Namen für Links (z.B. statt "html-basics" → "Was ist HTML?")
3. Latest Tutorials für die Startseite
Die "Neueste Tutorials" auf der Startseite werden manuell gepflegt :
const LATEST_TUTORIALS = [
'tutorials/css/css-specials/css-organization.html',
'tutorials/javascript/javascript-basics/js-security.html',
'tutorials/misc/web/console-security.html',
'tutorials/php/php-basics/php-security.html'
];
- Die ersten 4 Einträge erscheinen auf der Startseite
- Reihenfolge im Array = Reihenfolge auf der Startseite
- Neues Tutorial featuren? → An Position 1 einfügen, letztes entfernen
4. Header & Footer Templates
Das Script hat fertige HTML-Templates für Header und Footer gespeichert:
const HEADER_TEMPLATE = `<!-- Header -->
<header class="site-header">
<div class="container">
<!-- Logo, Theme Toggle, Navigation... -->
</div>
</header>`;
const FOOTER_TEMPLATE = `<footer class="site-footer">
<div class="container">
<!-- Copyright, Links... -->
</div>
</footer>`;
Vorteil: Wenn du den Header ändern willst, änderst du ihn nur HIER - dann wird er auf ALLEN Seiten aktualisiert!
5. Akronyme automatisch kapitalisieren
Das Script erkennt Akronyme und kapitalisiert sie korrekt in allen Navigationstiteln:
const ACRONYMS = {
'html': 'HTML',
'css': 'CSS',
'php': 'PHP',
'js': 'JS',
'javascript': 'JavaScript',
'seo': 'SEO',
'ftp': 'FTP',
'devpaniczone': 'DevPanicZone'
};
function capitalizeWithAcronyms(text) {
return text.split('-')
.map(word => {
const lower = word.toLowerCase();
if (ACRONYMS[lower]) {
return ACRONYMS[lower];
}
return word.charAt(0).toUpperCase() + word.slice(1);
})
.join(' ');
}
Beispiel:
Der Ordner
html-basics
wird zu "HTML Basics" (nicht "Html Basics").
Hilfsfunktionen
Das Script hat kleine Helferlein, die bestimmte Aufgaben übernehmen:
findHtmlFiles() - HTML-Dateien finden
function findHtmlFiles(dir, fileList = []) {
const files = fs.readdirSync(dir);
files.forEach(file => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
// Blacklist-Ordner ignorieren
if (BLACKLIST_FOLDERS.includes(file)) {
return;
}
// Rekursiv in Unterordner gehen
findHtmlFiles(filePath, fileList);
} else if (file.endsWith('.html')) {
fileList.push(filePath);
}
});
return fileList;
}
Was macht die Funktion?
- Liest alle Dateien in einem Ordner
- Ist es ein Ordner? → Prüfe, ob er auf der Blacklist steht
- Ist es keine Blacklist? → Gehe rekursiv in den Ordner (Funktion ruft sich selbst auf!)
- Ist es eine HTML-Datei? → Füge sie zur Liste hinzu
Die Funktion ruft sich selbst auf! Das ermöglicht es, durch ALLE Unterordner zu gehen, egal wie tief verschachtelt.
getCategoryFromPath() - Kategorie ermitteln
function getCategoryFromPath(filePath) {
const relativePath = path.relative(tutorialsDir, filePath);
const parts = relativePath.split(path.sep);
return parts[0]; // Erste Ebene (html, css, etc.)
}
Beispiel:
-
Pfad:
/tutorials/html/html-basics/html-basics.html -
Relative Pfad:
html/html-basics/html-basics.html
-
Aufteilen:
['html', 'html-basics', 'html-basics.html'] -
Erste Ebene:
html← Das ist die Kategorie!
getSubcategoryFromPath() - Unterkategorie ermitteln
function getSubcategoryFromPath(filePath) {
const relativePath = path.relative(tutorialsDir, filePath);
const parts = relativePath.split(path.sep);
if (parts.length >= 2) {
return 'tutorials/' + parts.slice(0, 2).join('/');
}
return 'tutorials/' + parts[0];
}
Beispiel:
-
Pfad:
/tutorials/html/html-basics/html-basics.html -
Parts:
['html', 'html-basics', 'html-basics.html']
-
Erste 2 Ebenen:
['html', 'html-basics'] -
Ergebnis:
tutorials/html/html-basics
Warum wichtig?
Das Script braucht diese Info, um in
TUTORIAL_ORDER
die richtige Reihenfolge zu finden!
Navigation-Generierung
Jetzt wird's interessant! Diese Funktionen erstellen die eigentlichen Navigationen:
generateMainNavigation() – Dropdown mit Submenus
Die neue Version erstellt verschachtelte Submenus für jede Kategorie:
function generateMainNavigation() {
const categories = Object.keys(CATEGORY_NAMES);
const navItems = [];
categories.forEach(category => {
const categoryName = CATEGORY_NAMES[category];
const subcategories = getSubcategoriesForCategory(category);
if (Object.keys(subcategories).length > 0) {
let navItem = `<li class="nav-item-nested">
<a href="/tutorials/${category}/" class="nav-link">
${categoryName}
<span class="submenu-icon">▸</span>
</a>
<ul class="dropdown-submenu">`;
// Unterkategorien hinzufügen
Object.keys(subcategories).forEach(subKey => {
const sub = subcategories[subKey];
navItem += `
<li><a href="/tutorials/${category}/#${subKey}">${sub.name}</a></li>`;
});
navItem += `
</ul>
</li>`;
navItems.push(navItem);
}
});
return navItems;
}
Was ist neu?
-
.nav-item-nested– Kategorie mit aufklappbarem Submenu -
.dropdown-submenu– Liste der Unterkategorien -
.submenu-icon– Pfeil-Symbol (▸) zeigt Submenu an -
Links zu Ankern:
/tutorials/html/#html-basics
Ergebnis im Dropdown:
Tutorials ▾
├── HTML ▸
│ ├── HTML Basics
│ └── HTML Advanced
├── CSS ▸
│ ├── CSS Basics
│ └── CSS Specials
└── JavaScript ▸
├── JavaScript Basics
└── JavaScript Projects
generateBreadcrumbs() - Navigationspfad
function generateBreadcrumbs(filePath, currentTitle) {
const category = getCategoryFromPath(filePath);
const categoryName = CATEGORY_NAMES[category] || category;
const basename = path.basename(filePath);
// Kategorieseite: Home › Kategorie
if (basename === 'index.html') {
return `<a href="/">Home</a>
<span>›</span>
<span>${categoryName}</span>`;
}
// Tutorial-Seite: Home › Kategorie › Tutorial
return `<a href="/">Home</a>
<span>›</span>
<a href="/tutorials/${category}/">${categoryName}</a>
<span>›</span>
<span>${currentTitle}</span>`;
}
Unterschied:
-
Kategorieseite:
Home › CSS(CSS ist nicht klickbar) -
Tutorial-Seite:
Home › CSS › Flexbox(CSS ist klickbar!)
generatePrevNextNav() – Kategorieübergreifend
Die Prev/Next-Navigation führt durch alle Tutorials einer Hauptkategorie , nicht nur innerhalb einer Unterkategorie:
function generatePrevNextNav(filePath) {
const category = getCategoryFromPath(filePath);
const currentSubcategory = getSubcategoryFromPath(filePath);
const allTutorials = getAllTutorialsFlat(category); // Alle Tutorials der Kategorie!
const currentIndex = allTutorials.findIndex(t => t.filePath === filePath);
if (currentIndex === -1) return '';
const prev = currentIndex > 0 ? allTutorials[currentIndex - 1] : null;
const next = currentIndex < allTutorials.length - 1 ? allTutorials[currentIndex + 1] : null;
let navHtml = '';
// PREV Button
if (prev) {
const prevSubcategory = `tutorials/${category}/${prev.subcategory}`;
const isNewCategory = prevSubcategory !== currentSubcategory;
const categoryClass = isNewCategory ? ' is-new' : '';
navHtml += `<div class="tutorial-nav-prev">
<a href="${prev.url}">
<span class="tutorial-nav-label">← Vorheriges</span>
<span class="tutorial-nav-link">${prev.title}</span>
<span class="tutorial-nav-category${categoryClass}">${prev.subcategoryDisplay}</span>
</a>
</div>`;
} else {
navHtml += '<div class="tutorial-nav-prev"></div>';
}
// NEXT Button (analog)
if (next) {
const nextSubcategory = `tutorials/${category}/${next.subcategory}`;
const isNewCategory = nextSubcategory !== currentSubcategory;
const categoryClass = isNewCategory ? ' is-new' : '';
navHtml += `<div class="tutorial-nav-next">
<a href="${next.url}">
<span class="tutorial-nav-label">Nächstes →</span>
<span class="tutorial-nav-link">${next.title}</span>
<span class="tutorial-nav-category${categoryClass}">${next.subcategoryDisplay}</span>
</a>
</div>`;
} else {
navHtml += '<div class="tutorial-nav-next"></div>';
}
return navHtml;
}
Was ist neu gegenüber der alten Version?
Alt (vor v2.2):
- Nur innerhalb einer Unterkategorie
- Am Ende von "HTML Basics" → Sackgasse
- Kein Hinweis auf Kategorie-Wechsel
Neu (v2.2):
- Durch alle Tutorials der Hauptkategorie
- "HTML Basics" → weiter zu "HTML Advanced"
- Badge zeigt Unterkategorie an
-
.is-newKlasse bei Kategorie-Wechsel
Beispiel-Output:
<div class="tutorial-nav-prev">
<a href="/tutorials/html/html-basics/html-listen.html">
<span class="tutorial-nav-label">← Vorheriges</span>
<span class="tutorial-nav-link">HTML Listen</span>
<span class="tutorial-nav-category">HTML Basics</span>
</a>
</div><div class="tutorial-nav-next">
<a href="/tutorials/html/html-advanced/html-semantik.html">
<span class="tutorial-nav-label">Nächstes →</span>
<span class="tutorial-nav-link">HTML Semantik</span>
<span class="tutorial-nav-category is-new">HTML Advanced</span>
</a>
</div>
Diese Funktion sammelt alle Tutorials einer Hauptkategorie (z.B. "html") als flache,
geordnete Liste – über alle Unterkategorien hinweg. Die Reihenfolge folgt der
Definition in
TUTORIAL_ORDER
.
addIdsToHeadingsAndGenerateSidebar() - Sidebar TOC
Diese Funktion macht mehrere Dinge auf einmal:
-
Findet alle
<h2>und<h3>Überschriften - Fügt ihnen IDs hinzu (falls keine vorhanden)
- Prüft ob Custom Titles in TOC_CUSTOM_TITLES definiert sind
- Erstellt die Sidebar-Links mit Custom oder Original-Titel
function addIdsToHeadingsAndGenerateSidebar(html, filename) {
const dom = new JSDOM(html);
const doc = dom.window.document;
const headings = doc.querySelectorAll('h2, h3');
const anchors = [];
const usedIds = new Set();
headings.forEach(heading => {
// Überschriften mit class="no-toc" überspringen
if (heading.classList.contains('no-toc')) return;
let id = heading.id;
// ID generieren wenn keine vorhanden
if (!id) {
id = heading.textContent.trim().toLowerCase()
.replace(/[äöüÄÖÜß]/g, match => {
const map = {
'ä': 'ae', 'ö': 'oe', 'ü': 'ue',
'Ä': 'Ae', 'Ö': 'Oe', 'Ü': 'Ue', 'ß': 'ss'
};
return map[match];
})
.replace(/[^\w\s-]/g, '') // Sonderzeichen entfernen
.replace(/\s+/g, '-'); // Leerzeichen → Bindestriche
// Duplikate vermeiden
let finalId = id;
let counter = 1;
while (usedIds.has(finalId)) {
finalId = `${id}-${counter}`;
counter++;
}
// ID ins Heading einfügen!
heading.id = finalId;
id = finalId;
}
usedIds.add(id);
const level = heading.tagName === 'H2' ? 'toc-level-1' : 'toc-level-2';
// Custom Title verwenden falls vorhanden, sonst Original-Text
let displayTitle = heading.textContent.trim();
if (TOC_CUSTOM_TITLES[filename] && TOC_CUSTOM_TITLES[filename][id]) {
displayTitle = TOC_CUSTOM_TITLES[filename][id];
}
// Sidebar-Link erstellen
anchors.push(
`<li class="${level}"><a href="#${id}">${displayTitle}</a></li>`
);
});
return {
html: dom.serialize(), // HTML mit IDs!
anchors: anchors.join('\n')
};
}
Beispiel Normal:
-
Überschrift:
<h2>Was ist CSS?</h2> -
Wird zu:
<h2 id="was-ist-css">Was ist CSS?</h2> -
Sidebar-Link:
<a href="#was-ist-css">Was ist CSS?</a>
Beispiel mit Custom Title:
-
Überschrift:
<h2 id="die-top-15-tags">HTML Cheat Sheet - Die Top 15 Tags</h2> -
Custom Title in TOC_CUSTOM_TITLES:
'die-top-15-tags': 'Top 15 Tags' -
Sidebar-Link:
<a href="#die-top-15-tags">Top 15 Tags</a>(gekürzt!)
Lange Überschriften können in der Sidebar zu breit werden. Mit TOC_CUSTOM_TITLES kannst du kurze, prägnante Titel für die Sidebar definieren, während die Original-Überschrift im Haupttext erhalten bleibt:
const TOC_CUSTOM_TITLES = {
'html-basics.html': {
'die-top-15-tags': 'Top 15 Tags',
'html-attribute-erklaert': 'HTML Attribute'
},
'css-farben.html': {
'rgb-rgba-hex': 'Farbformate'
}
};
Wichtig:
Die ID muss die
finale ID
sein (nach Slug-Generierung), also z.B.
'die-top-15-tags'
nicht
'die-Top-15-Tags'
.
IDs wie
#für-anfänger
können in URLs Probleme machen. Besser:
#fuer-anfaenger
generateSidebarNavList() – Gruppierte Tutorial-Liste
Die rechte Sidebar zeigt alle Tutorials der Hauptkategorie , gruppiert nach Unterkategorien:
function generateSidebarNavList(filePath) {
const category = getCategoryFromPath(filePath);
const currentUrl = getRelativeUrl(filePath);
const allTutorials = getAllTutorialsForCategory(category);
let html = '';
Object.keys(allTutorials).forEach(subcategoryKey => {
const group = allTutorials[subcategoryKey];
// Gruppen-Überschrift
html += `<li class="sidebar-group-title">${group.displayName}</li>\n`;
// Tutorials dieser Gruppe
group.tutorials.forEach(tutorial => {
const isActive = tutorial.url === currentUrl;
const activeClass = isActive ? ' class="active"' : '';
html += `<li><a href="${tutorial.url}"${activeClass}>${tutorial.title}</a></li>\n`;
});
});
return html.trim();
}
Ergebnis in der Sidebar:
<li class="sidebar-group-title">HTML Basics</li>
<li><a href="/tutorials/html/html-basics/html-basics.html">HTML Basics</a></li>
<li><a href="/tutorials/html/html-basics/html-grundgeruest.html">HTML Grundgerüst</a></li>
<li class="sidebar-group-title">HTML Advanced</li>
<li><a href="/tutorials/html/html-advanced/html-semantik.html" class="active">HTML Semantik</a></li>
<li><a href="/tutorials/html/html-advanced/html-formulare.html">HTML Formulare</a></li>
-
.sidebar-group-title– Visuelle Gruppierung nach Unterkategorie - Zeigt alle Tutorials der Hauptkategorie (nicht nur aktuelle Unterkategorie)
- Bessere Übersicht beim Navigieren zwischen Unterkategorien
tutorials.json Generierung (NEU in v2.2)
Das Script generiert automatisch eine JSON-Datei mit allen Tutorial-Metadaten:
/assets/data/tutorials.json
extractHeroExcerpt() – Excerpt aus Hero ziehen
function extractHeroExcerpt(html) {
const dom = new JSDOM(html);
const document = dom.window.document;
// Versuche verschiedene Selektoren
const selectors = [
'.hero-subtitle',
'.hero-text',
'.hero p',
'.tutorial-hero p'
];
for (const selector of selectors) {
const element = document.querySelector(selector);
if (element) {
let text = element.textContent.trim();
// Kürze auf max 160 Zeichen
if (text.length > 160) {
text = text.substring(0, 157) + '...';
}
return text;
}
}
return null;
}
generateLatestTutorialsJSON() – JSON erstellen
Diese Funktion sammelt alle Tutorial-Metadaten und speichert sie als JSON:
{
"generated": "2025-01-06T12:00:00.000Z",
"total": 42,
"all": [...], // Alle Tutorials
"latest": [...], // Die 4 aus LATEST_TUTORIALS
"byCategory": { // Gruppiert
"html": [...],
"css": [...],
"javascript": [...]
}
}
Die JSON-Datei wird bei jedem
npm run generate
neu erstellt. Du musst sie nie manuell bearbeiten!
HTML aktualisieren
Die Hauptfunktion
updateHtmlFile()
koordiniert alle Updates:
function updateHtmlFile(filePath) {
// HTML-Datei einlesen
let html = fs.readFileSync(filePath, 'utf8');
// Metadaten sammeln
const category = getCategoryFromPath(filePath);
const basename = path.basename(filePath);
const currentTitle = CUSTOM_TITLES[basename] || extractTitle(html);
// WICHTIG: ZUERST IDs zu Headings hinzufügen (nur für Tutorial-Seiten)
let sidebarAnchorsHtml = '';
if (basename !== 'index.html') {
const result = addIdsToHeadingsAndGenerateSidebar(html, basename);
html = result.html; // Nutze das HTML mit IDs!
sidebarAnchorsHtml = result.anchors;
}
// 1. HEADER AKTUALISIEREN
html = updateHeader(html);
// 2. FOOTER AKTUALISIEREN
html = updateFooter(html);
// 3. TUTORIAL BUTTONS (nur bei Kategorieseiten!)
if (basename === 'index.html') {
html = updateTutorialButtons(html, category);
}
// 4. Main Navigation einfügen
const mainNavItems = generateMainNavigation();
html = html.replace(
/<!-- Main-Nav-Start -->.*?<!-- Main-Nav-End -->/s,
`<!-- Main-Nav-Start -->\n${mainNavItems.join('\n')}\n<!-- Main-Nav-End -->`
);
// 5. Breadcrumbs (nur für Tutorial-Seiten)
const relativePath = path.relative(path.join(__dirname, '..'), filePath);
const isInTutorials = relativePath.includes('tutorials');
if (isInTutorials) {
const breadcrumbs = generateBreadcrumbs(filePath, currentTitle);
html = html.replace(
/<nav class="breadcrumbs">.*?<\/nav>/s,
`<nav class="breadcrumbs">${breadcrumbs}</nav>`
);
}
// 6. Latest Tutorials Section (nur Tutorial-Seiten, nicht index.html)
if (basename !== 'index.html') {
const latestSection = generateLatestTutorialsSection(category);
// ... (ersetzt oder fügt "Mehr aus X" Section ein)
}
// 7. Prev/Next Navigation (nur Tutorial-Seiten)
if (basename !== 'index.html') {
const prevNext = generatePrevNextNav(filePath);
html = html.replace(
/<nav class="tutorial-nav">.*?<\/nav>/s,
`<nav class="tutorial-nav">${prevNext}</nav>`
);
}
// 8. Sidebar Anchors (TOC)
if (basename !== 'index.html') {
html = html.replace(
/<!-- Sidebar-Anchor-Start -->.*?<!-- Sidebar-Anchor-End -->/s,
`<!-- Sidebar-Anchor-Start -->\n${sidebarAnchorsHtml}\n<!-- Sidebar-Anchor-End -->`
);
}
// 9. Sidebar Navigation List
if (basename !== 'index.html') {
const navList = generateSidebarNavList(filePath);
html = html.replace(
/<ul class="sidebar-nav-list">.*?<\/ul>/s,
`<ul class="sidebar-nav-list">\n${navList}\n</ul>`
);
}
// 10. Datei speichern
fs.writeFileSync(filePath, html, 'utf8');
}
- Zuerst IDs zu Headings hinzufügen
- Dann Header/Footer ersetzen
- Danach alle Navigationen einfügen
- Zum Schluss Datei speichern
Die Sidebar-Links verweisen auf IDs
#meine-ueberschrift
. Diese IDs müssen also existieren, BEVOR die Sidebar generiert wird!
Regex Patterns erklärt
Das Script nutzt Regular Expressions (Regex) , um HTML zu finden und zu ersetzen. Das sieht kompliziert aus, ist aber logisch:
Pattern für Kommentar-Marker
/<!-- Main-Nav-Start -->.*?<!-- Main-Nav-End -->/s
Aufschlüsselung:
-
/→ Start des Regex -
<!-- Main-Nav-Start -->→ Findet den Start-Kommentar -
.*?→ Findet ALLES dazwischen (aber so wenig wie möglich) -
<!-- Main-Nav-End -->→ Findet den End-Kommentar -
/s→ "Dotall" Mode -.matched auch Zeilenumbrüche
Beispiel:
<!-- Main-Nav-Start -->
<li><a href="/tutorials/html/">HTML</a></li>
<li><a href="/tutorials/css/">CSS</a></li>
<!-- Main-Nav-End -->
Das Regex findet ALLES zwischen den Markern und ersetzt es mit neuem HTML!
Pattern für HTML-Tags
/<nav class="breadcrumbs">.*?<\/nav>/s
Aufschlüsselung:
-
<nav class="breadcrumbs">→ Findet das öffnende Tag -
.*?→ Findet den Inhalt -
<\/nav>→ Findet das schließende Tag (/muss escaped werden!) -
/s→ Dotall Mode
Die Hauptlogik
Ganz am Ende des Scripts steht die Funktion, die alles startet:
function generateAllNavigation() {
console.log('🚀 Starte Navigation-Generierung...\n');
// 1. Alle HTML-Dateien finden
const tutorialFiles = findHtmlFiles(tutorialsDir);
console.log(`📄 Gefundene Tutorial-Dateien: ${tutorialFiles.length}\n`);
// 2. Jede Datei aktualisieren
tutorialFiles.forEach(filePath => {
const relativePath = path.relative(tutorialsDir, filePath);
console.log(` ✓ Aktualisiere: ${relativePath}`);
updateHtmlFile(filePath);
});
console.log('\n✅ Navigation erfolgreich generiert!');
}
// Script ausführen!
generateAllNavigation();
Ablauf:
-
Finde alle HTML-Dateien im
/tutorialsOrdner -
Für jede gefundene Datei: Rufe
updateHtmlFile()auf - Zeige Fortschritt im Terminal
- Fertig!
Mit
npm run build
wird das Script ausgeführt und es aktualisiert ALLE Seiten automatisch! 🎉
Best Practices & Tipps
1. Immer vor dem Committen ausführen
Gewöhne dir an, vor jedem Git-Commit
npm run build
auszuführen. So sind alle Navigationen garantiert aktuell!
2. Teste nach Änderungen
Nach größeren Änderungen am Script:
-
Führe
npm run buildaus - Öffne mehrere Tutorial-Seiten
- Prüfe Prev/Next, Sidebar, Breadcrumbs
- Teste die Links!
3. Backup vor Script-Änderungen
Wenn du das Script änderst:
-
Erstelle eine Kopie:
generate-navigation-backup.js - Teste deine Änderungen auf einer Datei
- Erst dann auf allen Dateien ausführen
4. Console-Logs nutzen
Füge bei Problemen Console-Logs hinzu:
console.log('Aktuelle Kategorie:', category);
console.log('Gefundene Tutorials:', tutorials);
console.log('Current Index:', currentIndex);
Häufige Probleme
Problem: Script findet keine Dateien
Ursache:
- Blacklist oder Pfad falsch
Lösung:
-
Prüfe
BLACKLIST_FOLDERS -
Prüfe ob Script in
/scripts/liegt -
Teste:
console.log(tutorialsDir)
Problem: Prev/Next zeigt falsches Tutorial
Ursache:
-
Reihenfolge in
TUTORIAL_ORDERfalsch
Lösung:
-
Öffne
generate-navigation.js - Finde die richtige Unterkategorie
- Korrigiere die Reihenfolge
-
Führe
npm run buildaus
Problem: Sidebar-Links führen nirgends hin
Ursache:
- IDs wurden nicht zu Headings hinzugefügt
Lösung:
-
Prüfe ob
addIdsToHeadingsAndGenerateSidebarausgeführt wird -
Prüfe ob
html = result.htmlverwendet wird -
Führe
npm run buildnochmal aus
Problem: Dropdown fehlt eine Kategorie
Ursache:
-
Keine Tutorials in
TUTORIAL_ORDERfür diese Kategorie
Lösung:
-
Füge Tutorials zu
TUTORIAL_ORDERhinzu -
Oder: Entferne die Kategorie aus
CATEGORY_NAMES
Zusammenfassung
Das
generate-navigation.js
Script ist ein mächtiges Werkzeug, das dir viel manuelle Arbeit abnimmt:
Was es macht:
- Findet alle HTML-Dateien
- Erstellt Header & Footer
- Generiert alle Navigationen
- Fügt IDs zu Überschriften hinzu
- Aktualisiert alle Seiten
Was du tun musst:
-
Neue Tutorials in
TUTORIAL_ORDEReintragen -
Optional: Custom-Titel in
CUSTOM_TITLES -
npm run buildausführen - Fertig!
Mehr aus DevPanicZone!
Tutorials werden geladen...