mkdir dialog in drive pages

This commit is contained in:
jaina heartles 2022-12-15 06:32:11 -08:00
parent 7d362f0708
commit 38f91dd890
3 changed files with 119 additions and 25 deletions

View file

@ -18,6 +18,7 @@ pub const routes = .{
controllers.apiEndpoint(cluster.communities.create.page), controllers.apiEndpoint(cluster.communities.create.page),
controllers.apiEndpoint(cluster.communities.create.submit), controllers.apiEndpoint(cluster.communities.create.submit),
controllers.apiEndpoint(drive.details), controllers.apiEndpoint(drive.details),
controllers.apiEndpoint(drive.form),
}; };
const static = struct { const static = struct {
@ -231,6 +232,31 @@ const user_details = struct {
}; };
const drive = struct { const drive = struct {
const dir_tmpl = @embedFile("./web/drive/directory.tmpl.html");
fn servePage(req: anytype, res: anytype, srv: anytype) !void {
const info = try srv.driveGet(req.args.path);
defer util.deepFree(srv.allocator, info);
var breadcrumbs = std.ArrayList([]const u8).init(srv.allocator);
defer breadcrumbs.deinit();
var iter = util.PathIter.from(req.args.path);
while (iter.next()) |p| {
std.log.debug("breadcrumb: {s}", .{p});
try breadcrumbs.append(if (p.len != 0) p else continue);
}
switch (info) {
.dir => |dir| try res.template(.ok, srv, dir_tmpl, .{
.dir = dir,
.breadcrumbs = breadcrumbs.items,
.mount_path = req.mount_path,
.base_drive_path = "drive",
}),
else => unreachable,
}
}
const details = struct { const details = struct {
pub const path = "/drive/:path*"; pub const path = "/drive/:path*";
pub const method = .GET; pub const method = .GET;
@ -239,29 +265,41 @@ const drive = struct {
path: []const u8, path: []const u8,
}; };
pub const dir_tmpl = @embedFile("./web/drive/directory.tmpl.html"); pub fn handler(req: anytype, res: anytype, srv: anytype) !void {
try servePage(req, res, srv);
}
};
const form = struct {
pub const path = "/drive/:path*";
pub const method = .POST;
pub const Args = struct {
path: []const u8,
};
const Action = enum {
mkcol,
};
pub const Body = struct {
action: Action,
data: union(Action) {
mkcol: struct {
name: []const u8,
},
},
};
pub fn handler(req: anytype, res: anytype, srv: anytype) !void { pub fn handler(req: anytype, res: anytype, srv: anytype) !void {
const info = try srv.driveGet(req.args.path); if (req.body.action != req.body.data) return error.BadRequest;
defer util.deepFree(srv.allocator, info); switch (req.body.data) {
.mkcol => |data| {
_ = try srv.driveMkdir(req.args.path, data.name);
// TODO
var breadcrumbs = std.ArrayList([]const u8).init(srv.allocator); try servePage(req, res, srv);
defer breadcrumbs.deinit(); },
var iter = util.PathIter.from(req.args.path);
while (iter.next()) |p| {
std.log.debug("breadcrumb: {s}", .{p});
try breadcrumbs.append(if (p.len != 0) p else continue);
}
switch (info) {
.dir => |dir| try res.template(.ok, srv, dir_tmpl, .{
.dir = dir,
.breadcrumbs = breadcrumbs.items,
.mount_path = req.mount_path,
.base_drive_path = "drive",
}),
else => unreachable,
} }
} }
}; };

View file

@ -17,6 +17,28 @@
</li> </li>
{/for =} {/for =}
</ol> </ol>
<div class="popup-buttons">
<div class="popup" id="mkdir">
<a class="button popup-open" href="#mkdir">
<span class="fa-stack small">
<i class="fa-solid fa-stack-2x fa-folder"></i>
<i class="fa-solid fa-stack-1x fa-inverse fa-plus"></i>
</span>
</a>
<a class="button popup-close" href="#">
<i class="fa-solid fa-xmark"></i>
</a>
<form class="popup-dialog" method="post" enctype="multipart/form-data">
<label>
<div>Create Directory</div>
<input type="text" name="mkcol.name" /> <!-- TODO: Rename this form param -->
</label>
<input type="hidden" name="action" value="mkcol" />
<button type="submit">Create</button>
</form>
</div>
</div>
<table class="directory-listing"> <table class="directory-listing">
{#for .dir.children.? |$child| =} {#for .dir.children.? |$child| =}
<tr> <tr>

View file

@ -1,8 +1,13 @@
@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap');
* { * {
--theme-color: #713c8c; --theme-accent: #713c8c;
--theme-color-highlight: #9b52bf; --theme-accent-highlight: #9b52bf;
--theme-accent-contrast: #fff;
--theme-fg-color: #000;
--theme-bg-color: #fff;
--fa-inverse: var(--theme-accent);
} }
body { body {
@ -92,7 +97,7 @@ form .textinput input:focus-visible{
outline: none; outline: none;
} }
form .textinput:focus-within { form .textinput:focus-within {
outline: solid 2px var(--theme-color); outline: solid 2px var(--theme-accent);
} }
form .textinput span.prefix { form .textinput span.prefix {
user-select: none; user-select: none;
@ -124,14 +129,14 @@ button, a.button {
border-radius: 10px; border-radius: 10px;
border: none; border: none;
color: #fff; color: #fff;
background-color: var(--theme-color); background-color: var(--theme-accent);
font-weight: bold; font-weight: bold;
transition: background-color 0.2s; transition: background-color 0.2s;
cursor: pointer; cursor: pointer;
} }
button:hover, a.button:hover { button:hover, a.button:hover {
background-color: var(--theme-color-highlight); background-color: var(--theme-accent-highlight);
} }
.user-profile img.banner { .user-profile img.banner {
@ -228,3 +233,32 @@ button:hover, a.button:hover {
justify-content: flex-end; justify-content: flex-end;
vertical-align: bottom; vertical-align: bottom;
} }
.drive .buttons a[href="#mkdir"] span.fa-stack {
font-size: 8pt;
vertical-align: bottom;
}
.drive .buttons a[href="#mkdir"] .fa-plus {
position: relative;
bottom: -1px;
}
.popup :is(.popup-close, .popup-dialog) {
display: none;
}
.popup:target .popup-open {
display: none;
}
.popup:target :is(.popup-close, .popup-dialog) {
display: unset;
}
.popup:target .popup-dialog {
position: absolute;
color: var(--theme-fg-color);
background-color: var(--theme-bg-color);
border: 1px solid var(--theme-accent);
}