╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ─╮ │src/ui.zig│ ╰──────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │2298 // a failed terminal undo retained on the current tab │ │2299 undo_failure: ?[]const u8 = null, │ │2300 current_page: RoutablePage = .default, │ │2300 - // whether to render the ANSI art backdrop │ │2301 - enable_ansi: bool = true, │ │2301 // the selected ANSI art. the server serializes one image for WASM so│ │2302 // the browser does not need the whole build-generated collection. │ │2303 ansi_art: []const u8 = "", │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │2311 // the wasm side also parses elided link urls and hides the multi-user │ │2312 // chrome. │ │2313 host_kind: evt.HostKind = .server, │ │2315 - }; │ │2316 - │ │2317 - // a user-initiated state change. widgets enqueue these on the session during │ │2318 - // input instead of mutating state or touching the DB themselves; the host │ │2319 - // drains them each frame (see applyAndWritePending / applyPending). this keeps DB│ │2320 - // side effects out of the widget tree and gives every render path one place to │ │2321 - // turn a UI action into a state change + event. │ │2322 - pub const Action = union(enum) { │ │2323 - toggle_ansi, │ │2314 }; │ │2315 │ │2316 pub fn init( │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2338 const moment = self.haxy_moment orelse return; │ │2339 const user = (try activeUser(moment, self.arena, user_id)) orelse return self.logOut();│ │2340 self.data.user_name = user.event.name; │ │2351 - self.data.enable_ansi = user.event.enable_ansi; │ │2341 } │ │2342 │ │2343 // forget the logged-in user, on a logout or once their account is removed │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2394 .local => .local, │ │2395 .server => .{ .server = .{ .users_dir = self.users_dir orelse unreachable } }, │ │2396 }; │ │2408 - } │ │2409 - │ │2410 - // queue an action for the host to drain this frame. │ │2411 - pub fn push(self: *Self, action: Action) !void { │ │2412 - try self.pending.append(self.arena.allocator(), action); │ │2397 } │ │2398 │ │2415 - // apply a single action's in-memory effect only (no persistence). │ │2416 - fn apply(self: *Self, action: Action) void { │ │2417 - switch (action) { │ │2418 - .toggle_ansi => self.data.enable_ansi = !self.data.enable_ansi, │ │2419 - } │ │2420 - } │ │2421 - │ │2422 - // drain the session's queued actions by applying them to the session. │ │2423 - // used on the wasm path, which has no repo to persist to. │ │2424 - pub fn applyPending(self: *Self) void { │ │2425 - for (self.pending.items) |action| self.apply(action); │ │2426 - self.pending.clearRetainingCapacity(); │ │2427 - } │ │2428 - │ │2429 - // drain the session's queued actions by applying them to the session and │ │2430 - // writing them to the db │ │2431 - pub fn applyAndWritePending( │ │2432 - self: *Self, │ │2433 - io: std.Io, │ │2434 - allocator: std.mem.Allocator, │ │2435 - repo: *rp.Repo(.xit, evt.admin_repo_opts), │ │2436 - ) !void { │ │2437 - defer self.pending.clearRetainingCapacity(); │ │2438 - for (self.pending.items) |action| { │ │2439 - self.apply(action); │ │2440 - switch (action) { │ │2441 - .toggle_ansi => if (self.data.user_id) |user_id| { │ │2442 - try evt.User.toggleAnsi(evt.admin_repo_opts, io, allocator, repo, self.users_dir orelse unreachable, user_id);│ │2443 - }, │ │2444 - } │ │2445 - } │ │2446 - } │ │2447 - │ │2448 - // reload the moment from the admin repo and re-read user preferences │ │2399 + // reload the moment from the admin repo and log out a removed user │ │2400 pub fn reloadMoment(self: *Self, allocator: std.mem.Allocator, repo: *rp.Repo(.xit, evt.admin_repo_opts)) !void { │ │2401 const moment = try evt.currentMoment(evt.admin_repo_opts, repo); │ │2402 self.haxy_moment = moment; │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────╮ │2404 const user_id = self.userId() orelse return; │ │2405 var arena = std.heap.ArenaAllocator.init(allocator); │ │2406 defer arena.deinit(); │ │2456 - const user = (try activeUser(moment, &arena, user_id)) orelse return self.logOut();│ │2457 - self.data.enable_ansi = user.event.enable_ansi; │ │2407 + if (try activeUser(moment, &arena, user_id) == null) self.logOut(); │ │2408 } │ │2409 │ │2410 // request a forward navigation to `route`; the host consumes next_page │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────╮ │2428 term.setActive(&terminal); │ │2429 defer term.setActive(null); │ │2430 │ │2431 + try terminal.queryBackground(); │ │2432 + │ │2433 while (!terminal.shouldQuit()) { │ │2434 const grid_changed = try terminal.render(&nav.root);│ │2435 │ ╰──────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────╮ │2478 } │ │2479 } │ │2480 │ │2529 - // persist queued actions when there's a repo; local mode has none, │ │2530 - // so just apply in-memory │ │2531 - if (repo_maybe) |repo| { │ │2532 - try session.applyAndWritePending(io, allocator, repo); │ │2533 - // reload so the next navigation builds its page from the current moment │ │2534 - try session.reloadMoment(allocator, repo); │ │2535 - } else { │ │2536 - session.applyPending(); │ │2537 - } │ │2481 + // reload so the next navigation builds its page from the current moment │ │2482 + if (repo_maybe) |repo| try session.reloadMoment(allocator, repo); │ │2483 │ │2484 // reconcile navigation: forward to a new page, or back on escape. │ │2540 - try nav.sync(allocator, session); │ │2485 + // the terminal background can change at any time, so recheck it on each page│ │2486 + if (try nav.sync(allocator, session)) try terminal.queryBackground(); │ │2487 │ │2488 // the quit button (on the quit tab) asks the host to tear down. │ │2489 if (session.quit_requested) terminal.requestQuit(); │ ╰───────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────╮ │2577 } else { │ │2578 try root.input(allocator, key, root_focus); │ │2579 } │ │2580 + }, │ │2581 + .event => |event| switch (event) { │ │2582 + .background => |rgb| session.terminal_background = rgb,│ │2583 + .resize => try root.input(allocator, key, root_focus), │ │2584 }, │ │2585 else => try root.input(allocator, key, root_focus), │ │2586 } │ ╰─────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────╮ │2815 // current root and builds the new page in a fresh arena; a back request │ │2816 // frees the current page and restores the previous one. when escape is │ │2817 // pressed with no history left we switch to the quit tab instead of quitting. │ │2868 - pub fn sync(self: *Nav, allocator: std.mem.Allocator, session: *Session) !void {│ │2818 + // returns whether the root was replaced. │ │2819 + pub fn sync(self: *Nav, allocator: std.mem.Allocator, session: *Session) !bool {│ │2820 // refresh: rebuild the current page in place from a current moment │ │2821 if (session.refresh_requested) { │ │2822 session.refresh_requested = false; │ ╰──────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────╮ │2823 try self.rebuild(allocator, session);│ │2873 - return; │ │2824 + return true; │ │2825 } │ │2826 │ │2827 if (session.back == .requested) { │ ╰───────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯