diff options
Diffstat (limited to 'static')
| -rw-r--r-- | static/api/images.js | 35 | ||||
| -rw-r--r-- | static/index.js | 48 | ||||
| -rw-r--r-- | static/pages/image-viewer/index.js | 4 | ||||
| -rw-r--r-- | static/widgets/upload-bar/index.css | 41 | ||||
| -rw-r--r-- | static/widgets/upload-bar/index.js | 42 |
5 files changed, 145 insertions, 25 deletions
diff --git a/static/api/images.js b/static/api/images.js index 4a41a3c..4bdac1f 100644 --- a/static/api/images.js +++ b/static/api/images.js @@ -1,31 +1,29 @@ import * as sfw from 'sfw'; const { Input } = sfw.element.native; +import * as rest from './rest.js'; class FileUploader { - constructor(url) { + constructor(url, files) { this.onprogress = () => {} this.ondone = () => {} this.url = url; this.sessions = []; + this.files = files; } - send(...files) { + send() { let count = 0; - this.sessions = this.sessions.concat(files.map( - file => new Promise((resolve) => { + this.sessions = this.sessions.concat(this.files.map( + (file) => new Promise((resolve) => { const xhr = new XMLHttpRequest(); - xhr.upload.addEventListener("progress", (event) => { - if (event.lengthComputable) { - this.onprogress(file, event.loaded, event.total) - } - }); - - xhr.addEventListener("loadend", () => { + xhr.addEventListener("loadend", (event) => { count += 1; + this.onprogress(count, this.files.length) + resolve(xhr.readyState === 4 && xhr.status === 200); - if (count == files.length) { + if (count == this.files.length) { this.ondone(); } }); @@ -46,11 +44,12 @@ export async function upload_to_timeline() { }) input.click(); - const uploader = new FileUploader('/api/image/upload'); - input.onchange = async () => { - uploader.send(...input.files); - } + return new Promise((resolve) => { + input.onchange = () => { + resolve(new FileUploader('/api/image/upload', [...input.files])); + } + }) } export async function upload_to_profile() { @@ -61,3 +60,7 @@ export async function upload_to_profile() { }) input.click(); } + +export function list() { + return rest.get('/api/image/list').then(r => r.images); +} diff --git a/static/index.js b/static/index.js index 90b5ffd..2fcca88 100644 --- a/static/index.js +++ b/static/index.js @@ -11,14 +11,25 @@ import Search from './widgets/search/index.js'; import MonthSelect from './widgets/month-select/index.js'; import SettingsView from './pages/settings/index.js'; import ShuffleView from './pages/shuffle/index.js'; +import UploadBar from './widgets/upload-bar/index.js'; sfw.theme.add_css(await sfw.css(import.meta.url, './index.css')); const image_viewer = ImageViewer.new(); +const reload = () => { + image_viewer.clear(); + api.images.list().then(images => { + for (const image of images) { + image_viewer.add(`/api/image/load/${image.id}`); + } + }); +} + const login = LoginView.new({ onlogin: async (user, password) => { if (await api.auth.login(user, password)) { + reload(); login.hide(); } else { login.comment = 'Incorrect username or password.'; @@ -38,10 +49,13 @@ const search = Search.new({ onsubmit: (content) => console.log(content), onhide: () => main.show(), }); + const month_select = MonthSelect.new({ months: m`2019-08`.to(m`2025-11`), }); +const upload_bar = UploadBar.new(); + const settings = SettingsView.new({ onlogout: () => { login.show(); @@ -49,8 +63,7 @@ const settings = SettingsView.new({ }, }); -const shuffle = ShuffleView.new({ -}); +const shuffle = ShuffleView.new({ }); const main = MainView.new({ active_view: image_viewer, @@ -66,7 +79,23 @@ const main = MainView.new({ main.active_view = image_viewer; month_select.show(); }, - onupload: () => api.images.upload_to_timeline(), + onupload: async () => { + const uploader = await api.images.upload_to_timeline(); + + upload_bar.progress = 0; + upload_bar.show(); + + uploader.onprogress = (count, total) => { + upload_bar.progress = count / total; + } + + uploader.ondone = () => { + upload_bar.hide(); + reload(); + } + + uploader.send(); + }, onshuffle: () => { main.active_kind = MainView.Kind.home; main.active_view = shuffle; @@ -86,12 +115,13 @@ document.body.append( main, search, month_select, + upload_bar, ); -login.hide(); -//if (await api.session.is_valid()) { -// login.hide(); -//} else { -// login.focus(); -//} +if (await api.session.is_valid()) { + login.hide(); + reload(); +} else { + login.focus(); +} diff --git a/static/pages/image-viewer/index.js b/static/pages/image-viewer/index.js index 76d720f..f65c12b 100644 --- a/static/pages/image-viewer/index.js +++ b/static/pages/image-viewer/index.js @@ -17,4 +17,8 @@ export default class ImageViewer extends sfw.element.Container { add(url) { this.#container.append(Img.new({ src: url })); } + + clear() { + this.#container.innerHTML = ''; + } } diff --git a/static/widgets/upload-bar/index.css b/static/widgets/upload-bar/index.css new file mode 100644 index 0000000..8ec1697 --- /dev/null +++ b/static/widgets/upload-bar/index.css @@ -0,0 +1,41 @@ + +#container { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: calc(100% - 10px); + height: 100px; + background: #efefef99; + backdrop-filter: blur(10px); + border-radius: var(--border-radius); + max-width: 500px; + padding: 10px 20px; + display: grid; +} + +#files { + background: #efefef; + padding: 10px; + border-radius: 20px; + margin: auto; + width: min-content; + white-space: nowrap; +} + +#inner-progress { + width: 100%; + height: 5px; + border-radius: 5px; + background: #efefef; + overflow: hidden; + margin: auto; +} + + +#progress { + background: var(--primary); + height: 100%; + border-radius: 5px; + transition: width 0.2s ease; +} diff --git a/static/widgets/upload-bar/index.js b/static/widgets/upload-bar/index.js new file mode 100644 index 0000000..a9e0220 --- /dev/null +++ b/static/widgets/upload-bar/index.js @@ -0,0 +1,42 @@ +import * as sfw from 'sfw'; +const { Div } = sfw.element.native; + +const css = await sfw.css(import.meta.url, './index.css') + +export default class UploadBar extends sfw.element.Container { + #files_progress + #inner_progress + #container + + constructor() { + super({ css }); + + this.body.append( + this.#container = Div.new({ + id: 'container', + style: { display: 'none' }, + children: [ + this.#files_progress = Div.new({ id: 'files', innerText: 'Uploading...' }), + Div.new({ + id: 'inner-progress', + children: [ + this.#inner_progress = Div.new({ id: 'progress' }), + ] + }) + ] + }) + ); + } + + set progress(progress) { + this.#inner_progress.style.width = `${progress * 100}%` + } + + hide() { + this.#container.style.display = 'none'; + } + + show() { + this.#container.style.display = ''; + } +} |