diff --git a/README.md b/README.md index dabd63b..7d6c9a2 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ There is trivial security on the web pages to allow for multiple user support. - css framework > [bulma.io](https://www.bulma.io) - js framework > [reef](https://reefjs.com) +- pin zoom > [lightgallery.js](https://sachinchoolur.github.io/lightgallery.js/) - boards icon > [squares by Andrejs Kirma from the Noun Project](https://thenounproject.com/term/squares/1160031/) - pin icon > [pinned by Gregor Cresnar from the Noun Project](https://thenounproject.com/term/pinned/1560993/) - web icon > [website by Supriadi Sihotang from the Noun Project](https://thenounproject.com/term/website/2868662/) diff --git a/TODO.md b/TODO.md index 415e277..a35149d 100644 --- a/TODO.md +++ b/TODO.md @@ -11,5 +11,5 @@ - sqlite3 may need to be compiled, but seems to happen automatically (albeit slow) - support receiving data urls - support uploading images -- left/right arrow links on pinzoom - +- ~~left/right arrow links on pinzoom~~ (replaced with lightgallery) +- enable drag up/down to close lightgallery diff --git a/static/app.js b/static/app.js index 4d35938..20a7ebc 100644 --- a/static/app.js +++ b/static/app.js @@ -46,7 +46,6 @@ app.addSetter('load.user', async (data) => { }); app.addSetter("hash.update", (data) => { - console.log("hash update"); data.hash = parseQueryString(window.location.hash.substr(1)); if ( data.hash.board ){ @@ -148,8 +147,7 @@ document.addEventListener('click', (el) => { // we always want to close the menu on click. if we clicked an item, // that will still trigger below let burger = el.target.closest('.navbar-burger'); - console.log("the burger is: ", burger); - if ( !burger ){ + if ( !burger && store.data.menuOpen ){ store.do('navbar.closeMenu'); } @@ -162,6 +160,14 @@ document.addEventListener('click', (el) => { } catch (err){ console.error(`Error invoking ${action}:`, err); } + } + } else { + let targetx = el.target.closest('[data-onclick-x]'); // onclick-x attempts to invoke a function on window instead of a setter. this is useful to bypass re-rendering + if ( targetx ){ + let actionx = targetx.getAttribute('data-onclick-x'); + if ( actionx ){ + window[actionx](targetx); + } } } diff --git a/static/client.css b/static/client.css index 112b339..af0de7f 100644 --- a/static/client.css +++ b/static/client.css @@ -293,4 +293,87 @@ .navbar-item span, .navbar-item img{ line-height: 24px; vertical-align: middle; +} + +.modal-background { + background-color:#000; + opacity: 0.9; +} + +/* lightgallery customizations */ +.lg-actions .lg-next.disabled, .lg-actions .lg-prev.disabled { + opacity: 0; +} + +.lg-outer .lg-image { + width: 90%!important; + height: 90%!important; + object-fit: contain; +} + +.supports-touch .lg-prev, .supports-touch .lg-next{ + display: none; +} + +.lg-backdrop.in { + opacity: 0.9; +} + +#lg-edit { + background-image: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjRkZGRkZGIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHg9IjBweCIgeT0iMHB4Ij48dGl0bGU+NTE8L3RpdGxlPjxwYXRoIGQ9Ik04NC44NTAxMiw1MFY4MS43NDUxMkExMy4yNzAxMiwxMy4yNzAxMiwwLDAsMSw3MS41OTUyNCw5NUgxOC4yNTQ5MUExMy4yNzAxMiwxMy4yNzAxMiwwLDAsMSw1LDgxLjc0NTEyVjI4LjQwNTI4QTEzLjI3MDEyLDEzLjI3MDEyLDAsMCwxLDE4LjI1NDkxLDE1LjE1MDRINTBhMi41LDIuNSwwLDAsMSwwLDVIMTguMjU0OTFBOC4yNjQyMyw4LjI2NDIzLDAsMCwwLDEwLDI4LjQwNTI4VjgxLjc0NTEyQTguMjY0MjQsOC4yNjQyNCwwLDAsMCwxOC4yNTQ5MSw5MEg3MS41OTUyNGE4LjI2NDIzLDguMjY0MjMsMCwwLDAsOC4yNTQ4OC04LjI1NDg5VjUwYTIuNSwyLjUsMCwwLDEsNSwwWk04OS4xNDg0Niw2LjIzNzkyYTQuMjI2NjEsNC4yMjY2MSwwLDAsMC01Ljk3NzI5LDBsLTMzLjk2MjksMzMuOTYzTDU5Ljc5OTE2LDUwLjc5MTc2bDMzLjk2Mjg5LTMzLjk2M2E0LjIyNjUzLDQuMjI2NTMsMCwwLDAsMC01Ljk3NzIzWk00My42MjM4LDU4LjMxMjg3bDEzLjAwOTQtNC4zNTUxNkw0Ni4wNDIyNiw0My4zNjY4M2wtNC4zNTUxLDEzLjAwOTRBMS41MzAwNSwxLjUzMDA1LDAsMCwwLDQzLjYyMzgsNTguMzEyODdaIj48L3BhdGg+PC9zdmc+"); + background-repeat: no-repeat; + background-size: 20px 20px; + background-position: 17px 13px; + opacity: 0.7; + transition: opacity 0.2s linear; +} + +#lg-edit:hover { + opacity: 1; +} + +#lg-siteUrl { + background-image: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjRkZGRkZGIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczp4b2RtPSJodHRwOi8vd3d3LmNvcmVsLmNvbS9jb3JlbGRyYXcvb2RtLzIwMDMiIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgc3R5bGU9InNoYXBlLXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb247dGV4dC1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uO2ltYWdlLXJlbmRlcmluZzpvcHRpbWl6ZVF1YWxpdHk7IiB2aWV3Qm94PSIwIDAgMzIwIDMxOS45OSIgeD0iMHB4IiB5PSIwcHgiIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIj48ZGVmcz48c3R5bGUgdHlwZT0idGV4dC9jc3MiPgogICAKICAgIC5maWwwIHtmaWxsOiNGRkZGRkY7ZmlsbC1ydWxlOm5vbnplcm99CiAgIAogIDwvc3R5bGU+PC9kZWZzPjxnPjxwYXRoIGNsYXNzPSJmaWwwIiBkPSJNMTYwIDI4My4zM2MzNC4wNiwwIDY0LjksLTEzLjgxIDg3LjIxLC0zNi4xMiAyMi4zMSwtMjIuMzEgMzYuMTIsLTUzLjE2IDM2LjEyLC04Ny4yMSAwLC0zNC4wNiAtMTMuODEsLTY0Ljg5IC0zNi4xMiwtODcuMjEgLTIyLjMxLC0yMi4zMSAtNTMuMTYsLTM2LjEzIC04Ny4yMSwtMzYuMTMgLTM0LjA2LDAgLTY0LjksMTMuODEgLTg3LjIxLDM2LjEzIC0yMi4zMSwyMi4zMSAtMzYuMTMsNTMuMTUgLTM2LjEzLDg3LjIxIDAsMzQuMDYgMTMuODEsNjQuOSAzNi4xMyw4Ny4yMSAyMi4zMSwyMi4zMSA1My4xNSwzNi4xMiA4Ny4yMSwzNi4xMnptMTAxLjM1IC0yMS45OGMtMjUuOTQsMjUuOTMgLTYxLjc4LDQxLjk4IC0xMDEuMzUsNDEuOTggLTM5LjU4LDAgLTc1LjQyLC0xNi4wNSAtMTAxLjM1LC00MS45OCAtMjUuOTQsLTI1Ljk0IC00MS45OCwtNjEuNzggLTQxLjk4LC0xMDEuMzUgMCwtMzkuNTggMTYuMDUsLTc1LjQyIDQxLjk4LC0xMDEuMzUgMjUuOTMsLTI1Ljk0IDYxLjc3LC00MS45OCAxMDEuMzUsLTQxLjk4IDM5LjU4LDAgNzUuNDIsMTYuMDUgMTAxLjM1LDQxLjk4IDI1LjkzLDI1LjkzIDQxLjk4LDYxLjc3IDQxLjk4LDEwMS4zNSAwLDM5LjU4IC0xNi4wNSw3NS40MiAtNDEuOTgsMTAxLjM1eiI+PC9wYXRoPjxwYXRoIGNsYXNzPSJmaWwwIiBkPSJNMjYuNjYgMTY5Ljg2Yy01LjUsMCAtOS45NiwtNC40NiAtOS45NiwtOS45NiAwLC01LjUgNC40NiwtOS45NiA5Ljk2LC05Ljk2bDI2Ni42NyAtMS4wNGM1LjUsMCA5Ljk2LDQuNDYgOS45Niw5Ljk2IDAsNS41IC00LjQ2LDkuOTYgLTkuOTYsOS45NmwtMjY2LjY3IDEuMDR6Ij48L3BhdGg+PHBhdGggY2xhc3M9ImZpbDAiIGQ9Ik0xNDkuNTIgMjYuNjZjMCwtNS41IDQuNDYsLTkuOTYgOS45NiwtOS45NiA1LjUsMCA5Ljk2LDQuNDYgOS45Niw5Ljk2bDEuMDQgMjY2LjY3YzAsNS41IC00LjQ2LDkuOTYgLTkuOTYsOS45NiAtNS41LDAgLTkuOTYsLTQuNDYgLTkuOTYsLTkuOTZsLTEuMDQgLTI2Ni42N3oiPjwvcGF0aD48cGF0aCBjbGFzcz0iZmlsMCIgZD0iTTE2MCAyODMuMzNjMTQuMzIsMCAyNy44OSwtMTIuODEgMzguMjQsLTMzLjUxIDExLjM5LC0yMi43NyAxOC40MywtNTQuNTIgMTguNDMsLTg5LjgzIDAsLTM1LjMxIC03LjA1LC02Ny4wNiAtMTguNDMsLTg5LjgzIC0xMC4zNSwtMjAuNyAtMjMuOTEsLTMzLjUxIC0zOC4yNCwtMzMuNTEgLTE0LjMyLDAgLTI3Ljg5LDEyLjgxIC0zOC4yNCwzMy41MSAtMTEuMzksMjIuNzcgLTE4LjQzLDU0LjUyIC0xOC40Myw4OS44MyAwLDM1LjMxIDcuMDUsNjcuMDYgMTguNDMsODkuODMgMTAuMzUsMjAuNyAyMy45MSwzMy41MSAzOC4yNCwzMy41MXptNTYuMDUgLTI0LjZjLTEzLjc3LDI3LjU2IC0zMy41NSw0NC42IC01Ni4wNSw0NC42IC0yMi41LDAgLTQyLjI4LC0xNy4wNSAtNTYuMDUsLTQ0LjYgLTEyLjc0LC0yNS40NyAtMjAuNjIsLTYwLjQxIC0yMC42MiwtOTguNzMgMCwtMzguMzMgNy44OCwtNzMuMjYgMjAuNjIsLTk4LjczIDEzLjc3LC0yNy41NiAzMy41NSwtNDQuNiA1Ni4wNSwtNDQuNiAyMi41LDAgNDIuMjgsMTcuMDUgNTYuMDUsNDQuNiAxMi43NCwyNS40NyAyMC42Miw2MC40MSAyMC42Miw5OC43MyAwLDM4LjMzIC03Ljg4LDczLjI2IC0yMC42Miw5OC43M3oiPjwvcGF0aD48cGF0aCBjbGFzcz0iZmlsMCIgZD0iTTQ1LjcgMTA0LjA0Yy01LjUsMC4wMiAtOS45OCwtNC40MiAtMTAsLTkuOTIgLTAuMDIsLTUuNSA0LjQyLC05Ljk4IDkuOTIsLTEwbDIyOC42OCAtMS4wNGM1LjUsLTAuMDIgOS45OCw0LjQyIDEwLDkuOTIgMC4wMiw1LjUgLTQuNDIsOS45OCAtOS45MiwxMGwtMjI4LjY4IDEuMDR6Ij48L3BhdGg+PHBhdGggY2xhc3M9ImZpbDAiIGQ9Ik00NS43IDIzNy40MmMtNS41LDAuMDIgLTkuOTgsLTQuNDIgLTEwLC05LjkyIC0wLjAyLC01LjUgNC40MiwtOS45OCA5LjkyLC0xMGwyMjguNjggLTEuMDRjNS41LC0wLjAyIDkuOTgsNC40MiAxMCw5LjkyIDAuMDIsNS41IC00LjQyLDkuOTggLTkuOTIsMTBsLTIyOC42OCAxLjA0eiI+PC9wYXRoPjwvZz48L3N2Zz4="); + background-repeat: no-repeat; + background-size: 20px 20px; + background-position: 16px 14px; + opacity: 0.7; + transition: opacity 0.2s linear; +} + +#lg-siteUrl:hover { + opacity: 1; +} + +#lg-deletePin { + background-image: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjRkZGRkZGIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHg9IjBweCIgeT0iMHB4Ij48dGl0bGU+dHJhc2g8L3RpdGxlPjxwYXRoIGQ9Ik05MC42OSwxMi4yMlYxOGEyLjkxLDIuOTEsMCwwLDEtMi45MSwyLjkxSDEyLjIyQTIuOTEsMi45MSwwLDAsMSw5LjMxLDE4VjEyLjIyYTIuOTEsMi45MSwwLDAsMSwyLjkxLTIuOTFIMzRsMS43MS0zLjRBNC43Miw0LjcyLDAsMCwxLDM5LjU5LDMuNUg2MC4zOGE0Ljc4LDQuNzgsMCwwLDEsMy45LDIuNDFMNjYsOS4zMWgyMS44QTIuOTEsMi45MSwwLDAsMSw5MC42OSwxMi4yMlpNMTUuMTMsMjYuNzVIODQuODh2NjFhOC43Miw4LjcyLDAsMCwxLTguNzIsOC43MkgyMy44NGE4LjcyLDguNzIsMCwwLDEtOC43Mi04LjcyWk0yOS42Niw4MmEyLjkxLDIuOTEsMCwwLDAsNS44MSwwVjQxLjI4YTIuOTEsMi45MSwwLDAsMC01LjgxLDBabTE3LjQ0LDBhMi45MSwyLjkxLDAsMCwwLDUuODEsMFY0MS4yOGEyLjkxLDIuOTEsMCwwLDAtNS44MSwwWm0xNy40NCwwYTIuOTEsMi45MSwwLDAsMCw1LjgxLDBWNDEuMjhhMi45MSwyLjkxLDAsMCwwLTUuODEsMFoiPjwvcGF0aD48L3N2Zz4="); + background-repeat: no-repeat; + background-size: 20px 20px; + background-position: 16px 14px; + opacity: 0.7; + transition: opacity 0.2s linear; +} + +#lg-deletePin:hover{ + opacity: 1; +} + +.lg-control-hide { + display: none; +} + + +.lg-sub-html { + opacity: 1; + transition: .35s cubic-bezier(0,0,.25,1) 0s, opacity .35s cubic-bezier(0,0,.25,1) 0s, color .2s linear; +} + +.lg-touch-hide-items .lg-sub-html{ + opacity: 0; + transform: translate3d(0,10px,0); +} + +.lg-touch-hide-items .lg-toolbar { + opacity: 0; + transform: translate3d(0,-10px,0); } \ No newline at end of file diff --git a/static/components/about.js b/static/components/about.js index fca785e..6ff95c3 100644 --- a/static/components/about.js +++ b/static/components/about.js @@ -28,6 +28,8 @@ app.addComponent('aboutModal', (store) => { return new Reef("#aboutModal", {
 ui framework » reef
+  pin zoom » lightgallery.js +
 boards icon » squares by Andrejs Kirma from the Noun Project
 pin icon » pinned by Gregor Cresnar from the Noun Project diff --git a/static/components/addpin.js b/static/components/addpin.js index b4743e1..fd16e92 100644 --- a/static/components/addpin.js +++ b/static/components/addpin.js @@ -24,7 +24,6 @@ app.addSetter('addPinModal.close', (data) => { }); app.addSetter('addPinModal.updatePreview', (data) => { - console.log("update preview"); if ( data.addPinModal.imageUrl.startsWith("http") ){ ( async() => { let res = await fetch(data.addPinModal.imageUrl, { diff --git a/static/components/brickwall.js b/static/components/brickwall.js index b9cf2d8..8e7c1be 100644 --- a/static/components/brickwall.js +++ b/static/components/brickwall.js @@ -3,6 +3,119 @@ app.addSetter('brickwall.toggleHiddenBoards', (data) => { window.localStorage.showHiddenBoards = data.showHiddenBoards; }); +app.addSetter("brickwall.editPin", (data) => { + + let index = getLightGalleryIndex(); + + + data.editPinModal.pin = store.data.board.pins[index]; + + store.do('editPinModal.open'); + + closeLightGallery(); +}); + +app.addSetter("brickwall.deletePin", async (data) => { + if ( !confirm("Are you sure you want to delete this pin?" ) ){ + return; + } + + store.do('loader.show'); + + let index = getLightGalleryIndex(); + + let pinId = data.board.pins[index].id; + + data.board.pins.splice(index,1); + + // store.do("pinZoomModal.close"); + closeLightGallery(); + + let res = await fetch(`api/pins/${pinId}`, { + method: 'DELETE' + }); + + if ( res.status == 200 ){ + console.log(`deleted pin#${pinId}`); + } else { + console.error(`error deleting pin#${pinId}`); + } + + store.do('loader.hide'); +}); + +var supportsTouch = 'ontouchstart' in window; +if ( supportsTouch ){ + document.body.classList.add("supports-touch"); +} +let lightgalleryElement = document.getElementById("lightgallery"); +let lightgalleryOpen = false; + +function openLightGallery(pinId){ + + let data = store.data; + + let elements = []; + let index = 0; + + for ( let i = 0; i < data.board.pins.length; ++i ){ + elements.push({ + src: getOriginalImagePath(data.board.pins[i].id), + subHtml: data.board.pins[i].description, + siteUrl: data.board.pins[i].siteUrl + }); + if ( data.board.pins[i].id == pinId ){ + index = i; + } + } + + let options = { + speed: 333, + loop: false, + hideControlOnEnd: true, + preload: 3, + slideEndAnimatoin: false, + dynamic: true, + dynamicEl: elements, + index: index, + download: false, + startClass: '', // disable zoom + backdropDuration: 0 // disable animate in + }; + + lightGallery(lightgalleryElement, options ); + lightgalleryOpen = true; +} + +function closeLightGallery(){ + lightgalleryOpen = false; + let uid = lightgalleryElement.getAttribute("lg-uid"); + window.lgData[uid].destroy(); +} + +function getLightGalleryIndex(){ + let uid = lightgalleryElement.getAttribute("lg-uid"); + return window.lgData[uid].index; +} + +document.getElementById("lightgallery").addEventListener("onCloseAfter", () => { + + let uid = lightgalleryElement.getAttribute("lg-uid"); + if ( uid ){ + window.lgData[uid].destroy(true); + } + +}); + +document.getElementById("lightgallery").addEventListener("onSlideClick", () => { + let lgOuter = document.querySelector(".lg-outer"); + if ( lgOuter.classList.contains("lg-touch-hide-items") ){ + lgOuter.classList.remove("lg-touch-hide-items"); + } else { + lgOuter.classList.add("lg-touch-hide-items"); + } +}); + app.addComponent('brickwall', (store) => { return new Reef('#brickwall', { store: store, @@ -82,8 +195,8 @@ app.addComponent('brickwall', (store) => { return new Reef('#brickwall', { function createBrickForPin(board, pin){ return { height: pin.thumbnailHeight, template: /*html*/`
- - + +
`}; diff --git a/static/components/editboard.js b/static/components/editboard.js index a74cf0a..b238be7 100644 --- a/static/components/editboard.js +++ b/static/components/editboard.js @@ -62,7 +62,6 @@ app.addSetter('editBoardModal.delete', async (data) => { let idx = getBoardIndexById(boardId); - console.log(idx); if ( idx >= 0 ){ data.boards.splice(idx, 1); } diff --git a/static/components/editpin.js b/static/components/editpin.js index 696b514..e60fc0f 100644 --- a/static/components/editpin.js +++ b/static/components/editpin.js @@ -5,9 +5,13 @@ app.addSetter('editPinModal.open', (data) => { app.addSetter('editPinModal.close', (data) => { data.editPinModal.active = false; + let pinId = data.editPinModal.pin.id; + data.editPinModal.pin = null; data.editPinModal.newBoardName = null; data.editPinModal.saveInProgress = false; + + openLightGallery(pinId); }); app.addGetter('editPinModal.isValid', (data) => { @@ -88,8 +92,6 @@ app.addSetter("editPinModal.save", async (data) => { data.board.pins[idx].boardId = boardId; data.board.pins[idx].siteUrl = pin.siteUrl; data.board.pins[idx].description = pin.description; - - console.log(data.board.pins[idx]); store.do("editPinModal.close"); } else { @@ -111,13 +113,8 @@ app.addComponent('editPinModal', (store) => { return new Reef("#editPinModal", { options += ``; } - console.log("render", data); - - console.log("set new board field"); let newBoardField = ''; if ( data.editPinModal.pin && data.editPinModal.pin.boardId == "new" ){ - // if ( true ) { - console.log("is new"); newBoardField = /*html*/`
@@ -126,13 +123,7 @@ app.addComponent('editPinModal', (store) => { return new Reef("#editPinModal", {
`; - } - - if ( data.editPinModal.pin ){ - console.log(getThumbnailImagePath(data.editPinModal.pin.id)); - } - - + } return /*html*/`