╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─────────────────╮ │src/ui/Home/Auth/Login.zig│ ╰──────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────╮ │261 // jump focus back to the users tab — the login button we │ │259 - // just pressed is about to be hidden by the tab-label swap.│ │262 + // just pressed is about to be hidden by the tab-label swap │ │263 try root_focus.setFocus(self.users_tab_id); │ │264 }, │ │265 } │ ╰─────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──────────────╮ │src/ui/Home/AuthTab.zig│ ╰───────────────────────╯ ╭──────────────────────────────────────────────────╮ │ 9 const Focus = xitui.focus.Focus; │ │10 │ │11 const Self = @This(); │ │12 + │ │13 +pub const min_width: usize = "logout".len + 2;│ │14 │ │15 pub fn init() Self { │ │16 return .{}; │ ╰──────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Home/Header.zig│ ╰──────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │26 box: wgt.Box(ui.Widget), │ │27 data: *const Self, │ │28 tab_ids: [4]usize, │ │29 - │ │30 - const ansi_tab_index: usize = 2; │ │31 - const auth_tab_index: usize = 3; │ │32 - // the auth slot must fit either "login" or "logout" │ │33 - const auth_tab_min_width: usize = @as(usize, "logout".len) + 2; │ │29 │ │30 pub fn init(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session) !View { │ │31 var box = wgt.Box(ui.Widget).init(.{ .border_style = .hidden, .rounded_corners = true, .direction = .horiz });│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ 55 }); │ │ 56 } │ │ 57 │ │ 63 - // fixed tabs │ │ 58 + // tabs │ │ 59 + var tab_index: usize = 0; │ │ 60 for ( │ │ 65 - [_][]const u8{ "users", "repos", "ANSI" }, │ │ 66 - [_][]const u8{ "a:/users", "a:/repos", "a:/ansi" }, │ │ 67 - 0.., │ │ 68 - ) |name, focus_name, i| { │ │ 69 - var text_box = try wgt.TextBox(ui.Widget).init(allocator, name, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none }); │ │ 70 - errdefer text_box.deinit(allocator); │ │ 71 - text_box.getFocus().focusable = true; │ │ 72 - text_box.getFocus().kind = .{ .custom = focus_name }; │ │ 73 - tab_ids[i] = text_box.getFocus().id; │ │ 74 - try box.children.put(allocator, text_box.getFocus().id, .{ │ │ 75 - .widget = .{ .text_box = text_box }, │ │ 76 - .rect = null, │ │ 77 - .min_size = .{ .width = name.len + 2, .height = null }, │ │ 78 - }); │ │ 79 - } │ │ 80 - │ │ 81 - // spacer pushes the auth tab to the right │ │ 82 - { │ │ 83 - var spacer = ui.Spacer.init(); │ │ 84 - errdefer spacer.deinit(allocator); │ │ 85 - try box.children.put(allocator, spacer.getFocus().id, .{ │ │ 86 - .widget = .{ .spacer = spacer }, │ │ 87 - .rect = null, │ │ 88 - .min_size = .{ .width = 1, .height = null }, │ │ 89 - }); │ │ 90 - } │ │ 91 - │ │ 92 - // auth tab — knows how to swap its own label based on session │ │ 93 - { │ │ 94 - var auth_tab = try AuthTab.View.init(allocator, &data.auth_tab, session); │ │ 95 - errdefer auth_tab.deinit(allocator); │ │ 96 - tab_ids[auth_tab_index] = auth_tab.getFocus().id; │ │ 97 - try box.children.put(allocator, auth_tab.getFocus().id, .{ │ │ 98 - .widget = .{ .home_auth_tab = auth_tab }, │ │ 99 - .rect = null, │ │100 - .min_size = .{ .width = auth_tab_min_width, .height = null }, │ │101 - }); │ │ 61 + [_][]const u8{ "users", "repos", "", "ANSI art", "" }, │ │ 62 + [_][]const u8{ "a:/users", "a:/repos", "", "a:/ansi", "a:/auth" }, │ │ 63 + ) |name, focus_name| { │ │ 64 + // spacer │ │ 65 + if (focus_name.len == 0) { │ │ 66 + var spacer = ui.Spacer.init(); │ │ 67 + errdefer spacer.deinit(allocator); │ │ 68 + try box.children.put(allocator, spacer.getFocus().id, .{ │ │ 69 + .widget = .{ .spacer = spacer }, │ │ 70 + .rect = null, │ │ 71 + .min_size = .{ .width = 1, .height = null }, │ │ 72 + }); │ │ 73 + } │ │ 74 + // auth │ │ 75 + else if (std.mem.eql(u8, "a:/auth", focus_name)) { │ │ 76 + var auth_tab = try AuthTab.View.init(allocator, &data.auth_tab, session); │ │ 77 + errdefer auth_tab.deinit(allocator); │ │ 78 + tab_ids[tab_index] = auth_tab.getFocus().id; │ │ 79 + tab_index += 1; │ │ 80 + try box.children.put(allocator, auth_tab.getFocus().id, .{ │ │ 81 + .widget = .{ .home_auth_tab = auth_tab }, │ │ 82 + .rect = null, │ │ 83 + .min_size = .{ .width = AuthTab.min_width, .height = null }, │ │ 84 + }); │ │ 85 + } │ │ 86 + // other tabs │ │ 87 + else { │ │ 88 + var text_box = try wgt.TextBox(ui.Widget).init(allocator, name, .{ .border_style = .single, .rounded_corners = true, .wrap_kind = .none });│ │ 89 + errdefer text_box.deinit(allocator); │ │ 90 + text_box.getFocus().focusable = true; │ │ 91 + text_box.getFocus().kind = .{ .custom = focus_name }; │ │ 92 + tab_ids[tab_index] = text_box.getFocus().id; │ │ 93 + tab_index += 1; │ │ 94 + try box.children.put(allocator, text_box.getFocus().id, .{ │ │ 95 + .widget = .{ .text_box = text_box }, │ │ 96 + .rect = null, │ │ 97 + .min_size = .{ .width = name.len + 2, .height = null }, │ │ 98 + }); │ │ 99 + } │ │100 } │ │101 │ │102 var self = View{ .box = box, .data = data, .tab_ids = tab_ids }; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────╮ │107 switch (session.data.current_page) {│ │108 .home_users => 0, │ │109 .home_repos => 1, │ │112 - .home_ansi => ansi_tab_index, │ │113 - .home_auth => auth_tab_index, │ │110 + .home_ansi => 2, │ │111 + .home_auth => 3, │ │112 } │ │113 ]; │ │114 return self; │ ╰─────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭──────────────────────────────────────╮ │1 const std = @import("std"); │ │2 const xit = @import("xit"); │ │3 const rp = xit.repo; │ │4 -const hash = xit.hash; │ │4 const evt = @import("./event.zig");│ │5 const ui = @import("./ui.zig"); │ │6 const xitui = xit.xitui; │ ╰──────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────╮ │149 return handleLogout(request, session_store); │ │150 } │ │151 if (method == .POST and std.mem.eql(u8, path, "/ansi")) { │ │153 - return handleAnsi(request); │ │152 + return handleAnsi(io, request, allocator, admin_repo_path, session_store);│ │153 } │ │154 │ │155 const get_or_head = method == .GET or method == .HEAD; │ ╰───────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │189 null │ │190 else │ │191 null; │ │192 + // enable_ansi is omitted here on purpose: Session.init fills it in from│ │193 + // the logged-in user's event, falling back to false when anonymous. │ │194 const html = try renderIndexHtml(io, allocator, admin_repo_path, .{ │ │195 .user_id = user_id, │ │196 .login_failure = login_failure, │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │197 .current_page = current_page, │ │197 - // enable_ansi is intentionally left at its default │ │198 }); │ │199 defer allocator.free(html); │ │200 // expire the flash cookie on the way out so a refresh doesn't keep│ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │248 var arena = std.heap.ArenaAllocator.init(allocator); │ │249 defer arena.deinit(); │ │250 │ │251 - const haxy_moment = try openHaxyMoment(repo_opts, &repo); │ │251 + const haxy_moment = try evt.currentMoment(repo_opts, &repo); │ │252 const result = try evt.User.verifyCredentials(Repo.DB, repo_opts.hash, haxy_moment, &arena, username, password);│ │253 │ │254 switch (result) { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯