experimenting with draggable toolbar (disabled)

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2023-08-17 11:24:30 +03:00
parent 4f5717178b
commit 8394c8e05f
3 changed files with 210 additions and 69 deletions

View File

@ -242,26 +242,36 @@ body {
/******************************************************** Toolbar ****/
/* XXX make the toolbar swirchable and contextual... */
.gallery .toolbar-anchor {
position: sticky;
top: 0;
margin: 0 calc(var(--gallery-padding-horizontal) * -1);
z-index: calc(var(--base-layer) + 2);
}
/* XXX make the toolbar contextual... */
.gallery .toolbar {
--move-x: 0;
--move-y: 0;
--padding: 0.5rem;
--top: 1rem;
--height: calc((var(--toolbar-button-size) + var(--padding) * 2));
position: absolute;
display: inline-block;
position: sticky;
left: var(--move-x);
top: var(--move-y);
width: fit-content;
top: calc(var(--height) * -1 + var(--top));
padding: var(--padding);
padding-right: var(--height);
padding-left: var(--height);
margin-left: calc(var(--gallery-padding-horizontal) * -1);
/* takeup no space... */
margin-top: calc(var(--height) * -1);
translate: 0 100%;
z-index: calc(var(--base-layer) + 2);
translate: 0 0;
border: solid 1px var(--gallery-secondary-color);
border-radius: calc(var(--height) / 8);
@ -270,6 +280,7 @@ body {
box-shadow: 0.2em 0.2em 0.5em -0.3em rgba(0,0,0,0.8);
transition:
left 0.2s,
padding-right 0.2s,
opacity 0.2s,
translate 0.2s;
@ -282,6 +293,10 @@ body {
display: none;
}
.gallery .toolbar.moving {
transition: none;
}
/* sticky toolbar indicator... */
.gallery .toolbar.sticky:after {
content: "lock";
@ -305,7 +320,10 @@ body {
/* collapsed toolbar (default)... */
/* XXX shoud the toolbar be vertical??? */
.gallery .toolbar:not(.shown) {
translate: calc(-100% + var(--toolbar-button-size) + var(--padding)) 100%;
translate: calc(-100% + var(--toolbar-button-size) + var(--padding)) 0;
left: 0;
/*padding-right: calc(var(--padding) / 5);*/
padding-right: var(--height);
}

View File

@ -78,39 +78,41 @@ For more info see: <a href="./README.md">README.md</a>
<div class="gallery otter">
<!-- toolbar -->
<div class="toolbar">
<button class="drag-handle" title="drag">drag_indicator</button>
<div>
<button onclick="gallery" title="upload">cloud_upload</button>
<button onclick="gallery" title="save">save</button>
<div class="toolbar-anchor">
<div class="toolbar">
<button class="drag-handle" title="drag">drag_indicator</button>
<div>
<button onclick="gallery" title="upload">cloud_upload</button>
<button onclick="gallery" title="save">save</button>
</div>
<!--div>
<button onclick="gallery" title="save">contrast</button>
</div-->
<div>
<!--button onclick="gallery.details.show()" title="info">imagesmode<sec>label</sec></button-->
<button onclick="gallery.details.show()" title="edit">imagesmode<sec>edit</sec></button>
</div>
<div>
<button onclick="gallery.toggleMark()" title="toggle mark current (space)">select</button>
<button onclick="gallery.markAll()" title="mark all (ctrl-a)">select<sec>select</sec></button>
<button onclick="gallery.unmarkAll()" title="unmark all (ctrl-d)">square<sec>square</sec></button>
<button onclick="gallery.markInverse()" title="reverse mark (ctrl-i)">select<sec>square</sec></button>
<button onclick="gallery.remove('marked')" title="remove marked">select<sec>close</sec></button>
</div>
<div>
<button onclick="gallery" title="crop marked">select<sec>crossword</sec></button>
<button onclick="gallery" title="uncrop">select<sec>grid_on</sec></button>
</div>
<div>
<button onclick="gallery.toggleQueueRemoval()" title="queue removal (del)">delete</button>
<button onclick="gallery.toggleQueueRemoval('marked')" title="toggle marked removal">delete<sec>select</sec></button>
<button onclick="gallery.removeQueued()" title="remove queued (shift-del)">delete<sec>close</sec></button>
</div>
<div>
<button onclick="gallery.clear()" title="clear">close</button>
</div>
<button class="collapse" title="toggle toolbar (hold to make sticky)">keyboard_double_arrow_left</button>
</div>
<!--div>
<button onclick="gallery" title="save">contrast</button>
</div-->
<div>
<!--button onclick="gallery.details.show()" title="info">imagesmode<sec>label</sec></button-->
<button onclick="gallery.details.show()" title="edit">imagesmode<sec>edit</sec></button>
</div>
<div>
<button onclick="gallery.toggleMark()" title="toggle mark current (space)">select</button>
<button onclick="gallery.markAll()" title="mark all (ctrl-a)">select<sec>select</sec></button>
<button onclick="gallery.unmarkAll()" title="unmark all (ctrl-d)">square<sec>square</sec></button>
<button onclick="gallery.markInverse()" title="reverse mark (ctrl-i)">select<sec>square</sec></button>
<button onclick="gallery.remove('marked')" title="remove marked">select<sec>close</sec></button>
</div>
<div>
<button onclick="gallery" title="crop marked">select<sec>crossword</sec></button>
<button onclick="gallery" title="uncrop">select<sec>grid_on</sec></button>
</div>
<div>
<button onclick="gallery.toggleQueueRemoval()" title="queue removal (del)">delete</button>
<button onclick="gallery.toggleQueueRemoval('marked')" title="toggle marked removal">delete<sec>select</sec></button>
<button onclick="gallery.removeQueued()" title="remove queued (shift-del)">delete<sec>close</sec></button>
</div>
<div>
<button onclick="gallery.clear()" title="clear">close</button>
</div>
<button class="collapse" title="toggle toolbar (hold to make sticky)">keyboard_double_arrow_left</button>
</div>
<!-- gallery: content -->
<div class="images">

View File

@ -128,6 +128,28 @@ function(elem) {
&& rect.right <= (window.innerWidth
|| document.documentElement.clientWidth) }
// XXX move to types.js...
var ruler
var px2rem = function(px){
if(!ruler){
ruler = document.createElement('div')
document.body.append(ruler) }
ruler.style.width = '1rem'
var c = ruler.offsetWidth
return px / c }
var rem2px = function(rem){
if(!ruler){
ruler = document.createElement('div')
document.body.append(ruler) }
ruler.style.width = rem + 'em'
var px = ruler.offsetWidth
return px }
var getTouch = function(evt, id){
if(id != null && id !== false && evt.targetTouches){
for(var k in evt.targetTouches){
if(evt.targetTouches[k]?.identifier == id){
return evt.targetTouches[k] } } } }
//---------------------------------------------------------------------
@ -872,46 +894,141 @@ var Gallery = {
// toolbar...
var toolbar = this.dom.querySelector('.toolbar')
var toolbar_moving = false
// prevent clicks in toolbar from affecting the gallery...
toolbar
.addEventListener('click', function(evt){
evt.stopPropagation() })
// toolbar: collapse: click, hold to make sticky...
var hold_timeout
var handleInterationStart = function(evt){
var holding_toggle
var handleInteractionStart = function(evt){
holding_toggle = true
hold_timeout = setTimeout(
function(){
hold_timeout = undefined
toolbar.classList.toggle('sticky') },
that.toolbar_hold ?? 300) }
var handleInterationEnd = function(evt){
evt.preventDefault()
hold_timeout
&& clearTimeout(hold_timeout)
hold_timeout = undefined
that.toggleToolbar() }
var handleInteractionEnd = function(evt){
if(holding_toggle){
holding_toggle = false
evt.preventDefault()
hold_timeout
&& clearTimeout(hold_timeout)
hold_timeout = undefined
that.toggleToolbar() }}
var collapse_button = toolbar.querySelector('.collapse')
collapse_button.addEventListener('touchstart', handleInterationStart)
collapse_button.addEventListener('mousedown', handleInterationStart)
collapse_button.addEventListener('touchend', handleInterationEnd)
collapse_button.addEventListener('mouseup', handleInterationEnd)
collapse_button.addEventListener('touchstart', handleInteractionStart)
collapse_button.addEventListener('mousedown', handleInteractionStart)
// XXX should these be on document???
// ...if yes we'll need to be carefull with .preventDefault(..)
document.addEventListener('touchend', handleInteractionEnd)
document.addEventListener('mouseup', handleInteractionEnd)
// toolbar: autohide...
var hide_timeout
toolbar
.addEventListener('mouseout', function(evt){
if(that.toolbar_autohide == 0
|| toolbar.classList.contains('sticky')){
// XXX does not work correctly with touch...
var toolbarAutoHideTimerStart = function(evt){
if(that.toolbar_autohide == 0
|| toolbar.classList.contains('sticky')){
return }
hide_timeout = setTimeout(
function(){
hide_timeout = undefined
that.toggleToolbar('hide') },
that.toolbar_autohide ?? 1000) }
var toolbarAutoHideCancel = function(evt){
hide_timeout
&& clearTimeout(hide_timeout)
hide_timeout = undefined }
toolbar.addEventListener('mouseout', toolbarAutoHideTimerStart)
toolbar.addEventListener('touchend', toolbarAutoHideTimerStart)
toolbar.addEventListener('mouseover', toolbarAutoHideCancel)
toolbar.addEventListener('touchstart', toolbarAutoHideCancel)
/* XXX problems:
// - too many interactions: autohide, placement, ...
// - not sure if we need this...
// toolbar: move...
var handleToolbarMoveStart = function(evt){
evt.preventDefault()
evt.stopPropagation()
if(!toolbar_moving){
toolbar.classList.add('moving')
var x = evt.clientX
?? evt.targetTouches[0].clientX
var y = evt.clientY
?? evt.targetTouches[0].clientY
toolbar_moving = {
bounds: {
x: that.dom.offsetWidth - toolbar.offsetWidth - 20,
// XXX this gets off on high magnifications...
y: that.dom.offsetHeight - toolbar.offsetHeight - 20,
},
offset: {
x: x - toolbar.offsetLeft,
y: y - toolbar.offsetTop,
},
touch: evt.targetTouches ?
evt.targetTouches[0].identifier
: undefined,
} } }
var handleToolbarMoveEnd = function(evt){
if(toolbar_moving){
if(evt.targetTouches
&& (evt.targetTouches.length == 0
|| getTouch(evt, toolbar_moving.touch))){
return }
hide_timeout = setTimeout(
function(){
hide_timeout = undefined
that.toggleToolbar('hide') },
that.toolbar_autohide ?? 1000) })
toolbar
.addEventListener('mouseover', function(evt){
hide_timeout
&& clearTimeout(hide_timeout)
hide_timeout = undefined })
evt.preventDefault()
evt.stopPropagation()
toolbar.classList.remove('moving')
toolbar_moving = false } }
// XXX ignore non-local touches...
// XXX disable button clicking while moving...
var handleToolbarMove = function(evt){
if(toolbar_moving){
var src = toolbar_moving.touch != null ?
getTouch(evt, toolbar_moving.touch)
: evt
if(!src){
return }
evt.preventDefault()
evt.stopPropagation()
var x = src.clientX
var y = src.clientY
toolbar_moving.x =
toolbar_moving.bounds?.x != null ?
Math.min(toolbar_moving.bounds.x,
Math.max(0,
x - toolbar_moving.offset.x))
: x - toolbar_moving.offset.x
toolbar_moving.y =
toolbar_moving.bounds?.y != null ?
Math.min(toolbar_moving.bounds.y,
Math.max(0,
y - toolbar_moving.offset.y))
: y - toolbar_moving.offset.y
// NOTE: we only allow a single requestAnimationFrame(..)
// to run per frame...
if(!toolbar_moving.animate){
toolbar_moving.animate = requestAnimationFrame(function(){
if(!toolbar_moving){
return }
toolbar.style.setProperty('--move-x', toolbar_moving.x + 'px')
toolbar.style.setProperty('--move-y', toolbar_moving.y + 'px')
delete toolbar_moving.animate }) } } }
// XXX to drag anywhere on the toolbar we need to prevent
// clicks while dragging...
toolbar.querySelector('.drag-handle')
.addEventListener('mousedown', handleToolbarMoveStart)
toolbar.querySelector('.drag-handle')
.addEventListener('touchstart', handleToolbarMoveStart)
this.dom.addEventListener('mousemove', handleToolbarMove)
this.dom.addEventListener('touchmove', handleToolbarMove)
document.addEventListener('touchend', handleToolbarMoveEnd)
document.addEventListener('mouseup', handleToolbarMoveEnd)
//*/
// image clicks...
this.dom.querySelector('.images')
@ -937,6 +1054,7 @@ var Gallery = {
.addEventListener('click', function(evt){
that.unmark_current
&& (that.current = null) })
// drag/drop: sort...
var dragged
this.dom
@ -944,7 +1062,10 @@ var Gallery = {
var i = that.images.indexOf(evt.target)
if(i >= 0){
dragged = evt.target
dragged.classList.add('dragged') } })
dragged.classList.add('dragged')
evt.dataTransfer.setDragImage(dragged, evt.offsetX, evt.offsetY)
// XXX add
} })
var skip_dragover = false
this.dom
.addEventListener('dragenter', function(evt){