Tutorial Buttons
Die generierten Buttons auf den Kategorieseiten im Detail.
Tutorial-Listen (Kategorieseiten)
Auf Kategorieseiten (z.B. /tutorials/html/index.html) werden
automatisch alle
Tutorials dieser Kategorie als Button-Grid angezeigt. Die Liste wird aus manualOrder generiert.
HTML-Struktur auf Kategorieseiten
Füge diesen Container auf deiner Kategorieseite ein (z.B.
/tutorials/css/index.html):
<section class="tutorials-content">
<h2>Alle CSS Tutorials</h2>
<!-- Tutorial-Listen Container -->
<div id="tutorialButtons" class="tutorial-buttons" data-category="css">
<!-- Wird automatisch gefüllt -->
</div>
</section>
Das data-category Attribut muss mit dem
Ordnernamen übereinstimmen!
data-category="html"→ Zeigt alle HTML-Tutorialsdata-category="css"→ Zeigt alle CSS-Tutorials
data-category="javascript"→ Zeigt alle JavaScript-Tutorialsdata-category="php"→ Zeigt alle PHP-Tutorials
Wie funktioniert's?
Das Script durchsucht manualOrder nach allen Einträgen, die zur
Kategorie gehören:
// Beispiel: data-category="css"
// Das Script findet automatisch alle Ordner, die "css" enthalten:
const manualOrder = {
'tutorials/css/css-basics': [
'css-einbinden.html',
'css-color-units.html',
'css-variables.html'
],
'tutorials/css/css-advanced': [
'css-positioning.html',
'css-z-index.html'
]
};
// Ergebnis: Zwei Gruppen mit Buttons werden erstellt
Beispiel: Generierte Button-Liste
Aus dem leeren Container wird eine gruppierte Button-Liste:
<div id="tutorialButtons" class="tutorial-buttons" data-category="css">
<!-- Gruppe 1: CSS Basics -->
<div class="tutorial-group">
<h3 class="tutorial-group-title">CSS Basics</h3>
<div class="tutorial-group-buttons">
<a href="/tutorials/css/css-basics/css-einbinden.html" class="tutorial-button">CSS einbinden</a>
<a href="/tutorials/css/css-basics/css-color-units.html" class="tutorial-button">CSS Color Units</a>
<a href="/tutorials/css/css-basics/css-variables.html" class="tutorial-button">CSS Variables</a>
</div>
</div>
<!-- Gruppe 2: CSS Advanced -->
<div class="tutorial-group">
<h3 class="tutorial-group-title">CSS Advanced</h3>
<div class="tutorial-group-buttons">
<a href="/tutorials/css/css-advanced/css-positioning.html" class="tutorial-button">CSS Positioning</a>
<a href="/tutorials/css/css-advanced/css-z-index.html" class="tutorial-button">Z-Index</a>
</div>
</div>
</div>
Reihenfolge der Gruppen und Buttons
Die Reihenfolge wird aus manualOrder übernommen:
- Gruppen-Reihenfolge: Wie sie in
manualOrderstehen - Button-Reihenfolge: Wie die Dateien im Array sortiert sind
- Button-Titel: Aus
customTitles(falls vorhanden) oder automatisch formatiert
Neues Tutorial zur Liste hinzufügen
- Erstelle das neue Tutorial (z.B.
css-grid.html) - Öffne
generate-navigation.js - Füge die Datei in
manualOrderan der gewünschten Position ein:
'tutorials/css/css-basics': [
'css-einbinden.html',
'css-color-units.html',
'css-variables.html',
'css-grid.html', // <-- Neues Tutorial hier einfügen
'css-typografie.html'
]
- Optional: Custom Title in
customTitleshinzufügen:
const customTitles = {
'tutorials/css/css-basics/css-grid.html': 'CSS Grid Layout',
// ...
};
- Führe
npm run generateaus - Das neue Tutorial erscheint automatisch in der Button-Liste auf
/tutorials/css/index.html
Neue Tutorial-Gruppe hinzufügen
Um eine komplett neue Untergruppe zu erstellen (z.B. "CSS Specials"):
- Erstelle den Ordner:
/tutorials/css/css-specials/ - Erstelle Tutorials in diesem Ordner
- Füge die Gruppe in
manualOrderhinzu:
const manualOrder = {
'tutorials/css/css-basics': [
'css-einbinden.html',
// ...
],
'tutorials/css/css-advanced': [
'css-positioning.html',
// ...
],
'tutorials/css/css-specials': [ // <-- Neue Gruppe
'css-custom-fonts.html',
'css-animations.html'
]
};
- Führe
npm run generateaus - Die neue Gruppe erscheint automatisch auf der Kategorieseite
Gruppentitel anpassen
Gruppentitel werden automatisch aus dem Verzeichnisnamen generiert:
css-basics→ CSS Basicscss-advanced→ CSS Advancedjavascript-projects→ JavaScript Projects
Die Funktion fileNameToTitle() wandelt Bindestriche in Leerzeichen um
und macht jeden Wortanfang groß.
Vollständiger JavaScript-Code
// ============================================================================
// TUTORIAL-LISTEN (für Kategorieseiten)
// ============================================================================
/**
* Sammelt alle Tutorials einer Kategorie, gruppiert nach Unterordnern
*/
function getTutorialsByCategory(category) {
const tutorials = {};
// Durchsuche manualOrder nach der Kategorie
for (const [folder, files] of Object.entries(manualOrder)) {
if (folder.includes(category)) {
const subFolder = folder.split('/').pop(); // z.B. "html-basics"
tutorials[subFolder] = files.map(file => {
const fullPath = `${folder}/${file}`;
return {
title: customTitles[fullPath] || fileNameToTitle(file),
url: fullPath,
fileName: file
};
});
}
}
return tutorials;
}
/**
* Generiert HTML für Tutorial-Buttons
*/
function generateTutorialButtonsHTML(tutorials, currentFile) {
let html = '';
// Sortiere die Gruppen nach der Reihenfolge in manualOrder (nicht alphabetisch!)
const groupOrder = Object.keys(manualOrder)
.filter(folder => Object.keys(tutorials).some(group => folder.endsWith(group)))
.map(folder => folder.split('/').pop());
const sortedGroups = Object.keys(tutorials).sort((a, b) => {
const indexA = groupOrder.indexOf(a);
const indexB = groupOrder.indexOf(b);
return indexA - indexB;
});
sortedGroups.forEach(group => {
// Gruppe-Überschrift
const groupTitle = fileNameToTitle(group);
html += `\n <div class="tutorial-group">\n`;
html += ` <h3 class="tutorial-group-title">${groupTitle}</h3>\n`;
html += ` <div class="tutorial-group-buttons">\n`;
// Buttons für diese Gruppe
tutorials[group].forEach(tutorial => {
// Verwende absolute Pfade ab Root (statt relative)
const absolutePath = '/' + tutorial.url;
html += ` <a href="${absolutePath}" class="tutorial-button">${tutorial.title}</a>\n`;
});
html += ` </div>\n`;
html += ` </div>`;
});
return html;
}
/**
* Aktualisiert Tutorial-Listen auf Kategorieseiten
*/
function updateTutorialLists(files) {
let updatedCount = 0;
files.forEach(file => {
const filePath = path.join(BASE_DIR, file);
let content = fs.readFileSync(filePath, 'utf8');
// Suche nach dem öffnenden Tag mit data-category
const startTagRegex = /<div\s+id=["']tutorialButtons["']\s+class=["']tutorial-buttons["']\s+data-category=["']([^"']+)["'][^>]*>/;
const startMatch = content.match(startTagRegex);
if (startMatch) {
const category = startMatch[1]; // z.B. "html", "css", etc.
const tutorials = getTutorialsByCategory(category);
if (Object.keys(tutorials).length > 0) {
const buttonsHTML = generateTutorialButtonsHTML(tutorials, file);
// Finde die Position des öffnenden und schließenden Tags
const startIndex = content.indexOf(startMatch[0]) + startMatch[0].length;
const endTag = '</div>';
// Finde das passende schließende div (zähle opening/closing tags)
let depth = 1;
let endIndex = startIndex;
while (depth > 0 && endIndex < content.length) {
const nextOpen = content.indexOf('<div', endIndex);
const nextClose = content.indexOf('</div>', endIndex);
if (nextClose === -1) break;
if (nextOpen !== -1 && nextOpen < nextClose) {
depth++;
endIndex = nextOpen + 4;
} else {
depth--;
if (depth === 0) {
endIndex = nextClose;
} else {
endIndex = nextClose + 6;
}
}
}
// Ersetze nur den Inhalt zwischen den Tags
const before = content.substring(0, startIndex);
const after = content.substring(endIndex);
content = before + buttonsHTML + '\n ' + after;
fs.writeFileSync(filePath, content, 'utf8');
updatedCount++;
}
}
});
console.log(`✅ Tutorial-Listen aktualisiert in ${updatedCount} Dateien`);
}
Ausführen
Nach allen Änderungen ausführen:
npm run generate
Mehr aus DevPanicZone!
Tutorials werden geladen...