#!/usr/bin/env node /** * update-stories-page.js * * This script reads the sitemap.xml file and updates the stories/index.html page * 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 STORIES_INDEX_PATH = path.join(__dirname, 'stories', 'index.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', ''); // Split by hyphens and capitalize each word name = name.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1) ).join(' '); return name; } // Simple XML parser for sitemap (no external dependencies) function extractUrlsFromSitemap(sitemapContent) { const urls = []; const matches = sitemapContent.match(/([^<]+)<\/loc>/g) || []; for (const match of matches) { const url = match.replace('', '').replace('', ''); urls.push(url); } return urls; } // Helper function to extract metadata from a story file async function extractStoryMetadata(storyPath) { try { const content = fs.readFileSync(storyPath, 'utf8'); // Default metadata let metadata = { title: getFriendlyName(path.basename(storyPath)), excerpt: 'Detailed case study and project information.', category: 'Project', date: 'Recent' }; // Try to extract title from h1 const h1Match = content.match(/]*>(.*?)<\/h1>/i); if (h1Match && h1Match[1]) { metadata.title = h1Match[1].trim(); } // Try to extract excerpt from first paragraph after h1 const excerptMatch = content.match(/]*>.*?<\/h1>\s*]*>(.*?)<\/p>/is); if (excerptMatch && excerptMatch[1]) { metadata.excerpt = excerptMatch[1].trim().substring(0, 150) + '...'; } // Try to extract category and date const categoryMatch = content.match(/Category:<\/strong>\s*(.*?)(?:<|$)/i); if (categoryMatch && categoryMatch[1]) { metadata.category = categoryMatch[1].trim(); } const dateMatch = content.match(/(?:Date|Timeframe):<\/strong>\s*(.*?)(?:<|$)/i); if (dateMatch && dateMatch[1]) { metadata.date = dateMatch[1].trim(); } return metadata; } catch (error) { console.error(`Error extracting metadata from ${storyPath}:`, error); return { title: getFriendlyName(path.basename(storyPath)), excerpt: 'Detailed case study and project information.', category: 'Project', date: 'Recent' }; } } // Main function async function updateStoriesPage() { try { console.log('Updating stories page from sitemap.xml...'); // Check if sitemap.xml exists if (!fs.existsSync(SITEMAP_PATH)) { console.error('Sitemap.xml not found at:', SITEMAP_PATH); return; } // Check if stories/index.html exists if (!fs.existsSync(STORIES_INDEX_PATH)) { console.error('Stories index page not found at:', STORIES_INDEX_PATH); return; } // Read sitemap.xml const sitemapContent = fs.readFileSync(SITEMAP_PATH, 'utf8'); const allUrls = extractUrlsFromSitemap(sitemapContent); // Find all story URLs in sitemap const storyUrls = []; for (const url of allUrls) { if (url.includes(STORIES_PATH_PREFIX)) { const filename = url.split('/').pop(); if (!STORIES_PATH_EXCLUDE.includes(filename)) { storyUrls.push({ url: url, filename: filename }); } } } console.log(`Found ${storyUrls.length} story pages in sitemap.`); // Read stories/index.html const storiesIndexContent = fs.readFileSync(STORIES_INDEX_PATH, 'utf8'); // Extract metadata for each story const storyCards = []; for (const storyUrl of storyUrls) { const storyPath = path.join(__dirname, 'stories', storyUrl.filename); if (fs.existsSync(storyPath)) { const metadata = await extractStoryMetadata(storyPath); storyCards.push({ filename: storyUrl.filename, title: metadata.title, excerpt: metadata.excerpt, category: metadata.category, date: metadata.date }); } } // Generate HTML for story cards let storiesGridHtml = '
\n'; for (const card of storyCards) { storiesGridHtml += `

${card.title}

${card.excerpt}

Read Full Story
`; } storiesGridHtml += '
'; // Replace the stories grid in the index.html const updatedContent = storiesIndexContent.replace( /
[\s\S]*?<\/div>\s*
/, `${storiesGridHtml}\n\n
` ); // Write the updated content back to the file fs.writeFileSync(STORIES_INDEX_PATH, updatedContent, 'utf8'); console.log(`Updated stories page with ${storyCards.length} story cards.`); } catch (error) { console.error('Error updating stories page:', error); } } // Run the main function updateStoriesPage();