+// }}}
+
+// write {{{
+const TimeStr = std.BoundedArray(u8, 256);
+
+// http://howardhinnant.github.io/date_algorithms.html
+fn time_str(_t: i64) TimeStr {
+ const t: u64 = @intCast(_t);
+ var result = TimeStr.init(0) catch unreachable;
+
+ const nD = @divFloor(t, std.time.s_per_day);
+ const z: u64 = nD + 719468;
+ const era: u64 = (if (z >= 0) z else z - 146096) / 146097;
+ const doe: u64 = z - era * 146097; // [0, 146096]
+ const yoe: u64 = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; // [0, 399]
+ const Y: u64 = yoe + era * 400;
+ const doy: u64 = doe - (365 * yoe + yoe / 4 - yoe / 100); // [0, 365]
+ const mp: u64 = (5 * doy + 2) / 153; // [0, 11]
+ const D: u64 = doy - (153 * mp + 2) / 5 + 1; // [1, 31]
+ const M: u64 = if (mp < 10) mp + 3 else mp - 9;
+
+ const h: u64 = @divFloor(t - nD * std.time.s_per_day, std.time.s_per_hour);
+ const m: u64 = @divFloor(t - nD * std.time.s_per_day - h * std.time.s_per_hour, std.time.s_per_min);
+ const s: u64 = t - nD * std.time.s_per_day - h * std.time.s_per_hour - m * std.time.s_per_min;
+
+ std.fmt.format(result.writer(), "<time><span>{:0>4}-{:0>2}-{:0>2} {:0>2}:{:0>2}:{:0>2} UTC</span><script>document.currentScript.parentElement.innerHTML=new Date({}).toLocaleString()</script></time>", .{ Y, M, D, h, m, s, t * 1000 }) catch unreachable;
+
+ return result;
+}
+fn write_header(res: *http.Response, logged_in: ?Login) !void {
+ if (logged_in) |login| {
+ try res.write(
+ \\<a href="/">Home</a><br />
+ , .{});
+ try res.write(
+ \\<a href="/user/{s}">Profile</a><br />
+ , .{login.user.name.constSlice()});
+ try res.write(
+ \\<a href="/post">Post</a><br />
+ , .{});
+ try html_form(res, "/logout", .{
+ \\type="submit" value="Logout"
+ });
+ try res.write("<br /><br />", .{});
+ } else {
+ try res.write(
+ \\<a href="/">Home</a><br />
+ \\<form action="/register" method="post">
+ \\<input type="text" name="username" />
+ \\<input type="password" name="password" />
+ \\<input type="submit" value="Register" />
+ \\</form><br />
+ \\<form action="/login" method="post">
+ \\<input type="text" name="username" />
+ \\<input type="password" name="password" />
+ \\<input type="submit" value="Login" />
+ \\</form><br /><br />
+ , .{});
+ }
+}
+fn write_start(res: *http.Response) !void {
+ try res.write(
+ \\<!doctype html>
+ \\<html>
+ \\<head>
+ \\<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🐣</text></svg>">
+ \\<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ \\<style>
+ \\ form {
+ \\ display: inline-block;
+ \\ }
+ \\</style>
+ \\</head>
+ \\<body>
+ , .{});
+}
+fn write_end(res: *http.Response) !void {
+ try res.write("</body></html>", .{});
+}
+fn write_post(res: *http.Response, txn: lmdb.Txn, logged_in: ?Login, post_id: PostId, options: struct { recurse: u8 = 0, show_comment_field: bool = false }) !void {
+ const posts = try Db.posts(txn);
+ const post = posts.get(post_id) catch {
+ res.redirect("/") catch {};
+ return;
+ };
+ const users = try Db.users(txn);
+ const user = try users.get(post.user_id);
+
+ try res.write(
+ \\<div id="{x}">
+ \\<span><a href="/user/{s}">{s}</a>
+ , .{ @intFromEnum(post_id), user.name.constSlice(), user.display_name.constSlice() });
+ if (post.parent_id) |id| {
+ try res.write(" <a href=\"/post/{x}\">..</a>", .{@intFromEnum(id)});
+ }
+ try res.write(
+ \\ {s}</span><br />
+ \\<span>{s}</span><br />
+ , .{ time_str(post.time).constSlice(), post.text.constSlice() });
+
+ if (logged_in != null and post.user_id == logged_in.?.user.id) {
+ // Votes
+ try res.write(
+ \\<small>
+ \\<a href="/upvotes/{0x}">{1} Upvotes</a>
+ \\<a href="/downvotes/{0x}">{2} Downvotes</a>
+ \\</small>
+ \\<br />
+ , .{ @intFromEnum(post_id), post.upvotes, post.downvotes });
+ }
+
+ if (post.quote_id) |quote_id| {
+ try res.write("<div style=\"border: 1px solid black;\">", .{});
+ if (options.recurse > 0) {
+ try write_post(res, txn, logged_in, quote_id, .{ .recurse = options.recurse - 1 });
+ } else {
+ try res.write("<a href=\"/post/{x}\">...</a>", .{@intFromEnum(post_id)});
+ }
+ try res.write("</div>", .{});
+ }
+
+ const comments_view = try post.comments.open(txn);
+ const quotes_view = try post.quotes.open(txn);
+ const votes_view = try post.votes.open(txn);
+
+ // Votes
+ const vote: ?Vote = if (logged_in != null and try votes_view.has(logged_in.?.user.id)) try votes_view.get(logged_in.?.user.id) else null;
+
+ if (vote != null and vote.?.kind == .Up) {
+ try html_form(res, "/upvote", .{
+ .{ "type=\"hidden\" value=\"{x}\" name=\"post_id\"", .{@intFromEnum(post.id)} },
+ .{ "type=\"submit\" value=\"⬆ {}\"", .{post.upvotes} },
+ });
+ } else {
+ try html_form(res, "/upvote", .{
+ .{ "type=\"hidden\" value=\"{x}\" name=\"post_id\"", .{@intFromEnum(post.id)} },
+ .{ "type=\"submit\" value=\"⇧ {}\"", .{post.upvotes} },
+ });
+ }
+ if (vote != null and vote.?.kind == .Down) {
+ try html_form(res, "/downvote", .{
+ .{ "type=\"hidden\" value=\"{x}\" name=\"post_id\"", .{@intFromEnum(post.id)} },
+ .{ "type=\"submit\" value=\"⬇ {}\"", .{post.downvotes} },
+ });
+ } else {
+ try html_form(res, "/downvote", .{
+ .{ "type=\"hidden\" value=\"{x}\" name=\"post_id\"", .{@intFromEnum(post.id)} },
+ .{ "type=\"submit\" value=\"⇩ {}\"", .{post.downvotes} },
+ });
+ }
+
+ // Comment Count
+ try res.write(
+ \\<a href="/post/{x}">💭 {}</a>
+ , .{ @intFromEnum(post.id), comments_view.len() });
+
+ // Quote
+ try res.write(
+ \\<a href="/quoted/{x}">🔁 {}</a>
+ , .{ @intFromEnum(post.id), quotes_view.len() });
+
+ // Save to List
+ if (logged_in) |login| {
+ const lists_view = try login.user.post_lists.open(txn);
+ try res.write("<form action=\"/list_add\" method=\"post\">", .{});
+ try res.write("<select name=\"list_id\">", .{});
+ var it = lists_view.iterator();
+ // TODO: mark lists that already contain post
+ while (it.next()) |kv| {
+ const name = kv.val.name;
+ const id = kv.val.list.base.idx.?;
+ const list_view = try kv.val.list.open(txn);
+ try res.write("<option value=\"{x}\">{s}{s}</option>", .{ id, name.constSlice(), if (list_view.has(post_id) catch false) " *" else "" });
+ }
+ try res.write("</select>", .{});
+ try res.write("<input type=\"hidden\" name=\"post_id\" value=\"{x}\" />", .{@intFromEnum(post_id)});
+ try res.write("<input type=\"submit\" value=\"Save\" />", .{});
+ try res.write("</form>", .{});
+ }
+
+ // Comment field
+ // TODO: maybe always show comment field and prompt for login
+ if (options.show_comment_field and logged_in != null) {
+ try res.write("<br /><br />", .{});
+ try html_form(res, "/comment", .{
+ .{ "type=\"hidden\" value=\"{x}\" name=\"post_id\"", .{@intFromEnum(post.id)} },
+ .{ "textarea", "type=\"text\" name=\"text\" placeholder=\"Text\"", .{} },
+ "type=\"submit\" value=\"Comment\"",
+ });
+ try res.write("<br />", .{});
+ }