added basic details/edit view + streamlined control through gallery...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2023-08-03 14:10:59 +03:00
parent a4712a46ec
commit 7436eb2ada
3 changed files with 181 additions and 82 deletions

View File

@ -88,10 +88,6 @@ body {
color: var(--gallery-text-color);
background: var(--gallery-background-color);
}
.gallery.lightboxed {
--base-layer: 100;
}
.gallery .images {
position: relative;
display: flex;
@ -182,9 +178,19 @@ body {
/******************************************************* Lightbox ****/
/******************************************************* Overlays ****/
.gallery .lightbox {
.gallery.lightboxed,
.gallery.detailed {
--base-layer: 100;
}
.gallery.lightboxed .lightbox,
.gallery.detailed .details {
display: block;
}
.gallery .lightbox,
.gallery .details {
display: none;
position: fixed;
width: 100%;
@ -198,9 +204,10 @@ body {
color: var(--lightbox-text-color);
background: var(--lightbox-background-color);
}
.gallery.lightboxed .lightbox {
display: block;
}
/*------------------------------------------------------ Lightbox ---*/
.gallery .lightbox.show-caption:before {
content: attr(caption);
position: absolute;
@ -223,14 +230,24 @@ body {
var(--lightbox-frame)
* var(--lightbox-image-margin-top));
}
/* controls: next/prev... */
.gallery .lightbox .buttons {
/*------------------------------------------------------- Details ---*/
.gallery .details img {
width: 50%;
}
/******************************************************* Controls ****/
.gallery .buttons {
display: flex;
position: absolute;
top: 0;
right: 0;
}
.gallery .lightbox .button {
.gallery .button {
disbplay: inline-block;
cursor: pointer;
width: var(--lightbox-button-size);
@ -240,27 +257,28 @@ body {
filter: saturate(0);
opacity: 0.1;
}
.gallery .lightbox .button:hover {
.gallery .button:hover {
opacity: 1;
filter: saturate(1);
color: black;
}
/* controls: close... */
.gallery .lightbox .button.close:after {
.gallery .button.close:after {
content: "✕";
color: red;
}
.gallery .lightbox .button.fullscreen:after {
.gallery .button.fullscreen:after {
content: "⛶";
color: black;
}
/******************************************************** Details ****/
.gallery .details {
display: none;
.gallery .button.info:after {
content: "i";
}
.gallery .button.prev:after {
content: "<";
}
.gallery .button.next:after {
content: ">";
}
/**********************************************************************

View File

@ -122,6 +122,7 @@ var restoreScroll = function(){
<div class="lightbox">
<img>
<div class="buttons">
<div class="button info"></div>
<div class="button fullscreen"></div>
<div class="button close"></div>
</div>
@ -130,13 +131,17 @@ var restoreScroll = function(){
<div class="details">
<img>
<div class="caption">
CAPTION
</div>
<div class="tags">
TAGS
</div>
<div class="info">
<div class="metadata">
METADATA
</div>
<div class="buttons">
<div class="button fullscreen"></div>
<div class="button prev"></div>
<div class="button next"></div>
<div class="button close"></div>
</div>
</div>

View File

@ -122,29 +122,36 @@ function(elem) {
// XXX add home/end, pageup/pagedown...
var keyboard = {
ArrowLeft: function(){
gallery.lightbox.shown ?
gallery.lightbox.prev()
: gallery.prev() },
gallery.prev() },
ArrowRight: function(){
gallery.lightbox.shown ?
gallery.lightbox.next()
: gallery.next() },
gallery.next() },
// NOTE: up/down will not prevent the default scrolling behavior
// when at top/bottom of the gallery.
ArrowUp: function(evt){
gallery.__at_top_row
|| evt.preventDefault()
;(gallery.dom.classList.contains('lightboxed')
|| gallery.dom.classList.contains('detailed'))
&& evt.preventDefault()
gallery.lightbox.shown
|| gallery.details.shown
|| gallery.up() },
ArrowDown: function(evt){
gallery.__at_bottom_row
|| evt.preventDefault()
;(gallery.dom.classList.contains('lightboxed')
|| gallery.dom.classList.contains('detailed'))
&& evt.preventDefault()
gallery.lightbox.shown
|| gallery.details.shown
|| gallery.down() },
Enter: function(){
gallery.lightbox.toggle() },
// XXX need a real ui stack -- close top to bottom...
Escape: function(evt){
gallery.lightbox.shown ?
gallery.details.shown ?
gallery.details.hide()
: gallery.lightbox.shown ?
gallery.lightbox.hide()
// XXX should we remember which image was current and select
// it again when needed???
@ -263,6 +270,16 @@ var Gallery = {
this)) }
delete this.__lightbox
return undefined },
__details: undefined,
get details(){
if(this.dom){
return this.__details
?? (this.__details = { __proto__: Details }
.setup(
this.dom.querySelector('.details'),
this)) }
delete this.__details
return undefined },
__at_top_row: undefined,
__at_bottom_row: undefined,
@ -448,6 +465,7 @@ var Gallery = {
images.length-1
: 0
this.current = images[i]
this.update()
return this },
next: function(images){
images ??= this.images
@ -460,6 +478,7 @@ var Gallery = {
0
: images.length-1
this.current = images[i]
this.update()
return this },
// navigate images visually...
@ -546,12 +565,25 @@ var Gallery = {
show: function(){
this.lightbox.show()
return this },
showLightbox: function(){
this.lightbox.show()
return this },
showDetails: function(){
this.details.show()
return this },
update: function(){
__update_grid_size: function(){
patchFlexRows(this.images,
!this.allow_row_expansion,
this.last_row_resize ?? 1.2)
return this },
update: function(){
this.__update_grid_size()
this.lightbox.shown
&& this.lightbox.update()
this.details.shown
&& this.details.update()
return this },
// .load(<image>)
// .load(<images>)
@ -690,7 +722,7 @@ var Gallery = {
// handle resizing...
new ResizeObserver(
function(elems){
that.update() })
that.__update_grid_size() })
.observe(this.dom)
return this
@ -701,16 +733,10 @@ var Gallery = {
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// XXX ignore click from blur...
var Lightbox = {
var Overlay = {
dom: undefined,
gallery: undefined,
caption_format: '${INDEX} ${CAPTION}',
navigation_deadzone: 100,
caption_hysteresis: 10,
cache_count: 1,
cls: 'overlay',
get url(){
return this.dom.querySelector('img').src },
@ -719,31 +745,34 @@ var Lightbox = {
// remove preview dir...
.replace(/\/[0-9]+px\//, '/')
// cache...
this.cache_count != 0
this.cache
&& this.cache_count != 0
&& this.cache() },
get shown(){
return this.gallery.dom.classList.contains('lightboxed') },
show: function(url){
this.url = url
?? (this.gallery.current
?? this.gallery.next().current
?? {}).src
return this.gallery.dom.classList.contains(this.cls) },
show: function(){
this.update()
this.gallery.dom.classList.add('lightboxed')
this.gallery.dom.classList.add(this.cls)
return this },
hide: function(){
this.gallery.exit_fullscreen_on_lightbox_close
&& document.fullscreenElement
&& document.exitFullscreen()
this.gallery.dom.classList.remove('lightboxed')
this.gallery.dom.classList.remove(this.cls)
return this },
toggle: function(){
return this.shown ?
this.hide()
: this.show() },
cache: null,
update: function(){
this.url =
(this.gallery.current
?? this.gallery.next().current
?? {}).src
var caption =
(this.gallery.current
?? this.gallery.next().current
@ -754,7 +783,7 @@ var Lightbox = {
// set caption...
// XXX should these be separate elements???
this.dom.setAttribute('caption',
this.caption_format
(this.caption_format ?? '${CAPTION}')
.replace(/\${CAPTION}/, caption)
.replace(/\${INDEX}/, index))
// set selection...
@ -763,12 +792,67 @@ var Lightbox = {
: this.dom.classList.remove('marked')
return this },
prev: function(){
this.gallery.prev().show()
return this },
next: function(){
this.gallery.next().show()
setup: function(dom, gallery){
var that = this
this.dom = dom
this.gallery = gallery
// controls...
this.dom.querySelector('.close')
?.addEventListener('click', function(evt){
evt.stopPropagation()
that.hide() })
this.dom.querySelector('.fullscreen')
?.addEventListener('click', function(evt){
evt.stopPropagation()
document.fullscreenElement ?
document.exitFullscreen()
: that.dom.requestFullscreen() })
this.dom.querySelector('.info')
?.addEventListener('click', function(evt){
evt.stopPropagation()
that.gallery.showDetails() })
this.dom.querySelector('.prev')
?.addEventListener('click', function(evt){
evt.stopPropagation()
that.gallery.prev() })
this.dom.querySelector('.next')
?.addEventListener('click', function(evt){
evt.stopPropagation()
that.gallery.next() })
// stop body from scrolling...
var stop = function(evt){
evt.stopPropagation()
evt.preventDefault()
return false }
this.dom.addEventListener('touchmove', stop)
this.dom.addEventListener('mousewheel', stop)
this.dom.addEventListener('wheel', stop)
this.dom.addEventListener('scroll', stop)
// drag...
this.dom
.addEventListener('dragover', function(evt){
that.gallery.dom.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
})
that.hide() })
return this },
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var Lightbox = {
__proto__: Overlay,
cls: 'lightboxed',
caption_format: '${INDEX} ${CAPTION}',
navigation_deadzone: 100,
caption_hysteresis: 10,
cache_count: 1,
__cache: undefined,
cache: function(){
@ -795,28 +879,10 @@ var Lightbox = {
setup: function(dom, gallery){
var that = this
this.dom = dom
this.gallery = gallery
// controls...
this.dom.querySelector('.close')
.addEventListener('click', function(evt){
evt.stopPropagation()
that.hide() })
this.dom.querySelector('.fullscreen')
.addEventListener('click', function(evt){
evt.stopPropagation()
document.fullscreenElement ?
document.exitFullscreen()
: that.dom.requestFullscreen() })
// drag...
this.dom
.addEventListener('dragover', function(evt){
that.gallery.dom.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
})
that.hide() })
// click...
Overlay.setup.call(this, ...arguments)
// click zones...
var deadzone = this.navigation_deadzone ?? 100
this.dom
.addEventListener('click', function(evt){
@ -824,10 +890,10 @@ var Lightbox = {
// click left/right side of view...
// NOTE: this is vewport-relative...
evt.clientX < that.dom.offsetWidth / 2 - deadzone/2
&& that.prev()
&& that.gallery.prev()
evt.clientX > that.dom.offsetWidth / 2 + deadzone/2
&& that.next() })
// mousemove...
&& that.gallery.next() })
// hover zones...
var hysteresis = this.caption_hysteresis ?? 10
this.dom
.addEventListener('mousemove', function(evt){
@ -856,6 +922,16 @@ var Lightbox = {
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var Details = {
__proto__: Overlay,
cls: 'detailed',
// XXX
}
//---------------------------------------------------------------------