implement file dropping

This commit is contained in:
Reimar 2025-10-15 09:34:02 +02:00
parent e3326f0076
commit ff304c620c
3 changed files with 48 additions and 13 deletions

View File

@ -62,6 +62,7 @@ const projectName = document.querySelector("#project-name");
const saveButton = document.querySelector("#save-button");
const loadButton = document.querySelector("#load-button");
const exportButton = document.querySelector("#export-button");
const dropZone = document.querySelector("main");
const projectSaveHandler = new ProjectSaveHandler(editor, assetEditor, assetProvider, projectName);
@ -105,7 +106,7 @@ exportButton.onclick = async () => {
};
loadButton.onclick = () => {
projectSaveHandler.loadFromFile();
projectSaveHandler.showLoadFilePrompt();
};
saveButton.onclick = () => {
@ -120,3 +121,26 @@ addEventListener("keydown", (ev) => {
});
toggleAssetEditorButton.addEventListener("click", () => assetEditor.toggleEditor());
window.ondragover = (ev) => ev.preventDefault();
window.ondrop = (ev) => ev.preventDefault();
dropZone.onclick = (ev) => ev.preventDefault();
dropZone.ondragover = (ev) => ev.preventDefault();
dropZone.ondrop = async (ev) => {
for (const file of ev.dataTransfer.files) {
if (file.name.endsWith(".karlkode")) {
await projectSaveHandler.loadFromFile(file);
continue;
}
if (file.type.startsWith("image/")) {
await assetEditor.addAsset({ name: file.name, file });
continue;
}
alert("Invalid file: " + file.name);
}
ev.preventDefault();
};

View File

@ -1,6 +1,7 @@
import { promptUpload } from "./prompt_upload.js";
import { downloadFile, slugify } from "./utils.js";
import { HtmlExporter } from "./html_exporter.js";
import { KarlkoderCodec } from "./karlkoder_codec.js";
export class ProjectSaveHandler {
constructor(editor, assetEditor, assetProvider, projectName) {
@ -22,16 +23,7 @@ export class ProjectSaveHandler {
});
}
async loadFromFile() {
if (
!this.isSaved &&
!confirm(
"Your project has not been saved. Loading a new project will override your current one. Continue?",
)
) {
return;
}
async showLoadFilePrompt() {
const files = await promptUpload(".karlkode", false);
if (files.length === 0) {
return;
@ -43,8 +35,21 @@ export class ProjectSaveHandler {
);
}
this.loadFromFile(files[0]);
}
async loadFromFile(file) {
if (
!this.isSaved &&
!confirm(
"Your project has not been saved. Loading a new project will override your current one. Continue?",
)
) {
return;
}
const items = KarlkoderCodec.de(
await fetch(URL.createObjectURL(files[0])).then((x) => x.bytes()),
await fetch(URL.createObjectURL(file)).then((x) => x.bytes()),
);
const assets = items
@ -57,7 +62,7 @@ export class ProjectSaveHandler {
const code = items.find((x) => x.tag === "code");
delete code.tag;
assetEditor.importAssets(
this.assetEditor.importAssets(
assets.map(({ name, mime, content }) => {
const file = new File([content], name, { type: mime });
@ -68,6 +73,8 @@ export class ProjectSaveHandler {
this.projectName.value = code.name;
const dec = new TextDecoder();
this.editor.setValue(dec.decode(code.content));
this.isSaved = true;
}
async saveFile() {

View File

@ -24,6 +24,10 @@ main {
gap: 2rem;
}
#file-drop-input {
display: none;
}
.section-header {
background-color: #bdbdbd;
border-top-left-radius: 0.5rem;