mkdir dialog in drive pages
This commit is contained in:
parent
7d362f0708
commit
38f91dd890
3 changed files with 119 additions and 25 deletions
|
@ -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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue