--- import Base from '../../layouts/Base.astro'; import fs from 'node:fs'; import path from 'node:path'; export function getStaticPaths() { const dataDir = path.join(process.cwd(), 'src/data/comics'); if (!fs.existsSync(dataDir)) return []; const files = fs.readdirSync(dataDir).filter(f => f.endsWith('.html') && !f.includes('?')); return files.map(file => { const slug = file.replace('.html', ''); return { params: { slug }, props: { filePath: path.join(dataDir, file) } }; }); } const { filePath } = Astro.props; const { slug } = Astro.params; const html = fs.readFileSync(filePath, 'utf-8'); // Extract title const titleMatch = html.match(/([^<]+)<\/title>/i); const title = titleMatch ? titleMatch[1].replace(/'/g, "'").replace(/&/g, '&') : `Comic #${slug}`; // Extract comic image URL const imgMatch = html.match(/src="(http:\/\/assets\.componentowl\.com\/comics\/[^"?]+)/); const comicImg = imgMatch ? imgMatch[1] : ''; // Extract comic name from title (after "Comics: ") const nameMatch = title.match(/Comics:\s*(.+)/); const comicName = nameMatch ? nameMatch[1] : `Comic #${slug}`; // Extract navigation links const prevMatch = html.match(/class="comics-prev"[^>]*>/); const prevHref = html.match(/href="(\d+)\.html"[^>]*class="comics-prev"/); const nextHref = html.match(/href="(\d+)\.html"[^>]*class="comics-next"/); // Also try reverse order const prevHref2 = html.match(/class="comics-prev"[^>]*href="(\d+)/); const nextHref2 = html.match(/class="comics-next"[^>]*href="(\d+)/); // And link before class const prevLink = html.match(/<a\s+href="(\d+)\.html"\s+class="comics-prev"/); const nextLink = html.match(/<a\s+href="(\d+)\.html"\s+class="comics-next"/); const prev = prevHref?.[1] || prevHref2?.[1] || prevLink?.[1] || null; const next = nextHref?.[1] || nextHref2?.[1] || nextLink?.[1] || null; // Extract date const dateMatch = html.match(/comics-day[^>]*>\s*([^<]+)/); const comicDate = dateMatch ? dateMatch[1].trim() : ''; // Extract description/bubble text const bubbleMatch = html.match(/comics-bubble[^>]*>.*?<p>([^<]+)/s); const bubble = bubbleMatch ? bubbleMatch[1].trim() : ''; const num = parseInt(slug); --- <Base title={title} description="Component Owl's web comics for developers"> <div class="comics-wrap" style="text-align: center; padding: 20px 0;"> <h1 style="font-size: 24px; margin-bottom: 10px;">#{num}: {comicName}</h1> {comicDate && <p style="color: #a38952; font-size: 12px; margin-bottom: 15px;">{comicDate}</p>} <div class="comics-navigation" style="margin: 15px auto; overflow: hidden; max-width: 400px;"> {prev && <a href={`/comics/${prev}`} style="float: left; padding: 5px 15px; background: #3a2c18; color: #fff; text-decoration: none; border-radius: 4px;">« Previous</a>} <a href="/comics" style="padding: 5px 15px; background: #825900; color: #fff; text-decoration: none; border-radius: 4px;">All Comics</a> {next && <a href={`/comics/${next}`} style="float: right; padding: 5px 15px; background: #3a2c18; color: #fff; text-decoration: none; border-radius: 4px;">Next »</a>} </div> {comicImg && <div class="comics" style="margin: 20px auto;"> <img src={comicImg} alt={comicName} style="max-width: 100%; height: auto; border: 2px solid #1a1a1a; border-radius: 8px;" /> </div>} {bubble && <p style="font-size: 16px; font-style: italic; margin: 20px auto; max-width: 700px;">{bubble}</p>} <div class="comics-navigation" style="margin: 20px auto; overflow: hidden; max-width: 400px;"> {prev && <a href={`/comics/${prev}`} style="float: left; padding: 5px 15px; background: #3a2c18; color: #fff; text-decoration: none; border-radius: 4px;">« Previous</a>} <a href="/comics" style="padding: 5px 15px; background: #825900; color: #fff; text-decoration: none; border-radius: 4px;">All Comics</a> {next && <a href={`/comics/${next}`} style="float: right; padding: 5px 15px; background: #3a2c18; color: #fff; text-decoration: none; border-radius: 4px;">Next »</a>} </div> </div> </Base>