added a basic loading screen...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2023-08-18 17:48:53 +03:00
parent a6d04eff3b
commit 1f3adbbfb1
4 changed files with 173 additions and 30 deletions

View File

@ -45,7 +45,7 @@
- actions: - actions:
- "from selection" - "from selection"
- ~~Gallery: drag-n-drop~~ - ~~Gallery: drag-n-drop~~
- ~~drop files/images~~ -- add loading indicator - ~~drop files/images~~
- ~~drag to sort~~ - ~~drag to sort~~
- **drag marked** - **drag marked**
- touch... - touch...

View File

@ -84,6 +84,8 @@ body {
.gallery { .gallery {
--base-layer: 10; --base-layer: 10;
position: relative;
padding-top: var(--gallery-padding-top); padding-top: var(--gallery-padding-top);
padding-bottom: var(--gallery-padding-bottom); padding-bottom: var(--gallery-padding-bottom);
padding-left: calc( padding-left: calc(
@ -93,6 +95,7 @@ body {
color: var(--gallery-text-color); color: var(--gallery-text-color);
background: var(--gallery-background-color); background: var(--gallery-background-color);
font-family: sans-serif;
overflow-x: clip; overflow-x: clip;
} }
@ -580,6 +583,49 @@ body {
/********************************************************* Splash ****/
.gallery .loading {
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height:100%;
text-align: center;
z-index: calc(var(--base-layer) * 2);
background: white;
}
.gallery.ready .loading {
animation: fadeOutAnimation ease 2s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
pointer-events: none;
}
@keyframes fadeOutAnimation {
0% {
opacity: 1;
}
100% {
opacity: 0;
visibility: hidden;
}
}
.gallery.ready .loading * {
display: none;
}
.gallery:not(.ready) .images img {
visibility: hidden;
}
/********************************************************** Utils ****/ /********************************************************** Utils ****/
.gallery:not(.lightboxed):not(.detailed) .hide-in-gallery, .gallery:not(.lightboxed):not(.detailed) .hide-in-gallery,
@ -588,6 +634,40 @@ body {
display: none; display: none;
} }
/* loading animation... */
.gallery .loading>div {
--bar-size: 0.2rem;
position: sticky;
top: var(--bar-size);
}
.gallery .loading>div:before,
.gallery .loading>div:after {
content: "";
position: absolute;
top: calc(var(--bar-size) * -1);
left: 0;
width: 100%;
height: var(--bar-size);
opacity: 0.3;
}
.gallery .loading>div:after {
background: gray;
animation: loadingBarAnimation ease infinite alternate 2s;
}
.gallery .loading>div:before {
width: 50%;
background: gray;
animation: loadingBarAnimation ease infinite alternate 1.5s;
}
@keyframes loadingBarAnimation {
0% {
translate: -100%;
}
100% {
translate: 100%;
}
}
/********************************************************************** /**********************************************************************

View File

@ -16,7 +16,7 @@ body.splash {
} }
/* fade-in body... */ /* fade-in body... */
/* XXX add real splash screen... */ /* XXX add real splash screen...
body:not(.splash) { body:not(.splash) {
animation: fadeInAnimation ease 2s; animation: fadeInAnimation ease 2s;
animation-iteration-count: 1; animation-iteration-count: 1;
@ -31,6 +31,7 @@ body:not(.splash) {
opacity: 1; opacity: 1;
} }
} }
*/
</style> </style>
<script> <script>
@ -89,6 +90,7 @@ For more info see: <a href="./README.md">README.md</a>
<h3>Settings</h3> <h3>Settings</h3>
<button onclick="gallery.toolbar.movable()">toggle toolbar drag</button> <button onclick="gallery.toolbar.movable()">toggle toolbar drag</button>
<button onclick="gallery.toggleLoading()">toggle splash screen</button>
<hr> <hr>
@ -175,6 +177,10 @@ For more info see: <a href="./README.md">README.md</a>
<div class="button close"></div> <div class="button close"></div>
</div> </div>
</div> </div>
<!-- loading screen -->
<div class="loading">
<div></div>
</div>
</div> </div>
</body> </body>

View File

@ -22,6 +22,7 @@ var RESIZE_SETTLE_TIMEOUT = 16
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Generic stuff...
var patchFlexRows = var patchFlexRows =
function(elems, function(elems,
@ -133,7 +134,6 @@ function(elem) {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// XXX move to types.js...
var ruler var ruler
var px2rem = function(px){ var px2rem = function(px){
if(!ruler){ if(!ruler){
@ -150,9 +150,11 @@ var rem2px = function(rem){
var px = ruler.offsetWidth var px = ruler.offsetWidth
return px } return px }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var getTouch = function(evt, id){ var getTouch =
function(evt, id){
if(id != null && id !== false && evt.targetTouches){ if(id != null && id !== false && evt.targetTouches){
for(var k in evt.targetTouches){ for(var k in evt.targetTouches){
if(evt.targetTouches[k]?.identifier == id){ if(evt.targetTouches[k]?.identifier == id){
@ -171,41 +173,63 @@ var getTouch = function(evt, id){
// - scroll into view the dragged element // - scroll into view the dragged element
// - bound it by screen // - bound it by screen
// XXX need to check if element already set as movable... // XXX need to check if element already set as movable...
var moveable = function(elem, options={}){ // XXX docs...
HTMLElement.prototype.moveable =
function(options={}){
var elem = this
if(elem.dataset.movable){ if(elem.dataset.movable){
throw new Error('element already movable.') } throw new Error('element already movable.') }
elem.dataset.movable = true elem.dataset.movable = true
// options...
var { var {
cls, // CSS class added to element while it is dragged...
handle, cls = 'movable',
// Drag handle element -- watches the drag events...
handle = elem,
// Blement bounding box used to check bounds...
box = elem,
// Bounds object...
// can be:
// false
// {
// top: <top>,
// left: <left>,
// bottom: <bottom>,
// <right>: <right>,
// }
// XXX add support for:
// css selector
// element
bounds, bounds,
// can be: // can be:
// 'x' // 'x'
// 'y' // 'y'
// undefined // undefined
lock, lock,
start = function(elem, data){ // start(<elem>, <data>)
bounds // -> undefined
?? (data.bounds = bounds) // -> <data>
return data }, start,
beforeMove,
// can be: // can be:
// 'strict' // 'strict'
// 'scroll' / true // 'scroll' / true
// false // false
keepInView = true, keepInView = true,
// move(<elem>, <data>)
move = function(elem, data){ move = function(elem, data){
data.x != null data.x != null
&& (elem.style.left = data.x + 'px') && (elem.style.left = data.x + 'px')
data.y != null data.y != null
&& (elem.style.top = data.y + 'px') }, && (elem.style.top = data.y + 'px') },
// end(<elem>, <data>)
end, end,
ignoreBounds = false,
} = options } = options
handle = typeof(handle) == 'string' ? handle =
typeof(handle) == 'string' ?
elem.querySelector(handle) elem.querySelector(handle)
: handle instanceof Element ? : handle
handle
: elem
var data var data
var handleMoveStart = function(evt){ var handleMoveStart = function(evt){
@ -219,7 +243,7 @@ var moveable = function(elem, options={}){
var y = evt.clientY var y = evt.clientY
?? evt.targetTouches[0].clientY ?? evt.targetTouches[0].clientY
data = { data = {
bounds: false, bounds: bounds,
offset: { offset: {
x: x - elem.offsetLeft, x: x - elem.offsetLeft,
y: y - elem.offsetTop, y: y - elem.offsetTop,
@ -248,7 +272,8 @@ var moveable = function(elem, options={}){
data.x = data.x =
lock == 'x' ? lock == 'x' ?
null null
: data.bounds != null ? : (!ignoreBounds
&& data.bounds != null) ?
Math.min( Math.min(
data.bounds.right, data.bounds.right,
Math.max( Math.max(
@ -258,7 +283,8 @@ var moveable = function(elem, options={}){
data.y = data.y =
lock == 'y' ? lock == 'y' ?
null null
: data.bounds != null ? : (!ignoreBounds
&& data.bounds != null) ?
Math.min( Math.min(
data.bounds.bottom, data.bounds.bottom,
Math.max( Math.max(
@ -266,13 +292,15 @@ var moveable = function(elem, options={}){
y - data.offset.y)) y - data.offset.y))
: y - data.offset.y : y - data.offset.y
// restrict to viewport... // restrict to viewport...
if(keepInView == 'strict'){ if(!ignoreBounds
&& keepInView == 'strict'){
var t, l
var bb = elem.getBoundingClientRect() var bb = elem.getBoundingClientRect()
var screen = { var screen = {
top: t = elem.offsetTop - bb.top, top: t = box.offsetTop - bb.top,
left: l = elem.offsetLeft - bb.left, left: l = box.offsetLeft - bb.left,
bottom: window.innerHeight + t - elem.offsetHeight, bottom: window.innerHeight + t - box.offsetHeight,
right: window.innerWidth + l - elem.offsetWidth, right: window.innerWidth + l - box.offsetWidth,
} }
data.x = Math.min( data.x = Math.min(
screen.right, screen.right,
@ -294,7 +322,8 @@ var moveable = function(elem, options={}){
&& move(elem, data) && move(elem, data)
// keep in view... // keep in view...
// NOTE: this works best with CSS's scroll-margin... // NOTE: this works best with CSS's scroll-margin...
;(keepInView == 'scroll' !ignoreBounds
&& (keepInView == 'scroll'
|| keepInView === true) || keepInView === true)
&& elem.scrollIntoView({ block: 'nearest' }) && elem.scrollIntoView({ block: 'nearest' })
delete data.animate }) } } } delete data.animate }) } } }
@ -872,6 +901,18 @@ var Gallery = {
img.classList.toggle('marked') } img.classList.toggle('marked') }
return this.updateMarkers() }, return this.updateMarkers() },
get loading(){
return !this.dom.classList.contains('ready') },
showLoading: function(){
this.dom.classList.remove('ready')
return this },
hideLoading: function(){
this.dom.classList.add('ready')
return this },
toggleLoading: function(){
this.dom.classList.toggle('ready')
return this },
show: function(){ show: function(){
return this.showLightbox() }, return this.showLightbox() },
showLightbox: function(){ showLightbox: function(){
@ -1189,6 +1230,8 @@ var Gallery = {
// non-local drag... // non-local drag...
if(!dragged){ if(!dragged){
that.showLoading()
var expand = (evt.shiftKey && dragged_over) ? var expand = (evt.shiftKey && dragged_over) ?
that.images.indexOf(dragged_over) that.images.indexOf(dragged_over)
: undefined : undefined
@ -1231,12 +1274,14 @@ var Gallery = {
.flat()) .flat())
.then( .then(
function(images){ function(images){
that.hideLoading()
// no images... // no images...
if(images.length == 0){ if(images.length == 0){
return } return }
return that.load(images, expand) }, return that.load(images, expand) },
function(err){ function(err){
// XXX handle errors... // XXX handle errors...
that.hideLoading()
}) } }) }
dragged dragged
&& dragged.classList.remove('dragged') && dragged.classList.remove('dragged')
@ -1259,7 +1304,8 @@ var Gallery = {
return this return this
.updateMarkers() .updateMarkers()
.update() }, .update()
.hideLoading() },
} }
@ -1270,8 +1316,10 @@ var Toolbar = {
gallery: undefined, gallery: undefined,
cls: 'toolbar', cls: 'toolbar',
// time to hold the handle to toggle autohide...
hold: 300, hold: 300,
// autohide timeout...
toolbar_autohide: 2000, toolbar_autohide: 2000,
// XXX make these generic... // XXX make these generic...
@ -1354,10 +1402,7 @@ var Toolbar = {
// toolbar: move... // toolbar: move...
// XXX to drag anywhere on the elem we need to prevent // XXX to drag anywhere on the elem we need to prevent
// clicks while dragging... // clicks while dragging...
// XXX prevent from scrolling off screen when placed a bottom toolbar.moveable({
// and scrolling up -- i.e. keep within viewport and gallery
// at all times...
moveable(toolbar, {
cls: 'moving', cls: 'moving',
handle: '.drag-handle', handle: '.drag-handle',
// set bounds... // set bounds...
@ -1378,6 +1423,15 @@ var Toolbar = {
data.y != null data.y != null
&& elem.style.setProperty('--move-y', data.y + 'px') }, }) && elem.style.setProperty('--move-y', data.y + 'px') }, })
// keep toolbar in view while scrolling...
// NOTE: top is taken care of by position: sticky...
window.addEventListener('scroll', function(evt){
var bb = toolbar.getBoundingClientRect()
if(window.innerHeight <= bb.bottom){
var top = toolbar.offsetTop - bb.top
var bottom = window.innerHeight + top - toolbar.offsetHeight
toolbar.style.setProperty('--move-y', bottom + 'px') } })
return this }, return this },
} }
@ -1618,6 +1672,7 @@ var Details = {
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
var setupGallery = function(gallery){ var setupGallery = function(gallery){
@ -1631,6 +1686,8 @@ var setup = function(){
window.gallery = setupGallery(gallery) } window.gallery = setupGallery(gallery) }
// keyboard... // keyboard...
document.addEventListener('keydown', function(evt){ document.addEventListener('keydown', function(evt){
if(window.gallery.loading){
return }
var key = evt.key var key = evt.key
if(key in keyboard){ if(key in keyboard){
keyboard[key](evt) } }) } keyboard[key](evt) } }) }