resume/docker/resume/update-nav-from-sitemap.js

152 lines
5.0 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* update-nav-from-sitemap.js
*
* This script reads the sitemap.xml file and updates the navigation menu in header.html
* to include all story pages found in the sitemap.
*
* No external dependencies required.
*/
const fs = require('fs');
const path = require('path');
// Configuration
const SITEMAP_PATH = path.join(__dirname, 'sitemap.xml');
const HEADER_PATH = path.join(__dirname, 'includes', 'header.html');
const STORIES_PATH_PREFIX = '/stories/';
const STORIES_PATH_EXCLUDE = ['index.html', 'story-with-includes.html', 'template-story.html'];
// Helper function to get a friendly name from a filename
function getFriendlyName(filename) {
// Remove .html extension
let name = filename.replace('.html', '');
// Replace hyphens with spaces
name = name.replace(/-/g, ' ');
// Capitalize first letter of each word
return name.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
}
// Simple XML parser for sitemap (no external dependencies)
function extractUrlsFromSitemap(sitemapContent) {
const urls = [];
const matches = sitemapContent.match(/<loc>([^<]+)<\/loc>/g) || [];
for (const match of matches) {
const url = match.replace('<loc>', '').replace('</loc>', '');
urls.push(url);
}
return urls;
}
// Main function
async function updateNavFromSitemap() {
console.log('Updating navigation menu from sitemap.xml...');
try {
// Read sitemap.xml
const sitemapContent = fs.readFileSync(SITEMAP_PATH, 'utf8');
const urls = extractUrlsFromSitemap(sitemapContent);
// Extract story URLs from sitemap
const storyPages = [];
for (const url of urls) {
// Check if this is a story page
if (url.includes(STORIES_PATH_PREFIX)) {
const filename = url.split('/').pop();
// Skip excluded files
if (!STORIES_PATH_EXCLUDE.includes(filename)) {
const filePath = path.join(__dirname, 'stories', filename);
let isWritten = true;
try {
if (fs.existsSync(filePath)) {
const content = fs.readFileSync(filePath, 'utf8');
// Check if the file contains the placeholder notice
if (content.includes('class="placeholder-notice"') || content.includes("class='placeholder-notice'")) {
isWritten = false;
}
} else {
console.warn(`Warning: File not found: ${filePath}`);
}
} catch (err) {
console.warn(`Error reading file ${filePath}: ${err.message}`);
}
storyPages.push({
filename,
url: STORIES_PATH_PREFIX + filename,
name: getFriendlyName(filename),
isWritten
});
}
}
}
// Sort story pages alphabetically by name
storyPages.sort((a, b) => a.name.localeCompare(b.name));
// Read header.html
let headerContent = fs.readFileSync(HEADER_PATH, 'utf8');
// Find the stories dropdown content
const dropdownStartMarker = '<a href="/stories/" id="nav-stories">Stories</a>';
const dropdownEndMarker = '</div>';
const dropdownStartIndex = headerContent.indexOf(dropdownStartMarker);
if (dropdownStartIndex === -1) {
throw new Error('Could not find stories dropdown in header.html');
}
// Find the start of the dropdown content
const contentStartIndex = headerContent.indexOf('<div class="dropdown-content">', dropdownStartIndex);
if (contentStartIndex === -1) {
throw new Error('Could not find dropdown content in header.html');
}
// Find the end of the dropdown content
const contentEndIndex = headerContent.indexOf(dropdownEndMarker, contentStartIndex);
if (contentEndIndex === -1) {
throw new Error('Could not find end of dropdown content in header.html');
}
// Generate new dropdown content
let newDropdownContent = '<div class="dropdown-content">\n';
storyPages.forEach(page => {
const navId = 'nav-' + page.filename.replace('.html', '').replace(/-/g, '');
const className = page.isWritten ? 'nav-story-written' : 'nav-story-tbd';
newDropdownContent += ` <a href="${page.url}" id="${navId}" class="${className}">${page.name}</a>\n`;
});
// Replace dropdown content in header.html
const newHeaderContent =
headerContent.substring(0, contentStartIndex) +
newDropdownContent +
' ' + dropdownEndMarker +
headerContent.substring(contentEndIndex + dropdownEndMarker.length);
// Write updated header.html
fs.writeFileSync(HEADER_PATH, newHeaderContent, 'utf8');
console.log(`Updated navigation menu with ${storyPages.length} story pages`);
return true;
} catch (error) {
console.error('Error updating navigation menu:', error);
return false;
}
}
// Execute if run directly
if (require.main === module) {
updateNavFromSitemap();
}
module.exports = { updateNavFromSitemap };