
- edit toggle - reorder with drag and drop - delete button inside edit modal - add ability to clear image from card - make card textarea taller and avoid horizontal resize
88 lines
2.1 KiB
TypeScript
88 lines
2.1 KiB
TypeScript
import "./file-uploader.css";
|
|
import { VoidApi } from "@void-cat/api";
|
|
import { useState } from "react";
|
|
|
|
const voidCatHost = "https://void.cat";
|
|
const fileExtensionRegex = /\.([\w]{1,7})$/i;
|
|
const voidCatApi = new VoidApi(voidCatHost);
|
|
|
|
type UploadResult = {
|
|
url?: string;
|
|
error?: string;
|
|
};
|
|
|
|
async function voidCatUpload(file: File | Blob): Promise<UploadResult> {
|
|
const uploader = voidCatApi.getUploader(file);
|
|
|
|
const rsp = await uploader.upload({
|
|
"V-Strip-Metadata": "true",
|
|
});
|
|
if (rsp.ok) {
|
|
let ext = file.name.match(fileExtensionRegex);
|
|
if (rsp.file?.metadata?.mimeType === "image/webp") {
|
|
ext = ["", "webp"];
|
|
}
|
|
const resultUrl =
|
|
rsp.file?.metadata?.url ??
|
|
`${voidCatHost}/d/${rsp.file?.id}${ext ? `.${ext[1]}` : ""}`;
|
|
|
|
const ret = {
|
|
url: resultUrl,
|
|
} as UploadResult;
|
|
|
|
return ret;
|
|
} else {
|
|
return {
|
|
error: rsp.errorMessage,
|
|
};
|
|
}
|
|
}
|
|
|
|
export function FileUploader({ defaultImage, onClear, onFileUpload }) {
|
|
const [img, setImg] = useState(defaultImage);
|
|
const [isUploading, setIsUploading] = useState(false);
|
|
|
|
async function onFileChange(ev) {
|
|
const file = ev.target.files[0];
|
|
if (file) {
|
|
try {
|
|
setIsUploading(true);
|
|
const upload = await voidCatUpload(file);
|
|
if (upload.url) {
|
|
setImg(upload.url);
|
|
onFileUpload(upload.url);
|
|
}
|
|
if (upload.error) {
|
|
console.error(upload.error);
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
} finally {
|
|
setIsUploading(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
function clearImage() {
|
|
setImg("");
|
|
onClear();
|
|
}
|
|
|
|
return (
|
|
<div className="file-uploader-container">
|
|
<label className="file-uploader">
|
|
<input type="file" onChange={onFileChange} />
|
|
{isUploading ? "Uploading..." : "Add File"}
|
|
</label>
|
|
<div className="file-uploader-preview">
|
|
{img?.length > 0 && (
|
|
<button className="btn btn-primary clear-button" onClick={clearImage}>
|
|
Clear
|
|
</button>
|
|
)}
|
|
{img && <img className="image-preview" src={img} />}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|