╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ──╮ │src/web.zig│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │557 } │ │558 │ │559 return try out.toOwnedSlice(allocator); │ │560 +} │ │561 + │ │562 +fn colorEql(a: ?Grid.Color, b: ?Grid.Color) bool { │ │563 + if (a) |av| return if (b) |bv| av.eql(bv) else false; │ │564 + return b == null; │ │565 +} │ │566 + │ │567 +// builds an HTML ` style="color:#rrggbb;background-color:#rrggbb"` attribute │ │568 +// from a cell's fg/bg into `buf`, omitting whichever color is unset. returns an │ │569 +// empty slice when neither is set. │ │570 +fn styleAttr(buf: []u8, fg: ?Grid.Color, bg: ?Grid.Color) []const u8 { │ │571 + if (fg == null and bg == null) return buf[0..0]; │ │572 + const prefix = " style=\""; │ │573 + @memcpy(buf[0..prefix.len], prefix); │ │574 + var i: usize = prefix.len; │ │575 + if (fg) |c| { │ │576 + const s = std.fmt.bufPrint(buf[i..], "color:#{x:0>2}{x:0>2}{x:0>2};", .{ c.r, c.g, c.b }) catch return buf[0..0]; │ │577 + i += s.len; │ │578 + } │ │579 + if (bg) |c| { │ │580 + const s = std.fmt.bufPrint(buf[i..], "background-color:#{x:0>2}{x:0>2}{x:0>2};", .{ c.r, c.g, c.b }) catch return buf[0..0];│ │581 + i += s.len; │ │582 + } │ │583 + buf[i] = '"'; │ │584 + i += 1; │ │585 + return buf[0..i]; │ │586 } │ │587 │ │588 fn cellFocusId(focus: *Focus, x: usize, y: usize) ?usize { │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯