diff options
Diffstat (limited to 'src/html/Element.zig')
| -rw-r--r-- | src/html/Element.zig | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/html/Element.zig b/src/html/Element.zig new file mode 100644 index 0000000..8ecf31e --- /dev/null +++ b/src/html/Element.zig @@ -0,0 +1,104 @@ +const Self = @This(); + +pub const Content = union(enum) { + elements: []const Self, + string: []const u8, + void: void, + + pub fn content(string: []const u8) @This() { + return .{ .string = string }; + } + + pub fn children(elements: []const Self) @This() { + return .{ .elements = elements }; + } +}; + +pub const Attribute = struct { + name: []const u8, + value: []const u8, +}; + +tag: []const u8, +attributes: []const Attribute, +content: Content, + +fn attributesFrom(attributes: anytype) []const Attribute { + const T = @TypeOf(attributes); + const info = @typeInfo(T); + + if (info != .@"struct") { + @compileError("struct needed"); + } + + const fields = info.@"struct".fields; + + var attrs: []const Attribute = &.{}; + + for (fields) |field| { + const name = field.name; + const value = @field(attributes, name); + + const next_attr: []const Attribute = &.{ .{ .name = name, .value = value } }; + attrs = attrs ++ next_attr; + } + + return attrs; +} + +pub fn native(name: @EnumLiteral(), attrs: anytype, content: Content) Self { + return .{ + .tag = @tagName(name), + .attributes = attributesFrom(attrs), + .content = content, + }; +} + +pub fn transparent(content: Content) Self { + return .{ + .tag = "", + .attributes = &.{}, + .content = content, + }; +} + +pub fn toHtml(comptime self: Self) []const u8 { + var string: []const u8 = string: { + if (self.tag.len == 0) { + break :string ""; + } + + var string: []const u8 = "<" ++ self.tag; + + inline for (self.attributes) |attr| { + string = string ++ " " ++ attr.name ++ "='" ++ attr.value ++ "'"; + } + + string = string ++ ">"; + + break :string string; + }; + + + switch (self.content) { + .void => {}, + .string => |s| { + string = string ++ s ++ "</" ++ self.tag ++ ">"; + }, + .elements => |els| { + for (els) |el| { + string = string ++ el.toHtml(); + } + + string = string ++ "</" ++ self.tag ++ ">"; + } + } + + string = string ++ if (self.tag.len == 0) "" else "</" ++ self.tag ++ ">"; + + return string; +} + +pub fn toDocument(comptime self: Self) []const u8 { + return "<!DOCTYPE html>" ++ self.toHtml(); +} |