Files
timeshare/pages/upload.templ
T

146 lines
4.8 KiB
Templ

package pages
import (
"fmt"
"git.hafen.run/lukas/timeshare/components/button"
"git.hafen.run/lukas/timeshare/components/label"
"git.hafen.run/lukas/timeshare/components/radio"
"git.hafen.run/lukas/timeshare/components/toast"
)
type Expiry struct {
DurationCode string
DurationName string
}
templ Upload(expirations []Expiry, uploadedLink string) {
@PageSkeleton("Upload - Time Share") {
if uploadedLink != "" {
@toast.Toast(toast.Props{
Title: "Share Created!",
Description: fmt.Sprintf(`<a class="underline" href="%s">%s</a>`, uploadedLink, uploadedLink),
Variant: toast.VariantSuccess,
Duration: 120000, // 2 min
Position: toast.PositionBottomCenter,
Dismissible: true,
Icon: true,
})
}
<div class="flex flex-col p-10 w-full h-screen justify-center items-center">
<form class="flex flex-col items-center gap-2" method="POST" enctype="multipart/form-data">
<h1 class="text-3xl font-medium pb-4">Time Share Upload</h1>
<input type="file" class="hidden" id="files" name="files" multiple/>
<div class="border-2 border-dashed rounded-xl border-gray-400 flex flex-col justify-center items-center p-10" id="drop_zone">
<p id="desc" class="w-[39ch] text-center">Drop files onto here or click to upload</p>
</div>
<script>
let drop_zone = document.getElementById("drop_zone");
let desc = document.getElementById("desc");
let fileInput = document.getElementById("files");
function updateDescription(len) {
desc.innerText = `${len} File`
if (len > 1) {
desc.innerText += "s"
}
desc.innerText += " Attached"
}
fileInput.addEventListener("change", () => {
updateDescription(fileInput.files.length);
});
drop_zone.addEventListener("click", () => fileInput.click());
drop_zone.addEventListener("dragover", (e) => {
e.preventDefault();
drop_zone.classList.add('dragover');
});
drop_zone.addEventListener("dragleave", (e) => {
e.preventDefault();
drop_zone.classList.remove('dragover');
});
drop_zone.addEventListener("drop", async (ev) => {
ev.preventDefault();
drop_zone.classList.remove('dragover');
const items = ev.dataTransfer?.items;
if (!items) return;
const collected = [];
const readEntries = (reader) => new Promise((resolve, reject) => reader.readEntries(resolve, reject));
const getFile = (entry) => new Promise((resolve, reject) => entry.file(resolve, reject));
async function traverse(entry, path = "") {
if (entry.isFile) {
const file = await getFile(entry);
Object.defineProperty(file, "webkitRelativePath", {
value: path + file.name,
configurable: true });
collected.push(file);
} else if (entry.isDirectory) {
const reader = entry.createReader();
const prefix = path + entry.name + "/";
let entries;
do {
entries = await readEntries(reader);
for (const child of entries) {
await traverse(child, prefix);
}
} while (entries.length > 0);
}
}
const tasks = [];
for (let i = 0; i < items.length; i++) {
const entry = items[i].webkitGetAsEntry();
if (entry) {
tasks.push(traverse(entry));
} else {
const file = items[i].getAsFile();
if (file) collected.push(file);
}
}
await Promise.all(tasks);
const dt = new DataTransfer();
collected.forEach(f => dt.items.add(f));
fileInput.files = dt.files;
updateDescription(fileInput.files.length);
});
</script>
<style>.dragover {border-color: #00C950;}</style>
<div class="flex flex-col gap-3 w-full">
<p>Expiration:</p>
<div class="pl-2 flex flex-col gap-3">
for i, expiry := range expirations {
<div class="flex items-start gap-3">
@radio.Radio(radio.Props{
ID: expiry.DurationCode,
Name: "expiry",
Value: expiry.DurationCode,
Checked: i == 0,
})
@label.Label(label.Props{
For: expiry.DurationCode,
}) {
{ expiry.DurationName }
}
</div>
}
</div>
@button.Button(button.Props{
Type: "submit",
}) {
Upload
}
</div>
</form>
</div>
}
}