Split pages into one HTML file per episode
Assisted-by: Claude Opus 4.6 via pi
change qqokuyvytuuumwztzuoxyqlnzstspnqo
commit 962a265372bd0c23b11c8dd3d646e5d14013c533
author Alpha Chen <alpha@kejadlen.dev>
date
parent xmlysmww
diff --git a/.gitignore b/.gitignore
index b319076..34bcc24 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
 /cache/
 /sous_chef/.build/
-/site
+/pages
diff --git a/Rakefile b/Rakefile
index 0dfac96..374be99 100644
--- a/Rakefile
+++ b/Rakefile
@@ -125,11 +125,15 @@ end
 
 PAGES_DIR = Pathname("pages")
 
-desc "Generate an HTML page of transcripts"
+desc "Generate HTML transcript pages"
 task :pages do
   require "cgi"
   require "erb"
 
+  templates_dir = File.expand_path("lib/pages", __dir__)
+  index_template = ERB.new(File.read("#{templates_dir}/index.html.erb"))
+  episode_template = ERB.new(File.read("#{templates_dir}/episode.html.erb"))
+
   transcripts = EPISODE_TASKS
     .select { |et| Pathname(et.text_path).exist? }
     .map do |et|
@@ -141,10 +145,15 @@ task :pages do
       }
     end
 
-  template = File.read(File.expand_path("lib/pages.html.erb", __dir__))
-  html = ERB.new(template).result(binding)
-
   PAGES_DIR.mkpath
+
+  transcripts.each do |ep|
+    html = episode_template.result(binding)
+    (PAGES_DIR / "#{ep[:slug]}.html").write(html)
+  end
+
+  html = index_template.result(binding)
   (PAGES_DIR / "index.html").write(html)
-  puts "Generated pages/index.html with #{transcripts.length} episodes."
+
+  puts "Generated #{transcripts.length} episode pages + index."
 end
diff --git a/lib/pages.html.erb b/lib/pages.html.erb
deleted file mode 100644
index 3e336ac..0000000
--- a/lib/pages.html.erb
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Cooking Issues Transcripts</title>
-<style>
-  * { box-sizing: border-box; margin: 0; padding: 0; }
-  body { font-family: system-ui, sans-serif; line-height: 1.6; color: #222; max-width: 50rem; margin: 0 auto; padding: 1rem; }
-  h1 { margin-bottom: 1rem; }
-  .episode { margin: 1.5rem 0; }
-  .episode-header { cursor: pointer; padding: 0.5rem 0; border-bottom: 1px solid #eee; }
-  .episode-header h2 { font-size: 1.1rem; }
-  .episode-header:hover h2 { color: #0066cc; }
-  .episode-body { display: none; padding: 1rem 0; }
-  .episode-body.open { display: block; }
-  .episode-body p { margin-bottom: 1em; }
-  .timestamp { color: #888; font-size: 0.85rem; font-family: monospace; }
-</style>
-</head>
-<body>
-
-<h1>Cooking Issues Transcripts</h1>
-
-<div id="episodes">
-<% transcripts.each do |ep| %>
-  <div class="episode">
-    <div class="episode-header" onclick="toggle(this)">
-      <h2><%= CGI.escapeHTML("#{ep[:number]}. #{ep[:title]}") %></h2>
-    </div>
-    <div class="episode-body">
-      <% ep[:text].split("\n\n").each do |para| %>
-        <% if para =~ /\A\[([^\]]+)\]\s*(.*)/ %>
-          <p><span class="timestamp">[<%= CGI.escapeHTML($1) %>]</span> <%= CGI.escapeHTML($2) %></p>
-        <% else %>
-          <p><%= CGI.escapeHTML(para) %></p>
-        <% end %>
-      <% end %>
-    </div>
-  </div>
-<% end %>
-</div>
-
-<script>
-function toggle(header) {
-  header.nextElementSibling.classList.toggle('open');
-}
-</script>
-
-</body>
-</html>
diff --git a/lib/pages/episode.html.erb b/lib/pages/episode.html.erb
new file mode 100644
index 0000000..6eb5710
--- /dev/null
+++ b/lib/pages/episode.html.erb
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title><%= CGI.escapeHTML("#{ep[:number]}. #{ep[:title]}") %> — Cooking Issues</title>
+<style>
+  * { box-sizing: border-box; margin: 0; padding: 0; }
+  body { font-family: system-ui, sans-serif; line-height: 1.6; color: #222; max-width: 50rem; margin: 0 auto; padding: 1rem; }
+  h1 { font-size: 1.3rem; margin-bottom: 0.5rem; }
+  .back { display: inline-block; margin-bottom: 1rem; color: #0066cc; text-decoration: none; }
+  .back:hover { text-decoration: underline; }
+  p { margin-bottom: 1em; }
+  .timestamp { color: #888; font-size: 0.85rem; font-family: monospace; }
+</style>
+</head>
+<body>
+
+<a class="back" href="index.html">← All episodes</a>
+<h1><%= CGI.escapeHTML("#{ep[:number]}. #{ep[:title]}") %></h1>
+
+<% ep[:text].split("\n\n").each do |para| %>
+  <% if para =~ /\A\[([^\]]+)\]\s*(.*)/ %>
+    <p><span class="timestamp">[<%= CGI.escapeHTML($1) %>]</span> <%= CGI.escapeHTML($2) %></p>
+  <% else %>
+    <p><%= CGI.escapeHTML(para) %></p>
+  <% end %>
+<% end %>
+
+</body>
+</html>
diff --git a/lib/pages/index.html.erb b/lib/pages/index.html.erb
new file mode 100644
index 0000000..bc0f578
--- /dev/null
+++ b/lib/pages/index.html.erb
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Cooking Issues Transcripts</title>
+<style>
+  * { box-sizing: border-box; margin: 0; padding: 0; }
+  body { font-family: system-ui, sans-serif; line-height: 1.6; color: #222; max-width: 50rem; margin: 0 auto; padding: 1rem; }
+  h1 { margin-bottom: 1rem; }
+  ul { list-style: none; }
+  li { padding: 0.4rem 0; border-bottom: 1px solid #eee; }
+  a { color: #0066cc; text-decoration: none; }
+  a:hover { text-decoration: underline; }
+</style>
+</head>
+<body>
+
+<h1>Cooking Issues Transcripts</h1>
+<p><%= transcripts.length %> episodes</p>
+
+<ul>
+<% transcripts.each do |ep| %>
+  <li><a href="<%= ep[:slug] %>.html"><%= CGI.escapeHTML("#{ep[:number]}. #{ep[:title]}") %></a></li>
+<% end %>
+</ul>
+
+</body>
+</html>