lib/zen/src/slides/deck.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 const zen = @import("../root.zig");
 4 const print = @import("print.zig");
 5 const script = @import("script.zig");
 6 
 7 const Allocator = std.mem.Allocator;
 8 
 9 pub const Options = struct {
10     deck_class: []const u8 = "zen-slides",
11     slide_class: []const u8 = "zen-slide",
12     frame_class: []const u8 = "zen-slide-frame",
13     badge_class: []const u8 = "zen-slide-badge",
14     id_prefix: []const u8 = "slide",
15     badge: ?[]const u8 = null,
16     runtime: bool = true,
17 };
18 
19 pub const Deck = struct {
20     options: Options = .{},
21     open: bool = false,
22     slide_index: usize = 0,
23     slide_open_start: usize = 0,
24     slide_body_start: usize = 0,
25 
26     pub fn begin(self: *Deck, out: *std.ArrayList(u8), allocator: Allocator) Allocator.Error!void {
27         if (self.open) return;
28         try out.appendSlice(allocator, "<div class=\"");
29         try zen.html.appendAttributeEscaped(out, allocator, self.options.deck_class);
30         try out.appendSlice(allocator, "\" data-zen-slides>\n");
31         self.open = true;
32         try self.openSlide(out, allocator);
33     }
34 
35     pub fn split(self: *Deck, out: *std.ArrayList(u8), allocator: Allocator) Allocator.Error!void {
36         if (!self.open) try self.begin(out, allocator);
37         if (self.empty(out)) return;
38         try out.appendSlice(allocator, "</div>\n</section>\n");
39         try self.openSlide(out, allocator);
40     }
41 
42     pub fn finish(self: *Deck, out: *std.ArrayList(u8), allocator: Allocator) Allocator.Error!void {
43         if (!self.open) return;
44         if (self.empty(out) and self.slide_index > 1) {
45             out.shrinkRetainingCapacity(self.slide_open_start);
46         } else {
47             try out.appendSlice(allocator, "</div>\n</section>\n");
48         }
49         try out.appendSlice(allocator, "</div>\n");
50         try out.appendSlice(allocator, print.stylesheet);
51         if (self.options.runtime) {
52             try out.appendSlice(allocator, script.runtime);
53         }
54         const options = self.options;
55         self.* = .{ .options = options };
56     }
57 
58     fn openSlide(self: *Deck, out: *std.ArrayList(u8), allocator: Allocator) Allocator.Error!void {
59         self.slide_index += 1;
60         self.slide_open_start = out.items.len;
61         try out.appendSlice(allocator, "<section class=\"");
62         try zen.html.appendAttributeEscaped(out, allocator, self.options.slide_class);
63         try out.appendSlice(allocator, "\" id=\"");
64         try zen.html.appendAttributeEscaped(out, allocator, self.options.id_prefix);
65         try out.append(allocator, '-');
66         try appendUsize(out, allocator, self.slide_index);
67         try out.appendSlice(allocator, "\" aria-label=\"Slide ");
68         try appendUsize(out, allocator, self.slide_index);
69         try out.appendSlice(allocator, "\">\n");
70         try out.appendSlice(allocator, "<div class=\"");
71         try zen.html.appendAttributeEscaped(out, allocator, self.options.frame_class);
72         try out.appendSlice(allocator, "\">\n");
73         if (self.options.badge) |badge| {
74             try out.appendSlice(allocator, "<span class=\"");
75             try zen.html.appendAttributeEscaped(out, allocator, self.options.badge_class);
76             try out.appendSlice(allocator, "\" aria-label=\"Non-curated content\">");
77             try zen.html.appendEscaped(out, allocator, badge);
78             try out.appendSlice(allocator, "</span>\n");
79         }
80         self.slide_body_start = out.items.len;
81     }
82 
83     fn empty(self: Deck, out: *const std.ArrayList(u8)) bool {
84         return out.items.len == self.slide_body_start;
85     }
86 };
87 
88 fn appendUsize(out: *std.ArrayList(u8), allocator: Allocator, value: usize) Allocator.Error!void {
89     var buffer: [20]u8 = undefined;
90     const text = std.fmt.bufPrint(&buffer, "{d}", .{value}) catch unreachable;
91     try out.appendSlice(allocator, text);
92 }