aboutsummaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2026-05-28 16:30:26 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2026-05-28 16:30:26 +0200
commitcd32a3ca0173676ed31486b5fa4dbd8c744cdec5 (patch)
treea9d0888c7a0e425ef8006cc9aade5889b78c074c /src/frontend
parente749e2ccf97e6e7a2d1c124c4e5bed688e4c06f2 (diff)
implement frontend framework
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/Component.zig30
-rw-r--r--src/frontend/Document.zig46
-rw-r--r--src/frontend/File.zig41
-rw-r--r--src/frontend/Head.zig58
-rw-r--r--src/frontend/Minifier.zig168
-rw-r--r--src/frontend/root.zig13
-rw-r--r--src/frontend/web/hello-world/index.css7
-rw-r--r--src/frontend/web/hello-world/index.html6
-rw-r--r--src/frontend/web/hello-world/index.js3
-rw-r--r--src/frontend/web/index.css4
-rw-r--r--src/frontend/web/index.html3
-rw-r--r--src/frontend/z-component.js16
12 files changed, 0 insertions, 395 deletions
diff --git a/src/frontend/Component.zig b/src/frontend/Component.zig
deleted file mode 100644
index d90ed3b..0000000
--- a/src/frontend/Component.zig
+++ /dev/null
@@ -1,30 +0,0 @@
-const std = @import("std");
-
-const File = @import("File.zig");
-
-const Self = @This();
-
-name: []const u8,
-parent_dir: []const u8,
-
-pub fn path(p: []const u8) Self {
- const name = p[if (std.mem.lastIndexOfScalar(
- u8,
- std.mem.trim(u8, p, "/"),
- '/',
- )) |index| index + 1 else 0..];
-
- return .{
- .name = name,
- .parent_dir = p,
- };
-}
-
-pub fn to_html_string(comptime self: Self) []const u8 {
- const html: File.Html = .minify(self.parent_dir ++ "/index.html");
- const js: File.Script = .minify(self.parent_dir ++ "/index.js");
- const css: File.Style = .minify(self.parent_dir ++ "/index.css");
- return "<template id=\"--" ++ self.name ++ "\">" ++ css.to_html_string() ++ html.to_html_string() ++ js.to_html_string() ++ "</template>";
-}
-
-test {}
diff --git a/src/frontend/Document.zig b/src/frontend/Document.zig
deleted file mode 100644
index 0ba46b1..0000000
--- a/src/frontend/Document.zig
+++ /dev/null
@@ -1,46 +0,0 @@
-const std = @import("std");
-
-const Component = @import("Component.zig");
-const Head = @import("Head.zig");
-const File = @import("File.zig");
-
-const Self = @This();
-
-components: []const Component,
-head: Head,
-styles: []const File.Style,
-contents: []const File.Html,
-
-pub const empty: Self = .{
- .head = .empty,
- .components = &.{},
- .styles = &.{},
- .contents = &.{},
-};
-
-pub fn to_string(comptime self: Self) []const u8 {
- comptime var content: []const u8 = "<!DOCTYPE html><html>";
- content = content ++ comptime self.head.to_html_string(self.components, self.styles);
- content = content ++ "<body>";
-
- inline for (self.contents) |c| {
- content = content ++ comptime c.to_html_string();
- }
-
- content = content ++ "</body></html>";
-
- return content;
-}
-
-test {
- const document: Self = comptime .{
- .head = .default("test"),
- .components = &.{
- .path("./web/hello-world"),
- },
- .styles = &.{},
- .contents = &.{.minify("./web/index.html")},
- };
-
- std.debug.print("{s}", .{document.to_string()});
-}
diff --git a/src/frontend/File.zig b/src/frontend/File.zig
deleted file mode 100644
index fac6a03..0000000
--- a/src/frontend/File.zig
+++ /dev/null
@@ -1,41 +0,0 @@
-const Minifier = @import("Minifier.zig");
-
-pub fn File(comptime tag: ?[]const u8, comptime minifier: Minifier) type {
- const opening = if (tag) |t| "<" ++ t ++ ">" else "";
- const closing = if (tag) |t| "</" ++ t ++ ">" else "";
-
- return struct {
- file: []const u8,
- do_minify: bool,
-
- pub fn path(comptime p: []const u8) @This() {
- return .{
- .file = p,
- .do_minify = false,
- };
- }
-
- pub fn minify(comptime p: []const u8) @This() {
- return .{
- .file = p,
- .do_minify = true,
- };
- }
-
- pub fn to_html_string(comptime self: @This()) []const u8 {
- return opening ++ (if (self.do_minify)
- minifier.minify(@embedFile(self.file))
- else
- @embedFile(self.file)) ++ closing;
- }
- };
-}
-
-/// When using regex in Javascript the spaces
-/// might get trimmed since /re/ is a awful syntax
-/// I don't what to add a rule for it currently,
-/// Since a single `/` is a operator but if there are two on one line
-/// it is a regex.
-pub const Script = File("script", .js);
-pub const Style = File("style", .css);
-pub const Html = File(null, .html);
diff --git a/src/frontend/Head.zig b/src/frontend/Head.zig
deleted file mode 100644
index 0eb090f..0000000
--- a/src/frontend/Head.zig
+++ /dev/null
@@ -1,58 +0,0 @@
-const File = @import("File.zig");
-const Component = @import("Component.zig");
-
-const z_component_code: File.Script = .minify("z-component.js");
-
-pub const Meta = struct {
- name: []const u8,
- content: []const u8,
-
- pub fn to_html_string(comptime self: @This()) []const u8 {
- return "<meta name=\"" ++ self.name ++ "\" content=\"" ++ self.content ++ "\">";
- }
-};
-
-title: []const u8,
-meta: []const Meta,
-
-pub const empty: @This() = .{
- .title = "",
- .meta = &.{},
-};
-
-pub fn default(comptime title: []const u8) @This() {
- return .{
- .title = title,
- .meta = &.{
- .{
- .name = "viewport",
- .content = "width=device-width, initial-scale=1.0",
- },
- },
- };
-}
-
-pub fn to_html_string(
- comptime self: @This(),
- comptime components: []const Component,
- comptime styles: []const File.Style,
-) []const u8 {
- var content: []const u8 = "<head>" ++ z_component_code.to_html_string();
-
- content = content ++ "<title>" ++ self.title ++ "</title>";
-
- inline for (components) |component| {
- content = content ++ comptime component.to_html_string();
- }
-
- inline for (styles) |style| {
- content = content ++ comptime style.to_html_string();
- }
-
- inline for (self.meta) |meta| {
- content = content ++ comptime meta.to_html_string();
- }
-
- content = content ++ "</head>";
- return content;
-}
diff --git a/src/frontend/Minifier.zig b/src/frontend/Minifier.zig
deleted file mode 100644
index 65dd9fb..0000000
--- a/src/frontend/Minifier.zig
+++ /dev/null
@@ -1,168 +0,0 @@
-const std = @import("std");
-
-/// A string contained in quotes will not be changed in any form.
-quotes: []const u8,
-
-/// This character is used to escape in strings.
-escape: ?u8,
-
-/// A delimiter does not need any padding around it.
-delimiters: []const u8,
-
-/// Kinds of comments, will be removed in the output.
-comments: []const struct { []const u8, []const u8 },
-
-pub const html: @This() = .{
- .quotes = "\"'",
- .escape = null,
- .delimiters = "<>",
- .comments = &.{.{ "<!--", "-->" }},
-};
-
-pub const js: @This() = .{
- .quotes = "\"'`",
- .escape = '\\',
- .delimiters = "+-*,.:;[](){}=&|^",
- .comments = &.{ .{ "//", "\n" }, .{ "/*", "*/" } },
-};
-
-pub const css: @This() = .{
- .quotes = "\"'",
- .escape = '\\',
- .delimiters = ":;{}",
- .comments = &.{.{ "/*", "*/" }},
-};
-
-fn skip(comptime source: *[]const u8, comptime len: usize) void {
- source.* = (source.*)[len..];
-}
-
-fn push(
- comptime source: *[]const u8,
- comptime target: *[]const u8,
- comptime len: usize,
-) void {
- target.* = target.* ++ (source.*)[0..len];
- skip(source, len);
-}
-
-pub fn minify(
- comptime self: *const @This(),
- comptime c: []const u8,
-) []const u8 {
- @setEvalBranchQuota(c.len * 100);
- var content = std.mem.trimStart(u8, c, &std.ascii.whitespace);
- var block: []const u8 = "";
-
- while (content.len > 0) {
- const had_comment: bool = cmt: {
- inline for (self.comments) |comment| {
- const start, const end = comment;
-
- if (std.mem.startsWith(u8, content, start)) {
- skip(&content, start.len);
- skip(&content, if (std.mem.indexOf(u8, content, end)) |l| l + end.len else content.len);
- break :cmt true;
- }
- }
- break :cmt false;
- };
-
- if (had_comment) {} else if (std.mem.indexOfScalar(u8, self.quotes, content[0])) |_| {
- const quote = content[0];
- push(&content, &block, 1);
- while (content.len > 0) {
- if (content[0] == self.escape) {
- push(&content, &block, 2);
- } else if (content[0] == quote) {
- push(&content, &block, 1);
- break;
- }
- push(&content, &block, 1);
- }
- } else {
- push(&content, &block, 1);
- }
-
- const was_trimmed = content.len > 0 and std.ascii.isWhitespace(content[0]);
- content = std.mem.trimStart(u8, content, &std.ascii.whitespace);
- if (was_trimmed and
- block.len > 0 and
- content.len > 0 and
- std.mem.indexOfScalar(u8, self.delimiters, block[block.len - 1]) == null and
- std.mem.indexOfScalar(u8, self.delimiters, content[0]) == null)
- {
- block = block ++ " ";
- }
- }
-
- return block;
-}
-
-test "html" {
- const buffer: []const u8 =
- \\<html>
- \\ <head>
- \\ <title>Some Title</title>
- \\ </head>
- \\ <body>
- \\ <z-component type="something here" tag="1 2 3"> 123 </z-component>
- \\ <!-- some comment here -->
- \\ Hello World!
- \\ </body>
- \\</html>
- ;
-
- try std.testing.expectEqualStrings(
- "<html><head><title>Some Title</title></head><body><z-component type=\"something here\" tag=\"1 2 3\">123</z-component>Hello World!</body></html>",
- comptime html.minify(buffer),
- );
-}
-
-test "css" {
- const buffer: []const u8 =
- \\body {
- \\ background: #fff;
- \\ color: red;
- \\}
- \\
- \\#content:first {
- \\ user-select: none;
- \\ /* comment */
- \\ content: ' ';
- \\ padding: 5px 5px;
- \\}
- ;
-
- try std.testing.expectEqualStrings(
- "body{background:#fff;color:red;}#content:first{user-select:none;content:' ';padding:5px 5px;}",
- comptime css.minify(buffer),
- );
-}
-
-test "js" {
- const buffer: []const u8 =
- \\class extends HTMLElement {
- \\ // comment here
- \\ constructor() {
- \\ super();
- \\ this.attachShadow({ mode: 'open' });
- \\ }
- \\
- \\ /*
- \\ * Mulitline
- \\ */
- \\ connectedCallback() {
- \\ const type = this.getAttribute('type');
- \\ const template = document.getElementById(`--${type}`);
- \\ const node = document.importNode(template.content, true);
- \\ this.shadowRoot.appendChild(node);
- \\ }
- \\}
- ;
-
- try std.testing.expectEqualStrings(
- "class extends HTMLElement{constructor(){super();this.attachShadow({mode:'open'});}connectedCallback(){const type=this.getAttribute('type');const template=document.getElementById(`--${type}`);const node=document.importNode(template.content,true);this.shadowRoot.appendChild(node);}}",
- comptime js.minify(buffer),
- );
-}
diff --git a/src/frontend/root.zig b/src/frontend/root.zig
deleted file mode 100644
index 8ff1055..0000000
--- a/src/frontend/root.zig
+++ /dev/null
@@ -1,13 +0,0 @@
-//! Implementation of the frontend contains mainly javascript files
-//! which will be embedded right into the ELF file to improve deployment.
-
-const std = @import("std");
-pub const Component = @import("Component.zig");
-pub const Document = @import("Document.zig");
-pub const File = @import("File.zig");
-pub const Head = @import("Head.zig");
-pub const Minifier = @import("Minifier.zig");
-
-test {
- _ = std.testing.refAllDecls(@This());
-}
diff --git a/src/frontend/web/hello-world/index.css b/src/frontend/web/hello-world/index.css
deleted file mode 100644
index 41b0b29..0000000
--- a/src/frontend/web/hello-world/index.css
+++ /dev/null
@@ -1,7 +0,0 @@
-#container {
- background: #efefef;
- padding: 10px;
- border-radius: 4px;
- user-select: none;
- cursor: pointer;
-}
diff --git a/src/frontend/web/hello-world/index.html b/src/frontend/web/hello-world/index.html
deleted file mode 100644
index 047a283..0000000
--- a/src/frontend/web/hello-world/index.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<div id="container" onclick="clicked()">
- Click Me!
- <z-component type="box">
- <span slot="title">Hello World!<span>
- </z-component>
-</div>
diff --git a/src/frontend/web/hello-world/index.js b/src/frontend/web/hello-world/index.js
deleted file mode 100644
index 8e55c52..0000000
--- a/src/frontend/web/hello-world/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-function clicked() {
- console.log('clicked');
-}
diff --git a/src/frontend/web/index.css b/src/frontend/web/index.css
deleted file mode 100644
index a93ea47..0000000
--- a/src/frontend/web/index.css
+++ /dev/null
@@ -1,4 +0,0 @@
-body {
- padding: 0;
- margin: 0;
-}
diff --git a/src/frontend/web/index.html b/src/frontend/web/index.html
deleted file mode 100644
index 646cdb0..0000000
--- a/src/frontend/web/index.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<z-component type="hello-world">
- <p slot="ur-mom">lulululu</p>
-</z-component>
diff --git a/src/frontend/z-component.js b/src/frontend/z-component.js
deleted file mode 100644
index 5e430b5..0000000
--- a/src/frontend/z-component.js
+++ /dev/null
@@ -1,16 +0,0 @@
-customElements.define(
- "z-component",
- class extends HTMLElement {
- constructor() {
- super();
- this.attachShadow({ mode: 'open' });
- }
-
- connectedCallback() {
- const type = this.getAttribute('type');
- const template = document.getElementById(`--${type}`);
- const node = document.importNode(template.content, true);
- this.shadowRoot.appendChild(node);
- }
- }
-);