diff --git a/src/lib/components/FullscreenViewer.js b/src/lib/components/FullscreenViewer.js index 9df1cd5..204f287 100644 --- a/src/lib/components/FullscreenViewer.js +++ b/src/lib/components/FullscreenViewer.js @@ -2,9 +2,11 @@ import {BaseComponent} from "$lib/components/base/BaseComponent.js"; export class FullscreenViewer extends BaseComponent { /** @type {HTMLVideoElement} */ - #videoElement; + #videoElement = document.createElement('video'); /** @type {HTMLImageElement} */ - #imageElement; + #imageElement = document.createElement('img'); + + #spinnerElement = document.createElement('i'); /** @type {number|null} */ #touchId = null; @@ -20,9 +22,9 @@ export class FullscreenViewer extends BaseComponent { */ build() { this.container.classList.add('fullscreen-viewer'); + this.container.append(this.#spinnerElement); - this.#videoElement = document.createElement('video'); - this.#imageElement = document.createElement('img'); + this.#spinnerElement.classList.add('spinner', 'fa', 'fa-circle-notch', 'fa-spin'); } /** @@ -35,6 +37,13 @@ export class FullscreenViewer extends BaseComponent { this.on('touchstart', this.#onTouchStart.bind(this)); this.on('touchmove', this.#onTouchMove.bind(this)); this.on('touchend', this.#onTouchEnd.bind(this)); + + this.#videoElement.addEventListener('loadeddata', this.#onLoaded.bind(this)); + this.#imageElement.addEventListener('load', this.#onLoaded.bind(this)); + } + + #onLoaded() { + this.container.classList.remove('loading'); } /** @@ -169,6 +178,8 @@ export class FullscreenViewer extends BaseComponent { * @param {string} url */ show(url) { + this.container.classList.add('loading'); + requestAnimationFrame(() => { this.container.classList.add(FullscreenViewer.#shownState); document.body.style.overflow = 'hidden'; diff --git a/src/styles/content/listing.scss b/src/styles/content/listing.scss index 7251a96..54b4496 100644 --- a/src/styles/content/listing.scss +++ b/src/styles/content/listing.scss @@ -177,6 +177,21 @@ object-fit: contain; width: 100%; height: 100%; + opacity: 1; + } + + .spinner { + position: fixed; + opacity: 0; + left: 50vw; + top: 50vh; + transform: translate(-50%, -50%); + font-size: 64px; + text-shadow: 0 0 15px black; + } + + img, video, .spinner { + transition: opacity .25s ease; } &.shown { @@ -188,4 +203,14 @@ opacity: var(--opacity, 1); transition: none; } + + &.loading { + img, video { + opacity: 0.25; + } + + .spinner { + opacity: 1; + } + } }