diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/web/component/navigation/index.css | 66 | ||||
| -rw-r--r-- | src/web/component/navigation/index.html | 11 | ||||
| -rw-r--r-- | src/web/component/navigation/index.js | 11 | ||||
| -rw-r--r-- | src/web/component/navigation/root.zig | 8 | ||||
| -rw-r--r-- | src/web/component/root.zig | 1 | ||||
| -rw-r--r-- | src/web/index.css | 1 | ||||
| -rw-r--r-- | src/web/index.html | 2 | ||||
| -rw-r--r-- | src/z/js/parser/builtin.zig | 17 | ||||
| -rw-r--r-- | src/z/js/parser/lexical_grammar.zig | 3 | ||||
| -rw-r--r-- | src/z/js/parser/parser.zig | 117 | ||||
| -rw-r--r-- | src/z/js/parser/result.zig | 4 | ||||
| -rw-r--r-- | src/z/js/parser/root.zig | 11 | ||||
| -rw-r--r-- | src/z/z.js | 21 |
13 files changed, 272 insertions, 1 deletions
diff --git a/src/web/component/navigation/index.css b/src/web/component/navigation/index.css new file mode 100644 index 0000000..836e3b5 --- /dev/null +++ b/src/web/component/navigation/index.css @@ -0,0 +1,66 @@ +#toggle { + --radius-open: 200px; + + position: absolute; + right: 10px; + bottom: 10px; + width: 45px; + height: 45px; + border-radius: 100%; + background: red; + z-index: 500; + cursor: pointer; + text-align: center; + align-content: center; + transition: + border-radius 0.1s ease, + right 0.1s ease, + bottom 0.1s ease, + width 0.1s ease, + height 0.1s ease; + + .bi { + baseline-shift: -2px; + } + + .items { + position: relative; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + } + + .item { + display: none; + width: 45px; + height: 45px; + border-radius: 100%; + background: blue; + position: absolute; + right: calc(cos(18deg * var(--index)) * var(--radius-open)); + bottom: calc(sin(18deg * var(--index)) * var(--radius-open)); + font-size: calc(var(--index) * 1px); + } + + .item { + --index: sibling-index(); + } +} + +#toggle.open { + width: var(--radius-open); + height: var(--radius-open); + bottom: 0px; + right: 0px; + border-radius: 0px; + border-top-left-radius: 250px; + + .bi { + display: none; + } + + .item { + display: block; + } +} diff --git a/src/web/component/navigation/index.html b/src/web/component/navigation/index.html new file mode 100644 index 0000000..b3b5ce0 --- /dev/null +++ b/src/web/component/navigation/index.html @@ -0,0 +1,11 @@ +<div id="toggle"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-three-dots-vertical" viewBox="0 0 16 16"> + <path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0"/> + </svg> + <div class="items"> + <div class="item"></div> + <div class="item"></div> + <div class="item"></div> + <div class="item"></div> + </div> +</div> diff --git a/src/web/component/navigation/index.js b/src/web/component/navigation/index.js new file mode 100644 index 0000000..2c996a0 --- /dev/null +++ b/src/web/component/navigation/index.js @@ -0,0 +1,11 @@ + +const toggle = Z.by_id('toggle'); + +toggle.onclick = (event) => { + toggle.classList.toggle('open'); + event.stopPropagation(); +}; + +document.addEventListener('click', () => { + toggle.classList.remove('open'); +}); diff --git a/src/web/component/navigation/root.zig b/src/web/component/navigation/root.zig new file mode 100644 index 0000000..919cddb --- /dev/null +++ b/src/web/component/navigation/root.zig @@ -0,0 +1,8 @@ +const z = @import("z"); + +pub const component: z.Component = .{ + .name = .navigation, + .body = @embedFile("index.html"), + .style = @embedFile("index.css"), + .script = @embedFile("index.js"), +}; diff --git a/src/web/component/root.zig b/src/web/component/root.zig index 226f3f7..ba2f565 100644 --- a/src/web/component/root.zig +++ b/src/web/component/root.zig @@ -3,4 +3,5 @@ const z = @import("z"); pub const components: []const z.Component = &.{ @import("image/root.zig").component, @import("timeline/root.zig").component, + @import("navigation/root.zig").component, }; diff --git a/src/web/index.css b/src/web/index.css index 6b1927f..bcdecae 100644 --- a/src/web/index.css +++ b/src/web/index.css @@ -1,6 +1,7 @@ html { height: 100vh; width: 100vw; + overflow: hidden; } body { diff --git a/src/web/index.html b/src/web/index.html index d2bc6fe..bcbb165 100644 --- a/src/web/index.html +++ b/src/web/index.html @@ -1,2 +1,4 @@ <z-component type="timeline" id="timeline"> </z-component> +<z-component type="navigation" id="navigation"> +</z-component> diff --git a/src/z/js/parser/builtin.zig b/src/z/js/parser/builtin.zig new file mode 100644 index 0000000..fc96fc3 --- /dev/null +++ b/src/z/js/parser/builtin.zig @@ -0,0 +1,17 @@ +const std = @import("std"); + +const parser = @import("root.zig"); +const Parser = parser.Parser; +const Result = parser.Result; + +pub fn literal(lit: []const u8) Parser(void) { + return .fromType(struct { + pub fn parse(buffer: []const u8) !Result(void) { + if (std.mem.startsWith(u8, buffer, lit)) { + return .{ void{}, buffer[lit.len..] }; + } + + return error.Literal; + } + }); +} diff --git a/src/z/js/parser/lexical_grammar.zig b/src/z/js/parser/lexical_grammar.zig new file mode 100644 index 0000000..7060766 --- /dev/null +++ b/src/z/js/parser/lexical_grammar.zig @@ -0,0 +1,3 @@ +const parser = @import("root.zig"); +const Result = parser.Result; + diff --git a/src/z/js/parser/parser.zig b/src/z/js/parser/parser.zig new file mode 100644 index 0000000..b73d895 --- /dev/null +++ b/src/z/js/parser/parser.zig @@ -0,0 +1,117 @@ +const std = @import("std"); + +const mod = @import("root.zig"); +const Result = mod.Result; + +pub fn Parser(T: type) type { + const R = Result(T); + + return struct { + parse: *const fn ([]const u8) anyerror!R, + + pub fn parseAll(self: *const @This(), buffer: []const u8) !T { + const value, const next = try self.parse(buffer); + + if (next.len > 0) { + return error.NotExhaustive; + } + + return value; + } + + pub fn fromType(P: type) @This() { + return .{ .parse = P.parse }; + } + + pub fn variants(V: type) @This() { + if (@typeInfo(T) != .@"union") { + @compileError("variants is only allowed with an union as result type"); + } + + return .{ + .parse = struct { + fn parse(buffer: []const u8) !R { + inline for (std.meta.fields(T)) |field| { + if (@field(V, field.name).parse(buffer)) |result| { + const value, const next = result; + return .{ + @unionInit(T, field.name, value), + next, + }; + } else |_| { } + } + + return error.Variants; + } + }.parse, + }; + } + + pub fn any(P: type, comptime parsers: []const struct { Parser(P), T }) @This() { + return .{ + .parse = struct { + fn parse(buffer: []const u8) !R { + inline for (parsers) |pair| { + const parser, const value = pair; + + if (parser.parse(buffer)) |result| { + _, const next = result; + return .{ value, next }; + } else |_| { } + } + return error.Any; + } + }.parse, + }; + } + }; +} + +test "variants" { + const Char = union(enum) { + upper: u8, + lower: u8, + space: void, + }; + + const parser: Parser(Char) = .variants(struct { + const upper: Parser(u8) = .any(void, &.{ + .{ mod.builtin.literal("A"), 'A' }, + .{ mod.builtin.literal("B"), 'B' }, + }); + + const lower: Parser(u8) = .any(void, &.{ + .{ mod.builtin.literal("a"), 'a' }, + .{ mod.builtin.literal("b"), 'b' }, + }); + + const space: Parser(void) = mod.builtin.literal(" "); + }); + + { + const result = try parser.parseAll("a"); + try std.testing.expect(result.lower == 'a'); + } + + { + const result = try parser.parseAll("b"); + try std.testing.expect(result.lower == 'b'); + } + + { + const result = try parser.parseAll("A"); + try std.testing.expect(result.upper == 'A'); + } + + { + const result = try parser.parseAll("B"); + try std.testing.expect(result.upper == 'B'); + } + + { + const result = try parser.parseAll(" "); + try std.testing.expect(result == .space); + } + + try std.testing.expect(parser.parseAll("c") == error.Variants); +} diff --git a/src/z/js/parser/result.zig b/src/z/js/parser/result.zig new file mode 100644 index 0000000..5cc5878 --- /dev/null +++ b/src/z/js/parser/result.zig @@ -0,0 +1,4 @@ + +pub fn Result(T: type) type { + return struct { T, []const u8 }; +} diff --git a/src/z/js/parser/root.zig b/src/z/js/parser/root.zig new file mode 100644 index 0000000..a6be9ca --- /dev/null +++ b/src/z/js/parser/root.zig @@ -0,0 +1,11 @@ +const std = @import("std"); + +pub const lexical_grammar = @import("lexical_grammar.zig"); + +pub const Result = @import("result.zig").Result; +pub const Parser = @import("parser.zig").Parser; +pub const builtin = @import("builtin.zig"); + +test { + _ = std.testing.refAllDecls(@This()); +} @@ -1,10 +1,14 @@ class ZComponent extends HTMLElement { + static observedAttributes = [ 'type' ]; + constructor() { super(); this.attachShadow({ mode: 'open' }); + this.onconnected = () => {}; + this.ondisconnected = () => {}; } - connectedCallback() { + build() { const type = this.getAttribute('type'); if (type == null) { @@ -22,6 +26,21 @@ class ZComponent extends HTMLElement { Zenv.constructors[`component__${type}`](new Zenv(this)); } + + attributeChangedCallback(name, previous, current) { + if (name == 'type') { + this.shadowRoot.innerHTML = ''; + this.build() + } + } + + connectedCallback() { + this.onconnected(); + } + + disconnectedCallback() { + this.ondisconnected(); + } } class Zenv { |