UNPKG

life-diary

Version:

Life Diary ❤️ your albums, your journey, your data

233 lines (202 loc) 6.45 kB
<style> ld-album { display: block; } </style> <style scoped> form > fieldset { border: 0; } fieldset > legend { display: none; } form { display: flex; align-items: center; flex-direction: row; min-height: 100px; } form > h1 { flex-grow: 1; margin: 0; display: flex; align-items: center; } form > h1 > button.remover { padding: 16px; } div[ref="list"] { display: flex; flex-wrap: wrap; justify-content: space-between; } </style> <ld-album> <form ref="form" onsubmit={{preventDefault}} method="post" action="/upload" enctype="multipart/form-data"> <h1> <button title="Home" class="remover" onclick={{home}}>🏡</button> {{album}} </h1> <fieldset> <legend>Upload new files</legend> <input onchange={{uploadFiles}} type="file" name="upload" accept="audio/*,image/*,video/*,.jpeg,.jpg,.JPEG,.JPG,.HEIC,.heic" multiple required> <ld-progress ref="progress"></ld-progress> </fieldset> </form> <masonry-rows ref="list"></masonry-rows> </ld-album> <script type="module"> /** * ISC License * * Copyright (c) 2020, Andrea Giammarchi, @WebReflection * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * */ import {render, html, ref} from '@uce'; const cursor = { char: ['⠦', '⠧', '⠇', '⠏', '⠋', '⠙', '⠹', '⠸', '⠼', '⠴'], i: 0, next() { if (this.i < 0) this.i = 0; return this.char[this.i++ % this.char.length]; } }; export default { props: {data: {}}, setup(element) { const renderFiles = files => { const fullscreen = event => { let {currentTarget, target} = event; if (/^a$/i.test(target.nodeName)) target = target.firstElementChild; if (/^(?:img|video)$/i.test(target.nodeName)) { event.preventDefault(); element.data.fullscreen.fullscreen(files, files.indexOf(currentTarget.data)); } }; const removeMedia = ({detail: file}) => { const i = files.indexOf(file); if (-1 < i) { files.splice(i, 1); renderFiles(files); } }; render(ref(element).list, html.for(files, 'album')` ${files.map(file => html.for(file, 'media-preview')` <ld-media-preview onclick=${fullscreen} ondeleted=${removeMedia} .data=${file} /> `)} `); }; element.connected = () => { renderFiles(element.data.files); }; return { get album() { return element.data.album; }, preventDefault(event) { event.preventDefault(); }, home(event) { event.preventDefault(); event.stopImmediatePropagation(); element.data.listAlbums(); }, uploadFiles() { const {data} = element; const {form, progress} = ref(element); const {upload} = form; const {disabled, files: uploads} = upload; if (disabled || uploads.length < 1) return; const {reduce} = []; const sum = (total, {size}) => total + size; const method = 'POST'; navigator.wakeLock.request('screen').then(wakeLock => { const max = reduce.call(uploads, sum, 0); const {length} = uploads; let uploading = true; let nextValue = 0; let value = 0; let isMOV = false; progress.max = max; progress.value = value; progress.details = `processing 0/${length}`; upload.disabled = true; const fail = () => { uploadFile(length); alert(`Unable to upload ${uploads[i].name}`); }; const uploadFile = i => { if (i === length) { data.fetching = false; upload.value = ''; progress.details = ''; upload.disabled = uploading = false; wakeLock.release(); } else { isMOV = /\.mov$/i.test(uploads[i].name); nextValue += uploads[i].size; const encoded = encodeURIComponent(element.data.album); const body = new FormData(); body.append('upload', uploads[i]); fetch( `${form.action}?album=${encoded}`, {method, body} ) .then(res => res.json()) .then(file => { if (file) { data.files.push(file); progress.details = `processing ${++i + 1}/${length}`; renderFiles(data.files); uploadFile(i); } else fail(); }) .catch(fail); } }; data.fetching = true; uploadFile(0); let frames = 0; (function update() { if (uploading) { value += (nextValue - value) * (isMOV ? .005 : .02); progress.value = value; if (!(frames++ % 6)) progress.spinner = cursor.next(); requestAnimationFrame(update); } else { progress.value = 0; progress.spinner = ''; } }()); }, () => { alert('Please confirm lock-screen to upload'); }); } }; } }; </script>