1
0
Fork 0
mirror of https://github.com/alangrainger/immich-public-proxy.git synced 2025-01-28 02:02:42 +01:00

Merge pull request from tenekev/main

Improved layout with Isotope Masonry and the loading experience with the Immich loading stencil
This commit is contained in:
Alan Grainger 2024-12-19 09:26:46 +13:00 committed by GitHub
commit 48e1ef832d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 232 additions and 38 deletions

View file

@ -0,0 +1,12 @@
/*!
* imagesLoaded PACKAGED v5.0.0
* JavaScript is all like "You images are done yet or what?"
* MIT License
*/
!function(t,e){"object"==typeof module&&module.exports?module.exports=e():t.EvEmitter=e()}("undefined"!=typeof window?window:this,(function(){function t(){}let e=t.prototype;return e.on=function(t,e){if(!t||!e)return this;let i=this._events=this._events||{},s=i[t]=i[t]||[];return s.includes(e)||s.push(e),this},e.once=function(t,e){if(!t||!e)return this;this.on(t,e);let i=this._onceEvents=this._onceEvents||{};return(i[t]=i[t]||{})[e]=!0,this},e.off=function(t,e){let i=this._events&&this._events[t];if(!i||!i.length)return this;let s=i.indexOf(e);return-1!=s&&i.splice(s,1),this},e.emitEvent=function(t,e){let i=this._events&&this._events[t];if(!i||!i.length)return this;i=i.slice(0),e=e||[];let s=this._onceEvents&&this._onceEvents[t];for(let n of i){s&&s[n]&&(this.off(t,n),delete s[n]),n.apply(this,e)}return this},e.allOff=function(){return delete this._events,delete this._onceEvents,this},t})),
/*!
* imagesLoaded v5.0.0
* JavaScript is all like "You images are done yet or what?"
* MIT License
*/
function(t,e){"object"==typeof module&&module.exports?module.exports=e(t,require("ev-emitter")):t.imagesLoaded=e(t,t.EvEmitter)}("undefined"!=typeof window?window:this,(function(t,e){let i=t.jQuery,s=t.console;function n(t,e,o){if(!(this instanceof n))return new n(t,e,o);let r=t;var h;("string"==typeof t&&(r=document.querySelectorAll(t)),r)?(this.elements=(h=r,Array.isArray(h)?h:"object"==typeof h&&"number"==typeof h.length?[...h]:[h]),this.options={},"function"==typeof e?o=e:Object.assign(this.options,e),o&&this.on("always",o),this.getImages(),i&&(this.jqDeferred=new i.Deferred),setTimeout(this.check.bind(this))):s.error(`Bad element for imagesLoaded ${r||t}`)}n.prototype=Object.create(e.prototype),n.prototype.getImages=function(){this.images=[],this.elements.forEach(this.addElementImages,this)};const o=[1,9,11];n.prototype.addElementImages=function(t){"IMG"===t.nodeName&&this.addImage(t),!0===this.options.background&&this.addElementBackgroundImages(t);let{nodeType:e}=t;if(!e||!o.includes(e))return;let i=t.querySelectorAll("img");for(let t of i)this.addImage(t);if("string"==typeof this.options.background){let e=t.querySelectorAll(this.options.background);for(let t of e)this.addElementBackgroundImages(t)}};const r=/url\((['"])?(.*?)\1\)/gi;function h(t){this.img=t}function d(t,e){this.url=t,this.element=e,this.img=new Image}return n.prototype.addElementBackgroundImages=function(t){let e=getComputedStyle(t);if(!e)return;let i=r.exec(e.backgroundImage);for(;null!==i;){let s=i&&i[2];s&&this.addBackground(s,t),i=r.exec(e.backgroundImage)}},n.prototype.addImage=function(t){let e=new h(t);this.images.push(e)},n.prototype.addBackground=function(t,e){let i=new d(t,e);this.images.push(i)},n.prototype.check=function(){if(this.progressedCount=0,this.hasAnyBroken=!1,!this.images.length)return void this.complete();let t=(t,e,i)=>{setTimeout((()=>{this.progress(t,e,i)}))};this.images.forEach((function(e){e.once("progress",t),e.check()}))},n.prototype.progress=function(t,e,i){this.progressedCount++,this.hasAnyBroken=this.hasAnyBroken||!t.isLoaded,this.emitEvent("progress",[this,t,e]),this.jqDeferred&&this.jqDeferred.notify&&this.jqDeferred.notify(this,t),this.progressedCount===this.images.length&&this.complete(),this.options.debug&&s&&s.log(`progress: ${i}`,t,e)},n.prototype.complete=function(){let t=this.hasAnyBroken?"fail":"done";if(this.isComplete=!0,this.emitEvent(t,[this]),this.emitEvent("always",[this]),this.jqDeferred){let t=this.hasAnyBroken?"reject":"resolve";this.jqDeferred[t](this)}},h.prototype=Object.create(e.prototype),h.prototype.check=function(){this.getIsImageComplete()?this.confirm(0!==this.img.naturalWidth,"naturalWidth"):(this.proxyImage=new Image,this.img.crossOrigin&&(this.proxyImage.crossOrigin=this.img.crossOrigin),this.proxyImage.addEventListener("load",this),this.proxyImage.addEventListener("error",this),this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.proxyImage.src=this.img.currentSrc||this.img.src)},h.prototype.getIsImageComplete=function(){return this.img.complete&&this.img.naturalWidth},h.prototype.confirm=function(t,e){this.isLoaded=t;let{parentNode:i}=this.img,s="PICTURE"===i.nodeName?i:this.img;this.emitEvent("progress",[this,s,e])},h.prototype.handleEvent=function(t){let e="on"+t.type;this[e]&&this[e](t)},h.prototype.onload=function(){this.confirm(!0,"onload"),this.unbindEvents()},h.prototype.onerror=function(){this.confirm(!1,"onerror"),this.unbindEvents()},h.prototype.unbindEvents=function(){this.proxyImage.removeEventListener("load",this),this.proxyImage.removeEventListener("error",this),this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},d.prototype=Object.create(h.prototype),d.prototype.check=function(){this.img.addEventListener("load",this),this.img.addEventListener("error",this),this.img.src=this.url,this.getIsImageComplete()&&(this.confirm(0!==this.img.naturalWidth,"naturalWidth"),this.unbindEvents())},d.prototype.unbindEvents=function(){this.img.removeEventListener("load",this),this.img.removeEventListener("error",this)},d.prototype.confirm=function(t,e){this.isLoaded=t,this.emitEvent("progress",[this,this.element,e])},n.makeJQueryPlugin=function(e){(e=e||t.jQuery)&&(i=e,i.fn.imagesLoaded=function(t,e){return new n(this,t,e).jqDeferred.promise(i(this))})},n.makeJQueryPlugin(),n}));

12
app/public/metafizzy/isotope.min.js vendored Normal file

File diff suppressed because one or more lines are too long

9
app/public/metafizzy/masonry.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,36 +1,71 @@
:root {
--gallery-width-ultrawide: 1900px;
--gallery-width-desktop: 90%;
--gallery-width-tablet: 90%;
--gallery-width-mobile: 98%;
--color-1: #191919;
--stencil-width: 150px;
}
html { html {
background: #191919; background: var(--color-1);
}
#lightgallery {
max-width: var(--gallery-width-mobile);
margin: 0 auto;
}
@media screen and (min-width: 600px) {
#lightgallery {
max-width: var(--gallery-width-tablet);
}
}
@media screen and (min-width: 900px) {
#lightgallery {
max-width: var(--gallery-width-desktop);
}
}
@media screen and (min-width: 1950px) {
#lightgallery {
max-width: var(--gallery-width-ultrawide);
}
} }
#lightgallery a { #lightgallery a {
position: relative; width: 400px;
display: inline-block; max-width: calc(50% - 6px);
text-decoration: none; margin: 3px;
margin: 0;
padding: 0;
cursor: pointer;
}
#lightgallery img {
max-height: 250px;
margin: 4px;
}
@media (max-width: 800px) {
#lightgallery a {
width: calc(100vw / 3 - 10px);
height: calc(100vw / 3 - 10px);
overflow: hidden; overflow: hidden;
} }
#lightgallery img { @media screen and (min-width: 600px) {
width: 100%; #lightgallery a {
height: 100%; max-width: calc(33.33333% - 10px);
object-fit: cover; margin: 5px;
object-position: center;
} }
} }
@media screen and (min-width: 900px) {
#lightgallery a {
max-width: calc(20% - 10px);
}
}
#lightgallery a img {
width: 100%;
position: relative;
display: block;
transition: transform .15s ease-in, filter .15s ease-in;
}
#lightgallery a:hover img {
transform: scale(1.1);
filter: brightness(0.7);
}
.play-icon { .play-icon {
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -68,3 +103,41 @@ html {
#download-all { #download-all {
margin: auto 4px auto auto; margin: auto 4px auto auto;
} }
#page-loader {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
flex-wrap: wrap;
z-index: 999999;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--color-1)
}
#stencil {
display: flex;
width: var(--stencil-width);
margin-left: auto;
margin-right: auto;
margin-top: calc(50vh - var(--stencil-width) / 2);
margin-bottom: 100vh;
place-items: center;
justify-content: center;
overflow: hidden;
visibility: hidden;
animation: 0s linear 0.3s forwards delayedVisibility, loadspin 8s linear infinite;
}
@keyframes delayedVisibility {
to {
visibility: visible;
}
}
@keyframes loadspin {
100% {
transform: rotate(360deg);
}
}

View file

@ -1,11 +1,41 @@
function initLightGallery (config = {}) { function initLightGallery (config = {}) {
lightGallery(document.getElementById('lightgallery'), Object.assign({ /* Preloader */
plugins: [lgZoom, lgThumbnail, lgVideo, lgFullscreen], const preloader = document.getElementById('page-loader');
if (preloader) {
const fadeEffect = () => {
setInterval(() => {
if (!preloader.style.opacity) { preloader.style.opacity = 1; }
if (preloader.style.opacity > 0) { preloader.style.opacity -= 0.1;}
else {
clearInterval(fadeEffect);
preloader.remove();
}
}, 20)
}
window.addEventListener('load', fadeEffect);
}
/* Init Gallery */
masonryElMixed = document.getElementById('lightgallery'),
masonryElMixed && imagesLoaded( document.getElementById('lightgallery'), function() {
masonry = new Masonry(masonryElMixed,{
itemSelector: '.grid-item',
percentPosition: true,
gutter: 0,
columnWidth: '.lg-item:first-of-type' //Taken from first item. Can put .Class as selector
})
masonry.layout()
lgallery = window.lightGallery(masonryElMixed, Object.assign({
selector: '.lg-item',
animateThumb: true,
/* /*
This license key was graciously provided by LightGallery under their This license key was graciously provided by LightGallery under their
GPLv3 open-source project license: GPLv3 open-source project license:
*/ */
licenseKey: '8FFA6495-676C4D30-8BFC54B6-4D0A6CEC' licenseKey: '8FFA6495-676C4D30-8BFC54B6-4D0A6CEC',
/* /*
Please do not take it and use it for other projects, as it was provided Please do not take it and use it for other projects, as it was provided
specifically for Immich Public Proxy. specifically for Immich Public Proxy.
@ -15,5 +45,20 @@ function initLightGallery (config = {}) {
https://www.lightgalleryjs.com/docs/settings/#licenseKey https://www.lightgalleryjs.com/docs/settings/#licenseKey
*/ */
}, config)) plugins: [
lgFullscreen,
lgThumbnail,
lgVideo,
lgZoom
],
hash: true,
toggleThumb: true,
allowMediaOverlap: true,
subHtmlSelectorRelative: true,
zoomFromOrigin: true,
}), config)
})
} }

View file

@ -8,6 +8,46 @@
<link type="text/css" rel="stylesheet" href="/share/static/lg/lightgallery-bundle.min.css"/> <link type="text/css" rel="stylesheet" href="/share/static/lg/lightgallery-bundle.min.css"/>
</head> </head>
<body> <body>
<div id="page-loader">
<div id="stencil">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 792 792">
<style type="text/css">
.st0 {
fill: #fa2921;
}
.st1 {
fill: #ed79b5;
}
.st2 {
fill: #ffb400;
}
.st3 {
fill: #1e83f7;
}
.st4 {
fill: #18c249;
}
</style>
<g>
<path class="st0" d="M375.48,267.63c38.64,34.21,69.78,70.87,89.82,105.42c34.42-61.56,57.42-134.71,57.71-181.3
c0-0.33,0-0.63,0-0.91c0-68.94-68.77-95.77-128.01-95.77s-128.01,26.83-128.01,95.77c0,0.94,0,2.2,0,3.72
C300.01,209.24,339.15,235.47,375.48,267.63z"></path>
<path class="st1" d="M164.7,455.63c24.15-26.87,61.2-55.99,103.01-80.61c44.48-26.18,88.97-44.47,128.02-52.84
c-47.91-51.76-110.37-96.24-154.6-110.91c-0.31-0.1-0.6-0.19-0.86-0.28c-65.57-21.3-112.34,35.81-130.64,92.15
c-18.3,56.34-14.04,130.04,51.53,151.34C162.05,454.77,163.25,455.16,164.7,455.63z"></path>
<path class="st2" d="M681.07,302.19c-18.3-56.34-65.07-113.45-130.64-92.15c-0.9,0.29-2.1,0.68-3.54,1.15
c-3.75,35.93-16.6,81.27-35.96,125.76c-20.59,47.32-45.84,88.27-72.51,118c69.18,13.72,145.86,12.98,190.26-1.14
c0.31-0.1,0.6-0.2,0.86-0.28C695.11,432.22,699.37,358.52,681.07,302.19z"></path>
<path class="st3" d="M336.54,510.71c-11.15-50.39-14.8-98.36-10.7-138.08c-64.03,29.57-125.63,75.23-153.26,112.76
c-0.19,0.26-0.37,0.51-0.53,0.73c-40.52,55.78-0.66,117.91,47.27,152.72c47.92,34.82,119.33,53.54,159.86-2.24
c0.56-0.76,1.3-1.78,2.19-3.01C363.28,602.32,347.02,558.08,336.54,510.71z"></path>
<path class="st4" d="M617.57,482.52c-35.33,7.54-82.42,9.33-130.72,4.66c-51.37-4.96-98.11-16.32-134.63-32.5
c8.33,70.03,32.73,142.73,59.88,180.6c0.19,0.26,0.37,0.51,0.53,0.73c40.52,55.78,111.93,37.06,159.86,2.24
c47.92-34.82,87.79-96.95,47.27-152.72C619.2,484.77,618.46,483.75,617.57,482.52z"></path>
</g>
</svg>
</div>
</div>
<div id="header"> <div id="header">
<% if (showTitle) { %> <% if (showTitle) { %>
<h1><%- title || 'Gallery' %></h1> <h1><%- title || 'Gallery' %></h1>
@ -27,7 +67,7 @@
<div id="lightgallery"> <div id="lightgallery">
<% items.forEach(item => { <% items.forEach(item => {
if (item.video) { %> if (item.video) { %>
<a data-video='<%- item.video %>' <a data-video='<%- item.video %>' class="lg-item grid-item"
<% if (item.downloadUrl) { %> <% if (item.downloadUrl) { %>
data-download-url="<%- item.downloadUrl %>" data-download-url="<%- item.downloadUrl %>"
<% } %> <% } %>
@ -36,7 +76,7 @@
<div class="play-icon"></div> <div class="play-icon"></div>
</a> </a>
<% } else { %> <% } else { %>
<a href="<%- item.previewUrl %>" <a href="<%- item.previewUrl %>" class="lg-item grid-item"
<% if (item.downloadUrl) { %> <% if (item.downloadUrl) { %>
data-download-url="<%- item.downloadUrl %>" data-download-url="<%- item.downloadUrl %>"
<% } %> <% } %>
@ -52,6 +92,9 @@
<script src="/share/static/lg/lg-thumbnail.min.js"></script> <script src="/share/static/lg/lg-thumbnail.min.js"></script>
<script src="/share/static/lg/lg-video.min.js"></script> <script src="/share/static/lg/lg-video.min.js"></script>
<script src="/share/static/lg/lg-zoom.min.js"></script> <script src="/share/static/lg/lg-zoom.min.js"></script>
<script src="/share/static/metafizzy/imagesloaded.min.js"></script>
<script src="/share/static/metafizzy/isotope.min.js"></script>
<script src="/share/static/metafizzy/masonry.min.js"></script>
<script type="text/javascript"> <script type="text/javascript">
initLightGallery(<%- JSON.stringify(lgConfig) %>) // initLightGallery imported from web.js initLightGallery(<%- JSON.stringify(lgConfig) %>) // initLightGallery imported from web.js
<% if (openItem) { %> <% if (openItem) { %>