185 lines
5.5 KiB
JavaScript
Executable File
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();
|