Share Utopia scales with snapshot viewer pages
Inline styles replaced with a shared snapshots.css that references
Utopia custom properties for spacing and type. Rake file tasks copy
reset.css, utopia.css, and snapshots.css alongside generated HTML.
Assisted-by: Claude Opus 4.6 via Claude Code
diff --git a/BACKLOG.md b/BACKLOG.md
index 934ddbd..8c040dc 100644
--- a/BACKLOG.md
+++ b/BACKLOG.md
@@ -17,3 +17,4 @@
- Shared tasks — visible to all users, anyone can mark done
- CLI interface
- Don't re-download baseline for snapshots unnecessarily
+- Dark mode
diff --git a/Rakefile b/Rakefile
index fe857cb..f0672a8 100644
--- a/Rakefile
+++ b/Rakefile
@@ -97,6 +97,23 @@ task :seed do
end
namespace :snapshots do
+ cache_dir = File.join(ENV.fetch("XDG_CACHE_HOME", File.expand_path("~/.cache")), "ketchup", "snapshots")
+ css_sources = {
+ "public/css/reset.css" => "reset.css",
+ "public/css/utopia.css" => "utopia.css",
+ "templates/snapshots.css" => "snapshots.css",
+ }
+
+ directory cache_dir
+
+ css_targets = css_sources.map do |src, basename|
+ target = File.join(cache_dir, basename)
+ file target => [cache_dir, src] do
+ cp src, target
+ end
+ target
+ end
+
desc "Capture screenshots of the app in key states"
task :capture do
ENV["DATABASE_URL"] = ":memory:"
@@ -112,7 +129,7 @@ namespace :snapshots do
end
desc "Compare current screenshots against baseline from latest release"
- task diff: :capture do
+ task diff: [:capture, *css_targets] do
require "erb"
base_dir = Ketchup::Snapshots.cache_dir
@@ -169,6 +186,9 @@ namespace :snapshots do
images_dir = args.fetch(:images_dir)
output_path = args.fetch(:output_path)
+ output_dir = File.dirname(output_path)
+
+ css_sources.each_key { |src| cp src, output_dir }
title = "Ketchup Snapshots"
images = Dir.glob(File.join(images_dir, "*.png")).sort.map do |f|
diff --git a/templates/snapshot_diff.erb b/templates/snapshot_diff.erb
index 2114ce4..7383a88 100644
--- a/templates/snapshot_diff.erb
+++ b/templates/snapshot_diff.erb
@@ -3,21 +3,9 @@
<head>
<meta charset="utf-8">
<title>Ketchup Snapshot Diff</title>
- <style>
- * { box-sizing: border-box; margin: 0; padding: 0; }
- body { background: #1a1a2e; color: #e0e0e0; font-family: system-ui, sans-serif; padding: 2rem; }
- h1 { margin-bottom: 2rem; color: #fff; }
- .snapshot { margin-bottom: 3rem; }
- .snapshot h2 { margin-bottom: 1rem; color: #ccc; }
- .label { font-size: 0.75rem; padding: 0.15rem 0.5rem; border-radius: 4px; vertical-align: middle; }
- .label.new { background: #2d6a4f; color: #b7e4c7; }
- .label.removed { background: #6a2d2d; color: #e4b7b7; }
- .pair { display: flex; gap: 1rem; }
- .side { flex: 1; min-width: 0; }
- .side h3 { margin-bottom: 0.5rem; color: #999; font-size: 0.875rem; text-transform: uppercase; }
- .side img { width: 100%; border: 1px solid #333; border-radius: 4px; }
- .placeholder { padding: 3rem; text-align: center; color: #666; border: 1px dashed #333; border-radius: 4px; }
- </style>
+ <link rel="stylesheet" href="reset.css">
+ <link rel="stylesheet" href="utopia.css">
+ <link rel="stylesheet" href="snapshots.css">
</head>
<body>
<h1>Ketchup Snapshot Diff</h1>
diff --git a/templates/snapshot_gallery.erb b/templates/snapshot_gallery.erb
index 9ddaf8c..0f56818 100644
--- a/templates/snapshot_gallery.erb
+++ b/templates/snapshot_gallery.erb
@@ -3,14 +3,9 @@
<head>
<meta charset="utf-8">
<title><%= title %></title>
- <style>
- * { box-sizing: border-box; margin: 0; padding: 0; }
- body { background: #1a1a2e; color: #e0e0e0; font-family: system-ui, sans-serif; padding: 2rem; }
- h1 { margin-bottom: 2rem; color: #fff; }
- .snapshot { margin-bottom: 3rem; }
- .snapshot h2 { margin-bottom: 1rem; color: #ccc; }
- .snapshot img { max-width: 100%; border: 1px solid #333; border-radius: 4px; }
- </style>
+ <link rel="stylesheet" href="reset.css">
+ <link rel="stylesheet" href="utopia.css">
+ <link rel="stylesheet" href="snapshots.css">
</head>
<body>
<h1><%= title %></h1>
diff --git a/templates/snapshots.css b/templates/snapshots.css
new file mode 100644
index 0000000..a21d230
--- /dev/null
+++ b/templates/snapshots.css
@@ -0,0 +1,26 @@
+body {
+ background: #1a1a2e;
+ color: #e0e0e0;
+ font-family: system-ui, sans-serif;
+ font-size: var(--step-0);
+ padding: var(--space-l);
+}
+
+h1 { margin-bottom: var(--space-l); color: #fff; }
+
+.snapshot { margin-bottom: var(--space-xl); }
+.snapshot h2 { margin-bottom: var(--space-s); color: #ccc; }
+.snapshot img { max-width: 100%; border: 1px solid #333; border-radius: 4px; }
+
+/* Diff-specific */
+
+.label { font-size: var(--step--2); padding: 0.15rem 0.5rem; border-radius: 4px; vertical-align: middle; }
+.label.new { background: #2d6a4f; color: #b7e4c7; }
+.label.removed { background: #6a2d2d; color: #e4b7b7; }
+
+.pair { display: flex; gap: var(--space-s); }
+.side { flex: 1; min-width: 0; }
+.side h3 { margin-bottom: var(--space-xs); color: #999; font-size: var(--step--1); text-transform: uppercase; }
+.side img { width: 100%; border: 1px solid #333; border-radius: 4px; }
+
+.placeholder { padding: var(--space-xl); text-align: center; color: #666; border: 1px dashed #333; border-radius: 4px; }