Mercurial > code > home > repos > video
view src/ingest/IngestDrop.ts @ 24:1a9a8af1aa19
breadcrumbs and tree view UI
author | drewp@bigasterisk.com |
---|---|
date | Mon, 17 Apr 2023 13:35:18 -0700 |
parents | ff73b95fc72f |
children |
line wrap: on
line source
import { LitElement, html, css, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators.js"; interface SubTree { name: string; children?: SubTree[]; } @customElement("ingest-drop") export class IngestDrop extends LitElement { @property() folder: string = "/"; @property() tree: SubTree = { name: "TOP" }; static styles = [ css` #drop { min-width: 10em; min-height: 10em; background: gray; border: 5px gray dashed; margin: 1% 10%; } #drop.dnd-hover { background: yellow; } .twocol { display: flex; } .twocol > div { background: #262626; } `, ]; render() { const self = this; function renderTree(node: SubTree, pathToHere?: string): TemplateResult { const isTop = pathToHere === undefined; const toplessPath = isTop ? "" : pathToHere + "/" + node.name; const internalPath = toplessPath || "/"; return html`<sl-tree-item expanded ?selected=${isTop} data-path="${internalPath}" @click=${self.setFolder}> ${node.name} ${(node.children || []).map((n: SubTree) => renderTree(n, toplessPath))} </sl-tree-item>`; } return html` <div class="twocol"> <div> <h3>Select folder</h3> <sl-tree>${renderTree(this.tree)}</sl-tree> </div> <div> <div id="drop" @dragover=${this.dragover} @dragleave=${this.leave} @drop=${this.drop}> Drop video file or url here to upload to <em>TOP${this.folder}</em> </div> </div> </div> `; } connectedCallback(): void { super.connectedCallback(); this.loadFolderTree(); } async loadFolderTree() { this.tree = await (await fetch("../api/folderTree")).json(); } setFolder(ev: MouseEvent) { for (let el of ev.composedPath()) { const ds = (el as HTMLElement).dataset; if (ds) { if (ds.path) { this.folder = ds.path; return; } } } console.error("didn't find data-path"); } dragover(ev: DragEvent) { this.shadowRoot?.querySelector("#drop")?.classList.add("dnd-hover"); ev.preventDefault(); if (ev.dataTransfer) { ev.dataTransfer.dropEffect = "copy"; } } leave() { this.shadowRoot?.querySelector("#drop")?.classList.remove("dnd-hover"); } drop(ev: DragEvent) { ev.preventDefault(); this.leave(); if (!ev.dataTransfer) { return; } const url = ev.dataTransfer.getData("text/plain"); if (url) { this.queueUrlToFetch(url); } else { for (let i = 0; i < ev.dataTransfer.files.length; i++) { this.uploadVideoFile(ev.dataTransfer.files[i]); } } } queueUrlToFetch(url: string) { fetch("../api/ingest/videoUrl?folder=" + encodeURIComponent(this.folder), { method: "POST", body: url, }); } uploadVideoFile(f: File) { fetch("../api/ingest/videoUpload?name=" + encodeURIComponent(this.folder + "/" + f.name), { method: "POST", body: f.stream(), duplex: "half", } as any /* types don't include 'duplex' */ ); } }