resume/docker/resume/update-stories-page.js

185 lines
5.5 KiB
JavaScript
Executable File

#!/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>([^<]+)<\/loc>/g) || [];
for (const match of matches) {
const url = match.replace('<loc>', '').replace('</loc>', '');
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[^>]*>(.*?)<\/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[^>]*>.*?<\/h1>\s*<p[^>]*>(.*?)<\/p>/is);
if (excerptMatch && excerptMatch[1]) {
metadata.excerpt = excerptMatch[1].trim().substring(0, 150) + '...';
}
// Try to extract category and date
const categoryMatch = content.match(/<strong>Category:<\/strong>\s*(.*?)(?:<|$)/i);
if (categoryMatch && categoryMatch[1]) {
metadata.category = categoryMatch[1].trim();
}
const dateMatch = content.match(/<strong>(?: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 = '<div class="stories-grid">\n';
for (const card of storyCards) {
storiesGridHtml += `
<div class="story-card">
<h2>${card.title}</h2>
<p class="story-excerpt">${card.excerpt}</p>
<p class="story-meta">Category: ${card.category} | Date: ${card.date}</p>
<a href="${card.filename}" class="story-link">Read Full Story</a>
</div>
`;
}
storiesGridHtml += ' </div>';
// Replace the stories grid in the index.html
const updatedContent = storiesIndexContent.replace(
/<div class="stories-grid">[\s\S]*?<\/div>\s*<hr>/,
`${storiesGridHtml}\n\n <hr>`
);
// 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();