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):

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>
Wichtig

Das data-category Attribut muss mit dem Ordnernamen übereinstimmen!

  • data-category="html" → Zeigt alle HTML-Tutorials
  • data-category="css" → Zeigt alle CSS-Tutorials
  • data-category="javascript" → Zeigt alle JavaScript-Tutorials
  • data-category="php" → Zeigt alle PHP-Tutorials

Wie funktioniert's?

Das Script durchsucht manualOrder nach allen Einträgen, die zur Kategorie gehören:

JavaScript
// 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:

HTML
<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 manualOrder stehen
  • Button-Reihenfolge: Wie die Dateien im Array sortiert sind
  • Button-Titel: Aus customTitles (falls vorhanden) oder automatisch formatiert

Neues Tutorial zur Liste hinzufügen

  1. Erstelle das neue Tutorial (z.B. css-grid.html)
  2. Öffne generate-navigation.js
  3. Füge die Datei in manualOrder an der gewünschten Position ein:
JavaScript
'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'
]
  1. Optional: Custom Title in customTitles hinzufügen:
JavaScript
const customTitles = {
    'tutorials/css/css-basics/css-grid.html': 'CSS Grid Layout',
    // ...
};
  1. Führe npm run generate aus
  2. 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"):

  1. Erstelle den Ordner: /tutorials/css/css-specials/
  2. Erstelle Tutorials in diesem Ordner
  3. Füge die Gruppe in manualOrder hinzu:
JavaScript
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'
    ]
};
  1. Führe npm run generate aus
  2. Die neue Gruppe erscheint automatisch auf der Kategorieseite

Gruppentitel anpassen

Gruppentitel werden automatisch aus dem Verzeichnisnamen generiert:

  • css-basicsCSS Basics
  • css-advancedCSS Advanced
  • javascript-projectsJavaScript Projects

Die Funktion fileNameToTitle() wandelt Bindestriche in Leerzeichen um und macht jeden Wortanfang groß.

Vollständiger JavaScript-Code
JavaScript
// ============================================================================
// 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:

Plain Text
npm run generate

Mehr aus DevPanicZone!

Tutorials werden geladen...