╭ changed ──────╮ │src/ui/User.zig│ ╰───────────────╯ ╭─────────────────────────────────────────────────────────────────╮ │21 │ │22 pub const ForkItem = struct { │ │23 id: []const u8, │ │24 - // the target repo's name │ │25 - name: []const u8, │ │24 + // the target repo, whose name and access the fork shares│ │25 + target: evt.Repo, │ │26 title: []const u8, │ │27 }; │ │28 + │ │29 +// a repo's access, shown under its list item │ │30 +fn accessLabel(repo: evt.Repo) []const u8 { │ │31 + return switch (repo.read_access) { │ │32 + .public => "(public)", │ │33 + .private => "(private)", │ │34 + }; │ │35 +} │ │36 │ │37 header: Header, │ │38 user: evt.User.Public, │ ╰─────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────╮ │160 } else |_| {} │ │161 try forks.append(arena.allocator(), .{ │ │162 .id = try arena.allocator().dupe(u8, &fork_id_hex),│ │155 - .name = target_repo.event.name, │ │163 + .target = target_repo.event, │ │164 .title = title, │ │165 }); │ │166 } │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │225 try items.append(aa, .{ .text = "← previous", .link = try std.fmt.allocPrint(aa, "a:/user/{s}/forks/start:{d}", .{ data.user.name, data.forks_start -| page_size }) });│ │226 for (data.forks) |fork_item| { │ │227 // the fork route names the forker │ │220 - const identity = try std.fmt.allocPrint(aa, "{s}/{s}", .{ data.user.name, fork_item.name }); │ │228 + const identity = try std.fmt.allocPrint(aa, "{s}/{s}", .{ data.user.name, fork_item.target.name }); │ │229 const route = ui.RoutablePage.forkPatchRoute(identity, fork_item.id) orelse return error.RouteTooLong; │ │230 try items.append(aa, .{ │ │223 - .text = try std.fmt.allocPrint(aa, "{s} - {s}", .{ fork_item.name, fork_item.title }), │ │231 + .text = try std.fmt.allocPrint(aa, "{s} - {s}", .{ fork_item.target.name, fork_item.title }), │ │232 .link = try std.fmt.allocPrint(aa, "a:{s}", .{try route.toUrl(session.page_arena)}), │ │233 + .bottom_label = accessLabel(fork_item.target), │ │234 }); │ │235 } │ │236 if (data.forks_next_start) |next_start| │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │410 try items.append(aa, .{ │ │411 .text = if (repo.event.description.len == 0) repo.event.name else try std.fmt.allocPrint(aa, "{s} - {s}", .{ repo.event.name, repo.event.description }),│ │412 .link = try std.fmt.allocPrint(aa, "a:/repo/{s}/{s}", .{ data.user.name, repo.event.name }), │ │413 + .bottom_label = accessLabel(repo.event), │ │414 }); │ │415 if (data.repos_next_start) |next_start| { │ │416 var next = route; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/ui/widget.zig│ ╰─────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │231 self.arena.deinit(); │ │232 } │ │233 │ │234 - // one flow item: its display text plus an optional link. a non-empty `link` │ │235 - // sets the item's focus kind such as `.{ .custom = "a:/user/foo" }`, which │ │236 - // the web renderer turns into an anchor. │ │237 - pub const Item = struct { text: []const u8, link: []const u8 = "" }; │ │234 + // one flow item: its display text plus an optional link and bottom label. a │ │235 + // non-empty `link` sets the item's focus kind such as `.{ .custom = "a:/user/foo" }`, │ │236 + // which the web renderer turns into an anchor. │ │237 + pub const Item = struct { text: []const u8, link: []const u8 = "", bottom_label: []const u8 = "" };│ │238 │ │239 - // the text box copies the item text; links are copied into the arena, so the │ │240 - // caller's slices needn't outlive this call. │ │239 + // the text box copies the item text; links and bottom labels are copied into │ │240 + // the arena, so the caller's slices needn't outlive this call. │ │241 pub fn setItems(self: *FlowBox, allocator: std.mem.Allocator, items: []const Item) !void { │ │242 for (self.text_boxes.items) |*tb| tb.deinit(allocator); │ │243 self.text_boxes.clearAndFree(allocator); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │251 self.focus.child_id = null; │ │252 │ │253 for (items) |item| { │ │254 - var text_box = try wgt.TextBox.init(allocator, item.text, .{ .border_style = .hidden, .round_corners = true, .wrap_kind = .word }); │ │254 + var text_box = try wgt.TextBox.init(allocator, item.text, .{ .border_style = .hidden, .round_corners = true, .wrap_kind = .word, .bottom_label = try aa.dupe(u8, item.bottom_label) });│ │255 errdefer text_box.deinit(allocator); │ │256 text_box.getFocus().mode = .all; │ │257 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯