╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ────────────╮ │src/ui/Auth/Login.zig│ ╰─────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │39 pub fn init(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session) !View { │ │40 var box = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = null, .rounded_corners = true, .direction = .vert });│ │41 errdefer box.deinit(allocator); │ │42 - // marks this subtree as an HTML form scope for the web overlay │ │42 + // marks this subtree as an HTML form scope for the web renderer │ │43 box.getFocus().kind = .{ .custom = "form:login" }; │ │44 │ │45 var nav_ids: [3]usize = undefined; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ─────────────╮ │src/ui/Auth/Logout.zig│ ╰──────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │27 pub fn init(allocator: std.mem.Allocator, data: *const Self, session: *ui.Session) !View { │ │28 var box = try wgt.Box(ui.Widget).init(allocator, .{ .border_style = null, .rounded_corners = true, .direction = .vert });│ │29 errdefer box.deinit(allocator); │ │30 - // marks this subtree as an HTML form scope for the web overlay │ │30 + // marks this subtree as an HTML form scope for the web renderer │ │31 box.getFocus().kind = .{ .custom = "form:logout" }; │ │32 │ │33 { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/ui/widget.zig│ ╰─────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────╮ │736 } │ │737 }; │ │738 │ │739 -// a submit button, indented past its form's content. the web overlay POSTs│ │739 +// a submit button, indented past its form's content. the web form POSTs │ │740 // the button's form; terminal hosts detect presses through `buttonId`. │ │741 pub const SubmitButton = struct { │ │742 box: wgt.Box(Widget), │ ╰────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │1329 const aa = self.session.arena.allocator(); │ │1330 const id = self.textInput().getFocus().id; │ │1331 try self.session.text_inputs.put(aa, id, self.textInput()); │ │1332 - try self.session.input_values.put(aa, id, self.choices[self.selected].text);│ │1332 } │ │1333 } │ │1334 │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────────────╮ │src/ui/widget/thread.zig│ ╰────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │716 var frame = try wgt.Box(Widget).init(allocator, .{ .border_style = .hidden, .direction = .vert });│ │717 errdefer frame.deinit(allocator); │ │718 // the tool row sits above the scroll (populateDetail fills │ │719 - // it per thread) so it can't scroll out from under the web │ │720 - // overlay <form>, whose position doesn't track pane scrolling. │ │719 + // it per thread). │ │720 { │ │721 var row = try wgt.Box(Widget).init(allocator, .{ .border_style = null, .direction = .horiz });│ │722 errdefer row.deinit(allocator); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │739 │ │740 // a thread form: title/tags/description inputs and a submit button, │ │741 // prefilled from `record` when given. its form: subtree makes the web │ │743 - // overlay wrap them in a <form> POSTing to `action`'s route. │ │742 + // renderer POST them to `action`'s route. │ │743 fn initThreadForm(allocator: std.mem.Allocator, session: *ui.Session, action: []const u8, record: ?*const Event.Record) !wgt.Box(Widget) {│ │744 var box = try wgt.Box(Widget).init(allocator, .{ .border_style = null, .direction = .vert }); │ │745 errdefer box.deinit(allocator); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │847 │ │848 // the conflict resolve form. the "use this" links are navigations that │ │849 // flip the url's theirs: pick, reloading the prefills; one submit │ │851 - // settles every conflict. the form: subtree makes the web overlay POST │ │850 + // settles every conflict. the form: subtree makes the web renderer POST │ │851 // to the resolve route. │ │852 fn initResolveForm(allocator: std.mem.Allocator, session: *ui.Session, data: *const Self) !wgt.Box(Widget) {│ │853 const aa = session.page_arena.allocator(); │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1032 return std.fmt.allocPrint(aa, "a:{s}", .{try route.toUrl(session.page_arena)}); │ │1033 } │ │1034 │ │1036 - // the resolve form's page-constant initial value for the input `name`: │ │1037 - // the picked side of its conflicted field or hunk │ │1038 - fn resolvePrefill(self: *This, name: []const u8) ?[]const u8 { │ │1039 - const conflict = if (self.data.conflict) |*c| c else return null; │ │1040 - const theirs = self.data.theirsPicked(name); │ │1041 - if (std.mem.eql(u8, name, "title")) { │ │1042 - const fc = if (conflict.title) |*f| f else return null; │ │1043 - return if (theirs) fc.theirs.text else fc.ours.text; │ │1044 - } │ │1045 - if (std.mem.eql(u8, name, "tags")) { │ │1046 - const fc = if (conflict.tags) |*f| f else return null; │ │1047 - return if (theirs) fc.theirs.text else fc.ours.text; │ │1048 - } │ │1049 - if (std.mem.startsWith(u8, name, "d")) { │ │1050 - const desc = if (conflict.description) |*d| d else return null; │ │1051 - const hunk_index = std.fmt.parseInt(usize, name[1..], 10) catch return null; │ │1052 - var seen: usize = 0; │ │1053 - for (desc.chunks) |chunk| switch (chunk) { │ │1054 - .conflict => |hunk| { │ │1055 - if (seen == hunk_index) return (if (theirs) hunk.theirs else hunk.ours) orelse ""; │ │1056 - seen += 1; │ │1057 - }, │ │1058 - else => {}, │ │1059 - }; │ │1060 - } │ │1061 - return null; │ │1062 - } │ │1063 - │ │1035 fn addRow(allocator: std.mem.Allocator, box: *wgt.Box(Widget), text: []const u8, bottom_label: []const u8, link: []const u8) !void { │ │1036 var row = try wgt.TextBox.init(allocator, text, .{ .border_style = .hidden, .rounded_corners = true, .wrap_kind = .word, .bottom_label = bottom_label });│ │1037 errdefer row.deinit(allocator); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │1236 .text_input => |*ti| try self.session.text_inputs.put(inputs_arena, ti.getFocus().id, ti), │ │1237 else => {}, │ │1238 }; │ │1268 - │ │1269 - // on an edit page, register the thread's content as the inputs' │ │1270 - // page-constant initial values, which the web overlay renders │ │1271 - // into them. │ │1272 - if (self.data.view == .edit) { │ │1273 - if (self.data.selectedThread()) |entry| { │ │1274 - const fields = form.children.values(); │ │1275 - try self.session.input_values.put(inputs_arena, fields[title_field_index].widget.text_input.getFocus().id, entry.record.event.title); │ │1276 - try self.session.input_values.put(inputs_arena, fields[tags_field_index].widget.text_input.getFocus().id, entry.record.event.tags); │ │1277 - try self.session.input_values.put(inputs_arena, fields[description_field_index].widget.text_input.getFocus().id, entry.record.event.description);│ │1278 - } │ │1279 - } │ │1280 - │ │1281 - if (self.data.view == .edit_comment) { │ │1282 - if (self.data.comment_page) |page| { │ │1283 - const body = &form.children.values()[comment_body_field_index].widget.text_input; │ │1284 - try self.session.input_values.put(inputs_arena, body.getFocus().id, page.selected.comment.event.body); │ │1285 - } │ │1286 - } │ │1287 - │ │1288 - // the resolve form's inputs prefill from the picked side, which │ │1289 - // is url state and so page-constant like the edit values above │ │1290 - if (supports_conflicts and self.data.view == .resolve) { │ │1291 - for (form.children.values()) |*child| switch (child.widget) { │ │1292 - .text_input => |*ti| if (self.resolvePrefill(ti.options.name)) |value| { │ │1293 - try self.session.input_values.put(inputs_arena, ti.getFocus().id, value); │ │1294 - }, │ │1295 - else => {}, │ │1296 - }; │ │1297 - } │ │1239 } │ │1240 │ │1241 try self.box.build(allocator, constraint, root_focus); │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │1498 │ │1499 const content = try generateHtml(allocator, &root, &session); │ │1500 defer allocator.free(content); │ │1501 - const overlay = try generateOverlay(allocator, &root, &session); │ │1502 - defer allocator.free(overlay); │ │1501 │ │1502 // serialize the snapshot so the wasm side can parse it back without making │ │1503 // a second request. it's embedded raw in a <script type="application/json">│ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯