╭ changed ────╮ │src/event.zig│ ╰─────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │30 pub const admin_repo_opts: rp.RepoOpts(.xit) = .{}; │ │31 pub const AdminDB = rp.Repo(.xit, admin_repo_opts).DB; │ │32 │ │33 +// the admin repo's file the home page renders │ │34 +pub const admin_about_path = "ABOUT.md"; │ │35 + │ │36 +// create the admin repo with a master branch holding the default about page. │ │37 +// pushes to master update its work dir. │ │38 +pub fn initAdminRepo(io: std.Io, allocator: std.mem.Allocator, path: []const u8) !rp.Repo(.xit, admin_repo_opts) { │ │39 + var repo = try rp.Repo(.xit, admin_repo_opts).init(io, allocator, .{ .path = path }); │ │40 + errdefer repo.deinit(io, allocator); │ │41 + try repo.addConfig(io, allocator, .{ .name = "receive.denycurrentbranch", .value = "updateInstead" }); │ │42 + { │ │43 + const file = try repo.core.work_dir.createFile(io, admin_about_path, .{}); │ │44 + defer file.close(io); │ │45 + try file.writeStreamingAll(io, "# HAXY\n\nWelcome to your Haxy instance!\n\nEdit `admin/ABOUT.md` in the server dir to change what this page says.");│ │46 + } │ │47 + try repo.add(io, allocator, &.{admin_about_path}); │ │48 + _ = try repo.commit(io, allocator, .{ .author = "haxy <haxy@localhost>", .message = "init" }); │ │49 + return repo; │ │50 +} │ │51 + │ │52 // the xitdb type events are stored in. it only depends on the hash kind, so │ │53 // this matches the db of any xit repo using that hash kind. │ │54 pub fn EventDB(comptime hash_kind: hash.HashKind) type { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │104 defer allocator.free(work_path); │ │105 │ │106 const Repo = rp.Repo(.xit, evt.admin_repo_opts); │ │107 - var repo = try Repo.init(io, allocator, .{ .path = work_path, .bare = true });│ │107 + var repo = try evt.initAdminRepo(io, allocator, work_path); │ │108 defer repo.deinit(io, allocator); │ │109 │ │110 var session_arena = std.heap.ArenaAllocator.init(allocator); │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │70 // the repo page can build without a moment in local mode; the home and │ │71 // user pages always read from the admin db. │ │72 return switch (route.parent()) { │ │73 - .home => .{ .home = try Home.init(arena, session.haxy_moment orelse return error.NoMoment, session.userId(), switch (route) {│ │73 + .home => .{ .home = try Home.init(arena, session, session.haxy_moment orelse return error.NoMoment, switch (route) { │ │74 .home_users => |start| start, │ │75 else => 0, │ │76 }, switch (route) { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │110 // .user parent page, so switching between them stays on that page (and just│ │111 // updates the url) rather than navigating away. │ │112 pub const RoutablePage = union(enum) { │ │113 + home_about, │ │114 home_users: usize, // 0 = first page │ │115 home_repos: usize, // 0 = first page │ │116 home_settings, │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────╮ │181 fork_settings: ForkRoute, │ │182 fork_auth: ForkRoute, │ │183 │ │183 - pub const default: RoutablePage = .{ .home_repos = 0 };│ │184 + pub const default: RoutablePage = .home_about; │ │185 │ │186 pub const RefKind = enum { branch, tag }; │ │187 │ ╰────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1017 │ │1018 pub fn toUrl(self: RoutablePage, arena: *std.heap.ArenaAllocator) ![]const u8 { │ │1019 return switch (self) { │ │1020 + .home_about => "/", │ │1021 .home_users => |start| if (start == 0) @as([]const u8, "/users") else try std.fmt.allocPrint(arena.allocator(), "/users/" ++ start_seg ++ "{d}", .{start}),│ │1022 .home_repos => |start| if (start == 0) @as([]const u8, "/repos") else try std.fmt.allocPrint(arena.allocator(), "/repos/" ++ start_seg ++ "{d}", .{start}),│ │1023 .home_settings => "/settings", │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1403 │ │1404 pub fn parent(self: RoutablePage) PageKind { │ │1405 return switch (self) { │ │1404 - .home_users, .home_repos, .home_settings, .home_auth => .home, │ │1406 + .home_about, .home_users, .home_repos, .home_settings, .home_auth => .home, │ │1407 .user_repos, .user_forks, .user_settings, .user_auth => .user, │ │1408 .repo_files, .repo_commits, .repo_diff, .repo_refs, .repo_issues, .repo_patches, .repo_discussions, .repo_events, .repo_undo, .repo_settings, .repo_auth => .repo,│ │1409 .fork_patch, .fork_diff, .fork_files, .fork_commits, .fork_settings, .fork_auth => .fork, │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────╮ │src/ui/Home.zig│ ╰───────────────╯ ╭────────────────────────────────────────────────────╮ │10 const inp = @import("./input.zig"); │ │11 const evt = @import("../event.zig"); │ │12 │ │13 +pub const About = @import("./Home/About.zig"); │ │14 pub const Users = @import("./Home/Users.zig"); │ │15 pub const Repos = @import("./Home/Repos.zig"); │ │16 pub const Header = @import("./Home/Header.zig");│ ╰────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────╮ │19 pub const Quit = @import("./Quit.zig");│ │20 │ │21 header: Header, │ │22 +about: About, │ │23 users: Users, │ │24 repos: Repos, │ │25 settings: Settings, │ ╰───────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────╮ │30 │ │31 pub fn init( │ │32 arena: *std.heap.ArenaAllocator, │ │33 + session: *ui.Session, │ │34 haxy_moment: evt.AdminDB.HashMap(.read_only), │ │32 - user_id: ?[evt.event_id_size]u8, │ │35 // pagination window start for each list tab; the inactive tab gets 0.│ │36 users_start: usize, │ │37 repos_start: usize, │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯