╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──────╮ │src/ui/User.zig│ ╰───────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 97 { │ │ 98 var header_view = try Header.View.init(allocator, &data.header, session); │ │ 99 errdefer header_view.deinit(allocator); │ │ 97 - repos_tab_id = header_view.tab_ids[0]; │ │100 + repos_tab_id = header_view.tab_ids.keys()[0]; │ │101 try box.children.put(allocator, header_view.getFocus().id, .{ .widget = .{ .user_header = header_view }, .rect = null, .min_size = null });│ │102 } │ │103 │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │135 try stack.children.put(allocator, auth_view.getFocus().id, .{ .home_auth = auth_view }); │ │136 } │ │137 │ │138 + if (session.is_terminal) { │ │139 + var quit_view = try Quit.View.init(allocator, &data.quit, session); │ │140 + errdefer quit_view.deinit(allocator); │ │141 + try stack.children.put(allocator, quit_view.getFocus().id, .{ .quit = quit_view }); │ │142 + } │ │143 + │ │144 try box.children.put(allocator, stack.getFocus().id, .{ .widget = .{ .stack = stack }, .rect = null, .min_size = null });│ │145 } │ │146 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │165 if (header.getSelectedIndex()) |index| { │ │166 stack.getFocus().child_id = stack.children.keys()[index]; │ │167 const name = self.data.route_name; │ │159 - self.session.data.current_page = switch (index) { │ │160 - 1 => .{ .user_settings = name }, │ │161 - 2 => .{ .user_auth = name }, │ │162 - else => .{ .user = name }, │ │163 - }; │ │168 + switch (index) { │ │169 + 1 => self.session.data.current_page = .{ .user_settings = name }, │ │170 + 2 => self.session.data.current_page = .{ .user_auth = name }, │ │171 + // the quit tab is tty-only and not a route, so leave current_page│ │172 + // alone (nothing to mirror into the url). │ │173 + 3 => {}, │ │174 + else => self.session.data.current_page = .{ .user = name }, │ │175 + } │ │176 } │ │177 try self.box.build(allocator, constraint, root_focus); │ │178 } │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────╮ │206 .flow_box_scroll => |*v| v.getSelectedIndex() == 0,│ │207 .home_settings => |*v| v.getSelectedIndex() == 0, │ │208 .home_auth => |*v| v.getSelectedIndex() == 0, │ │209 + .quit => |*v| v.getSelectedIndex() == 0, │ │210 else => false, │ │211 }; │ │212 if (at_top) { │ ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/User/Header.zig│ ╰──────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │27 pub const View = struct { │ │28 box: wgt.Box(ui.Widget), │ │29 data: *const Self, │ │30 - tab_ids: [3]usize, │ │30 + tab_ids: std.AutoArrayHashMapUnmanaged(usize, void), │ │31 │ │32 pub fn init(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session) !View { │ │33 var box = wgt.Box(ui.Widget).init(.{ .border_style = .hidden, .rounded_corners = true, .direction = .horiz });│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────╮ │34 errdefer box.deinit(allocator); │ │35 │ │36 - var tab_ids: [3]usize = undefined; │ │36 + var tab_ids: std.AutoArrayHashMapUnmanaged(usize, void) = .empty;│ │37 + errdefer tab_ids.deinit(allocator); │ │38 │ │39 // title sits to the left of the tabs │ │40 { │ ╰─────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────╮ │75 errdefer text_box.deinit(allocator); │ │76 text_box.getFocus().focusable = true; │ │77 text_box.getFocus().kind = .{ .custom = repos_link }; │ │77 - tab_ids[0] = text_box.getFocus().id; │ │78 + try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │79 try box.children.put(allocator, text_box.getFocus().id, .{│ │80 .widget = .{ .text_box = text_box }, │ │81 .rect = null, │ ╰──────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────╮ │100 errdefer text_box.deinit(allocator); │ │101 text_box.getFocus().focusable = true; │ │102 text_box.getFocus().kind = .{ .custom = settings_link }; │ │102 - tab_ids[1] = text_box.getFocus().id; │ │103 + try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │104 try box.children.put(allocator, text_box.getFocus().id, .{│ │105 .widget = .{ .text_box = text_box }, │ │106 .rect = null, │ ╰───────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │114 var auth_tab = try AuthTab.View.init(allocator, &data.auth_tab, session);│ │115 errdefer auth_tab.deinit(allocator); │ │116 auth_tab.text_box.getFocus().kind = .{ .custom = auth_link }; │ │116 - tab_ids[2] = auth_tab.getFocus().id; │ │117 + try tab_ids.put(allocator, auth_tab.getFocus().id, {}); │ │118 try box.children.put(allocator, auth_tab.getFocus().id, .{ │ │119 .widget = .{ .auth_tab = auth_tab }, │ │120 .rect = null, │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │121 .min_size = .{ .width = AuthTab.min_width, .height = null }, │ │122 + }); │ │123 + } │ │124 + │ │125 + // quit tab │ │126 + if (session.is_terminal) { │ │127 + var text_box = try wgt.TextBox(ui.Widget).init(allocator, ui.Quit.tab_label, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none });│ │128 + errdefer text_box.deinit(allocator); │ │129 + text_box.getFocus().focusable = true; │ │130 + text_box.getFocus().kind = .{ .custom = ui.Quit.tab_kind }; │ │131 + try tab_ids.put(allocator, text_box.getFocus().id, {}); │ │132 + try box.children.put(allocator, text_box.getFocus().id, .{ │ │133 + .widget = .{ .text_box = text_box }, │ │134 + .rect = null, │ │135 + // the label is a single column; +2 for the border │ │136 + .min_size = .{ .width = 1 + 2, .height = null }, │ │137 }); │ │138 } │ │139 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯