╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Users.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
53 const event_id = order_key[@sizeOf(u64)..]; 54 const user_cursor = try event_id_to_user.getCursor(hash.hashInt(hash_kind, event_id)) orelse continue; 55 const user_map = try DB.HashMap(.read_only).init(user_cursor); 56 const user_event = try evt.read(evt.User.Record, DB, hash_kind, arena, user_map); 57 try users.append(arena.allocator(), evt.project(evt.User.Public, user_event.event)); 58 } 59 60 return .{ 61 .users = users.items, 62 .start = start, 63 .next_start = if (end < count) end else null, 64 }; 65 } 66 67 pub const View = struct { 68 list: ui.FlowBox.Scroll, 69 data: *const Self, 70 71 pub fn init(allocator: std.mem.Allocator, data: *const Self, web_native: bool) !View { 72 var self = blk: { 73 var list = try ui.FlowBox.Scroll.init(allocator, .{ .cell_height = 1 }, web_native); 74 errdefer list.deinit(allocator); 75 76 break :blk View{ 77 .list = list, 78 .data = data, 79 }; 80 }; 81 errdefer self.deinit(allocator); 82 83 var arena = std.heap.ArenaAllocator.init(allocator); 84 defer arena.deinit(); 85 const aa = arena.allocator(); 86 87 // a leading "previous" row off the first window, one row per user, then 88 // a trailing "next" row when more remain. each window row navigates to the 89 // adjacent window (full reload on web, Nav rebuild on the TUI). 90 var items: std.ArrayList(ui.FlowBox.Item) = .empty; 91 if (data.start > 0) 92 try items.append(aa, .{ .text = "← previous", .link = try std.fmt.allocPrint(aa, "a:/users/start:{d}", .{data.start -| page_size}) }); 93 for (data.users) |user| 94 // clicking a user opens their page; the "a:" prefix makes the web 95 // renderer emit an <a href="/user/foo"> anchor. 96 try items.append(aa, .{ 97 .text = try aa.dupe(u8, user.name), 98 .link = try std.fmt.allocPrint(aa, "a:/user/{s}", .{user.name}), 99 }); 100 if (data.next_start) |next_start| 101 try items.append(aa, .{ .text = "next →", .link = try std.fmt.allocPrint(aa, "a:/users/start:{d}", .{next_start}) }); 102 try self.list.setItems(allocator, items.items); 103 104 return self; 105 } 106 107 pub fn deinit(self: *View, allocator: std.mem.Allocator) void { 108 self.list.deinit(allocator); 109 } 110 111 pub fn build(self: *View, allocator: std.mem.Allocator, constraint: layout.Constraint, root_focus: *Focus) !void { 112 try self.list.build(allocator, constraint, root_focus); 113 } 114 115 pub fn input(self: *View, allocator: std.mem.Allocator, key: Key, root_focus: *Focus) !void { 116 try self.list.input(allocator, key, root_focus); 117 } 118 119 pub fn clearGrid(self: *View) void { 120 self.list.clearGrid(); 121 } 122 123 pub fn getGrid(self: View) ?Grid { 124 return self.list.getGrid(); 125 } 126 127 pub fn getFocus(self: *View) *Focus { 128 return self.list.getFocus(); 129 } 130 131 pub fn getSelectedIndex(self: View) ?usize { 132 return self.list.getSelectedIndex(); 133 } 134 }; 135