treehouse/static/js/dev/picture-upload.js
liquidex 6d3037791a make the command line a bit more accessible by including a :| icon at the bottom
also add a few extra commands for navigating around the house
2024-12-10 20:41:14 +01:00

175 lines
5.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { CommandLine } from "treehouse/command-line.js";
class PictureUpload extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.gotoInit();
this.preview = this.querySelector("img[name='preview']");
this.addEventListener("click", (event) => {
if (event.target == this || event.target.parentElement == this) {
event.preventDefault();
this.focus();
}
});
this.addEventListener("paste", async (event) => {
if (event.clipboardData.items.length != 1) {
console.error("only one item is supported");
return;
}
let item = event.clipboardData.items[0];
await this.paste(item);
});
}
gotoInit() {
this.setState("init");
this.innerHTML = `
<div class="nothing-pasted" tabindex="0">
paste or drop an image here to make a picture out of it
</div>
`;
this.querySelector(".nothing-pasted").focus();
}
async gotoHavePicture(imageType, imageFile) {
this.setState("have-picture");
this.innerHTML = `
<form name="upload" class="have-picture">
<img name="preview" class="pic" alt="preview">
<p>
<span name="preview-width"></span> × <span name="preview-height"></span> px (<span name="file-size"></span>)
</p>
<p>
<label for="label">label</label>
<input name="label" type="text" placeholder="untitled"></input>
</p>
<p>
<label for="compression">compression</label>
<select name="compression">
<option value="Lossless">lossless</option>
</select>
</p>
<button type="submit" name="upload">upload</button>
</div>
`;
let uploadForm = this.querySelector("form[name='upload']");
let preview = this.querySelector("img[name='preview']");
let previewWidth = this.querySelector("[name='preview-width']");
let previewHeight = this.querySelector("[name='preview-height']");
let fileSize = this.querySelector("[name='file-size']");
let label = this.querySelector("[name='label']");
let compression = this.querySelector("[name='compression']");
fileSize.textContent = formatSizeSI(imageFile.size);
label.focus();
let url = URL.createObjectURL(imageFile);
preview.src = url;
createImageBitmap(imageFile).then((bitmap) => {
console.log(bitmap);
previewWidth.textContent = bitmap.width.toString();
previewHeight.textContent = bitmap.height.toString();
});
uploadForm.addEventListener("submit", async (event) => {
event.preventDefault();
let params = new URLSearchParams({
label: label.value,
format: imageType,
compression: compression.value,
});
let response = await fetch(`/dev/picture-upload?${params}`, {
method: "POST",
body: imageFile,
});
let json = await response.json();
if (json.error != null) {
console.error(json.error);
} else {
await navigator.clipboard.writeText(json.ulid);
await this.gotoCopiedToClipboard();
}
});
}
async gotoCopiedToClipboard() {
this.setState("copied-to-clipboard");
this.innerHTML = `
<div class="copied-to-clipboard">ulid copied to clipboard; the window will now refresh</div>
`;
}
setState(name) {
this.setAttribute("data-state", name);
}
async paste(item) {
console.log(item);
if (!isSupportedImageType(item.type)) {
console.error("unsupported mime type", item.type);
return;
}
let file = item.getAsFile();
if (file == null) {
console.error("data transfer does not contain a file");
return;
}
await this.gotoHavePicture(item.type, file);
}
}
customElements.define("th-picture-upload", PictureUpload);
function isSupportedImageType(mime) {
return (
mime == "image/png" ||
mime == "image/jpeg" ||
mime == "image/svg+xml" ||
mime == "image/webp"
);
}
function formatSizeSI(bytes) {
return new Intl.NumberFormat(undefined, {
style: "unit",
unit: "byte",
notation: "compact",
unitDisplay: "narrow",
}).format(bytes);
}
if (TREEHOUSE_DEV) {
CommandLine.registerCommand({
aliases: ["add-pic"],
description: "add a picture interactively and copy its ulid",
immediate: true,
run() {
let dialog = document.body.appendChild(document.createElement("dialog"));
dialog.addEventListener("keydown", (event) => {
if (event.key == "Escape") dialog.close();
});
dialog.addEventListener("close", () => {
dialog.remove();
});
dialog.appendChild(new PictureUpload());
dialog.show();
},
});
}