aboutsummaryrefslogblamecommitdiffstats
path: root/src/web/web.zig
blob: 184a1a37ecb943abfb9630a9c6131adf14be5924 (plain) (tree)












































































































                                                                                                                                                                   
pub const Templates = std.StringHashMap(Template);

pub var templates: Templates = undefined;

pub fn start(app: *App) !void {
    const allocator = app.allocator;

    var server = try httpz.ServerCtx(*const Dispatcher, *Env).init(allocator, .{
        .address = "0.0.0.0",
        .port = 5882,
    }, undefined);
    defer server.deinit();

    templates = Templates.init(allocator);
    defer {
        var it = templates.valueIterator();
        while (it.next()) |t| {
            t.deinit(allocator);
        }
        templates.deinit();
    }

    inline for (config.templates) |template| {
        try templates.put(template, try loadTemplate(allocator, template));
    }

    server.dispatcher(Dispatcher.dispatch);

    var router = server.router();
    {
        var routes = router.group("", .{ .ctx = &Dispatcher{ .app = app } });
        routes.get("/", index);
        routes.get("/about", about);
        routes.get("/drafts/:id", @import("drafts/show.zig").handler);
        routes.get("/drafts/:id/pick", @import("drafts/pick.zig").handler);
        routes.get("/leagues/:id", @import("leagues/show.zig").handler);
        routes.post("/leagues", @import("leagues/create.zig").handler);
        routes.get("/invites/:id", @import("leagues/invite.zig").handler);
    }

    // use get/post/put/head/patch/options/delete
    // you can also use "all" to attach to all methods

    // start the server in the current thread, blocking.
    try server.listen();
}

fn pick(_: *Env, req: *httpz.Request, res: *httpz.Response) !void {
    try render("pick", req, res);
}

fn about(_: *Env, req: *httpz.Request, res: *httpz.Response) !void {
    // try render(templates.get("about").?, req, res);
    try renderWithData("about", .{ .title = "foo" }, req, res);
}

fn index(_: *Env, req: *httpz.Request, res: *httpz.Response) !void {
    try render("index", req, res);
}

fn loadTemplate(allocator: std.mem.Allocator, comptime template_name: []const u8) !Template {
    return switch (try mustache.parseText(allocator, @embedFile("../views/" ++ template_name ++ ".mustache"), .{}, .{ .copy_strings = false })) {
        .success => |t| t,
        .parse_error => @panic("layout parse error"),
    };
}

fn loadTemplateFile(allocator: std.mem.Allocator, template_name: []const u8) !Template {
    const file = std.fs.cwd().openFile(try std.fmt.allocPrint(allocator, "src/views/{s}.mustache", .{template_name}), .{}) catch @panic("could not find template");
    defer file.close();
    const template_bytes = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch @panic("couldn't read template file ");

    return switch (try mustache.parseText(allocator, template_bytes, .{}, .{ .copy_strings = false })) {
        .success => |t| t,
        .parse_error => @panic("layout parse error"),
    };
}

pub fn renderWithDataPartials(template_name: []const u8, partials: anytype, data: anytype, req: *httpz.Request, res: *httpz.Response) !void {
    var template: Template = undefined;
    if (config.dev) {
        template = try loadTemplateFile(res.arena, template_name);
    } else {
        template = templates.get(template_name).?;
    }
    const content = try mustache.allocRenderPartials(res.arena, template, partials, data);
    if (req.header("hx-request")) |_| {
        res.body = content;
    } else {
        res.body = try mustache.allocRender(res.arena, templates.get("layout").?, .{ .content = content });
    }
}

pub fn renderWithData(template_name: []const u8, data: anytype, req: *httpz.Request, res: *httpz.Response) !void {
    try renderWithDataPartials(template_name, .{}, data, req, res);
}

pub fn render(template_name: []const u8, req: *httpz.Request, res: *httpz.Response) !void {
    try renderWithData(template_name, .{}, req, res);
}

const config = @import("config");
const App = @import("../app.zig").App;
const Env = @import("../env.zig").Env;
const httpz = @import("httpz");
const mustache = @import("mustache");
const Template = mustache.Template;
const std = @import("std");
const Dispatcher = @import("dispatcher.zig").Dispatcher;