commit 3d5382c1bf78e1fb1c97110c2dd28189273d4846
Author: tri <tri@thac.loan>
Date:   Tue Oct 7 08:29:06 2025 +0700

    generate objects/<hash>.patch files
    
    So people can easily cherry-pick specific commits without having to
    pull the repo.

diff --git a/src/assets/style.css b/src/assets/style.css
index 8be0b4b..86c48f3 100644
--- a/src/assets/style.css
+++ b/src/assets/style.css
@@ -239,6 +239,11 @@ table.text-blob-content {
   }
 }
 
+.patch-link {
+  margin-top: 1.5rem;
+  margin-bottom: 0.2rem;
+}
+
 .commit-content {
   width: fit-content;
   max-width: 100%;
@@ -246,6 +251,8 @@ table.text-blob-content {
   border: 1px solid var(--fg);
   padding: 1rem;
 
+  margin-top: 0;
+
   .bold {
     font-weight: bold;
   }
diff --git a/src/main.zig b/src/main.zig
index 6b683a9..fe2aa4f 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -596,6 +596,10 @@ pub fn writeCommitPage(
         },
     });
 
+    try writer.print(
+        \\<p class="patch-link"><a href="../{s}.patch">download patch</a></p>
+    , .{commit.hash});
+
     try writer.writeAll(
         \\<pre class="commit-content">
         \\
@@ -643,6 +647,15 @@ pub fn writeCommitPage(
 
     try templates.base_end(writer);
     try writer.flush();
+
+    var objects_dir = try out_repo_dir.openDir(constants.web_objects_path, .{});
+    defer objects_dir.close();
+
+    try objects_dir.writeFile(.{
+        .sub_path = try fmt.allocPrint(arena, "{s}.patch", .{commit.hash}),
+        .data = commit_text,
+        .flags = .{},
+    });
 }
 
 /// For each historical commit, iterate its blobs and generate if necessary