╭ changed ─────────────╮ │src/ui/Repo/Events.zig│ ╰──────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────╮ │35 count: usize = 0, │ │36 events: []const Item = &.{}, │ │37 next: ?EventRef = null, │ │38 + │ │39 + // a window without events, which shows the empty message│ │40 + fn isEmpty(self: *const Window) bool { │ │41 + return self.events.len == 0; │ │42 + } │ │43 }; │ │44 │ │45 identity: []const u8, │ ╰─────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │396 var content_stack = try wgt.Stack(ui.Widget).init(allocator); │ │397 errdefer content_stack.deinit(allocator); │ │398 inline for ([_]ui.RoutablePage.EventsView{ .active, .removed }) |view| { │ │394 - var content_box = try initContent(allocator, data, session, view); │ │395 - errdefer content_box.deinit(allocator); │ │396 - try content_stack.children.put(allocator, content_box.getFocus().id, .{ .box = content_box }); │ │399 + var view_content = try initContent(allocator, data, session, view); │ │400 + errdefer view_content.deinit(allocator); │ │401 + try content_stack.children.put(allocator, view_content.getFocus().id, view_content); │ │402 } │ │403 content_stack.getFocus().child_id = content_stack.children.keys()[@backingInt(data.view)]; │ │404 try outer.children.put(allocator, content_stack.getFocus().id, .{ .widget = .{ .stack = content_stack }, .rect = null, .min_size = null });│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │406 return .{ .box = outer, .data = data, .session = session, .detailed_index = .{ null, null } }; │ │407 } │ │408 │ │404 - fn initContent(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session, view: ui.RoutablePage.EventsView) !wgt.Box(ui.Widget) {│ │409 + // an empty window shows the empty message in place of the list and detail │ │410 + fn initContent(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session, view: ui.RoutablePage.EventsView) !ui.Widget { │ │411 + const event_window = data.window(view); │ │412 + if (event_window.isEmpty()) return .{ .center = try ui.widget.initEmpty(allocator) }; │ │413 + │ │414 var content_box = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .horiz }); │ │415 errdefer content_box.deinit(allocator); │ │416 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │417 var list_box = try wgt.Box(ui.Widget).init(allocator, .{ .border = null, .direction = .vert, .stretch = true }); │ │418 errdefer list_box.deinit(allocator); │ │410 - const event_window = data.window(view); │ │419 for (event_window.events) |event| { │ │420 const route = ui.RoutablePage.repoEventsRoute(data.identity, view, event.kind, event.id, data.moment) orelse return error.RouteTooLong;│ │421 const link = try session.page_arena.allocator().print("ai:{s}", .{try route.toUrl(session.page_arena)}); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │446 } │ │447 try content_box.children.put(allocator, frame.getFocus().id, .{ .widget = .{ .box = frame }, .rect = null, .min_size = .{ .width = detail_min_width, .height = null } });│ │448 │ │441 - content_box.getFocus().child_id = content_box.children.keys()[if (event_window.events.len > 0) detail_index else list_index]; │ │442 - return content_box; │ │449 + content_box.getFocus().child_id = content_box.children.keys()[detail_index]; │ │450 + return .{ .box = content_box }; │ │451 } │ │452 │ │453 fn addRow(allocator: std.mem.Allocator, box: *wgt.Box(ui.Widget), text: []const u8, link: []const u8) !void { │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │523 self.clearGrid(); │ │524 if (self.header().getSelectedIndex()) |index| │ │525 self.contentStack().getFocus().child_id = self.contentStack().children.keys()[index]; │ │526 + if (self.eventWindow().isEmpty()) return self.box.build(allocator, constraint, root_focus);│ │527 try self.refreshDetail(allocator); │ │528 │ │529 const list = self.listBox(); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │583 // scrolling crosses the sub header boundary the same way arrows do │ │584 const direction = inp.vertDirection(key); │ │585 if (self.headerActive()) { │ │577 - if (direction == .down) root_focus.setFocus(self.content().getFocus().id) else try self.header().input(allocator, key, root_focus);│ │586 + if (direction == .down) { │ │587 + // the empty message has nothing to focus │ │588 + if (!self.eventWindow().isEmpty()) root_focus.setFocus(self.content().getFocus().id); │ │589 + } else try self.header().input(allocator, key, root_focus); │ │590 return; │ │591 } │ │592 // the way back to the list, by enter or a click │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯