add inline gallery, use for gallery details page

This commit is contained in:
j 2025-03-28 10:48:55 +00:00
parent f3fed29150
commit 55314b9fd1
4 changed files with 139 additions and 69 deletions

View file

@ -1,4 +1,4 @@
.gallery-dialog {
.gallery-dialog, .gallery-main-stage {
&:open {
background: #282828;
width: 100%;
@ -52,9 +52,6 @@
cursor: pointer;
border: 2px solid transparent;
}
.thumbnail.active {
border-color: blue;
}
.nav-btn {
cursor: pointer;
font-size: 20px;
@ -122,3 +119,27 @@
}
}
.gallery-main-stage {
.photo-container .image {
height: auto;
}
.download {
right: 4px
}
@media screen and (max-width: 39.9375em) {
.download {
}
}
}
.gallery-dialog, .inline-gallery {
.thumbnail {
cursor: pointer;
border: 2px solid transparent;
}
.thumbnail.active {
cursor: initial;
border-color: #1779ba;
}
}

View file

@ -1,9 +1,18 @@
function isNumber(x) {
return parseFloat(x) == x
};
function parseGalleryHash() {
let parts = document.location.hash.slice(1).split('/')
if (parts[0] == 'g') {
if (parts.lengh == 1 && isNumber(parts[0])) {
return {
"gallery": parseInt(parts[1], 10),
"image": parseInt(parts[2], 10),
'gallery': 'inline',
"image": parseInt(parts[0], 10) - 1,
}
} else if (parts.length == 2 && isNumber(parts[0]) && isNumber(parts[1])) {
return {
"gallery": parseInt(parts[0], 10) - 1,
"image": parseInt(parts[1], 10) - 1,
}
}
return {}
@ -11,7 +20,7 @@ function parseGalleryHash() {
function loadGalleries() {
let current = parseGalleryHash()
let galleryIdx = 1
let galleryIdx = 0
document.querySelectorAll('.gallery').forEach(gallery => {
var photos = [], dialog
gallery.querySelectorAll(".photo").forEach(img => {
@ -35,49 +44,77 @@ function loadGalleries() {
}
galleryIdx += 1
})
document.querySelectorAll('.inline-gallery').forEach(gallery => {
var photos = [], stage
gallery.querySelectorAll(".photo").forEach(img => {
const src = img.src.replace('_thumbnail', '_display')
let photo = {
src: src,
caption: img.dataset.caption,
orig: img.dataset.orig
}
photos.push(photo)
img.parentElement.addEventListener("click", event => {
event.preventDefault()
event.stopPropagation()
stage.open(src)
})
})
const main = document.querySelector('.gallery-main-stage')
stage = loadGallery(photos, 'inline', main, gallery)
})
}
function loadGallery(images, idx) {
var gallery = document.createElement("dialog")
gallery.classList.add("gallery-dialog")
gallery.innerHTML = `
<div class="photo-container">
<div class="image">
<img class="main-image" src="" alt="">
</div>
<button class="prev nav-btn"> Prev</button>
<button class="next nav-btn">Next </button>
</div>
<button class="close">&#10006;</button>
<a class="download disabled" target="_blank" download title="download original">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 304 384"><path fill="currentColor" d="M299 128L149 277L0 128h85V0h128v128h86zM0 320h299v43H0v-43z"/></svg>
</a>
<div class="caption"></div>
<div class="thumbnails"></div>
`
function loadGallery(images, idx, main, thumbnails) {
let gallery;
gallery.addEventListener("click", event => {
if (event.target.className == "close") {
document.location.hash = ''
gallery.close();
return
}
var rect = gallery.getBoundingClientRect();
var isInDialog = (rect.top <= event.clientY && event.clientY <= rect.top + rect.height &&
rect.left <= event.clientX && event.clientX <= rect.left + rect.width);
if (!isInDialog) {
document.location.hash = ''
gallery.close();
}
})
if (idx == 'inline') {
gallery = main
} else {
gallery = document.createElement("dialog")
gallery.classList.add("gallery-dialog")
gallery.innerHTML = `
<div class="photo-container">
<div class="image">
<img class="main-image" src="" alt="">
</div>
<button class="prev nav-btn"> Prev</button>
<button class="next nav-btn">Next </button>
</div>
<button class="close">&#10006;</button>
<a class="download disabled" target="_blank" download title="download original">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 304 384"><path fill="currentColor" d="M299 128L149 277L0 128h85V0h128v128h86zM0 320h299v43H0v-43z"/></svg>
</a>
<div class="caption"></div>
<div class="thumbnails"></div>
`
gallery.addEventListener("click", event => {
if (event.target.className == "close") {
document.location.hash = ''
gallery.close();
return
}
var rect = gallery.getBoundingClientRect();
var isInDialog = (rect.top <= event.clientY && event.clientY <= rect.top + rect.height &&
rect.left <= event.clientX && event.clientX <= rect.left + rect.width);
if (!isInDialog) {
document.location.hash = ''
gallery.close();
}
})
}
let currentIndex = 0;
const mainImage = gallery.querySelector(".main-image");
const caption = gallery.querySelector(".caption");
const prevBtn = gallery.querySelector(".prev.nav-btn");
const nextBtn = gallery.querySelector(".next.nav-btn");
const thumbnailsContainer = gallery.querySelector(".thumbnails");
const download = gallery.querySelector(".download");
let thumbnailsContainer
if (idx != 'inline') {
thumbnailsContainer = gallery.querySelector(".thumbnails");
}
gallery.addEventListener("keydown", event => {
if (event.keyCode == 39) {
@ -97,9 +134,15 @@ function loadGallery(images, idx) {
mainImage.src = images[index].src;
}, 0)
caption.innerHTML = images[index].caption;
gallery.querySelectorAll(".thumbnail").forEach((thumb, i) => {
thumb.classList.toggle("active", i === index);
});
if (idx == 'inline') {
thumbnails.querySelectorAll(".thumbnail").forEach((thumb, i) => {
thumb.classList.toggle("active", i === index);
});
} else {
gallery.querySelectorAll(".thumbnail").forEach((thumb, i) => {
thumb.classList.toggle("active", i === index);
});
}
if (images[index].orig) {
download.href = images[index].orig
download.classList.remove('disabled')
@ -109,7 +152,11 @@ function loadGallery(images, idx) {
}
prevBtn.disabled = index === 0;
nextBtn.disabled = index === images.length - 1;
document.location.hash = `#g/${idx}/${index}`
if (idx == 'inline') {
document.location.hash = `#${index + 1}`
} else {
document.location.hash = `#${idx + 1}/${index + 1}`
}
}
function createThumbnails() {
@ -144,20 +191,23 @@ function loadGallery(images, idx) {
}
};
createThumbnails();
idx != 'inline' && createThumbnails();
updateGallery(currentIndex);
const imagesIndex = images.map(img => img.src);
return {
element: gallery,
open: function(src, idx=-1) {
if (idx != -1) {
currentIndex = idx
open: function(src, newIdx=-1) {
if (newIdx != -1) {
currentIndex = newIdx
} else {
currentIndex = imagesIndex.indexOf(src)
}
updateGallery(currentIndex)
showGallery()
console.log("!WTF", idx)
if (idx != 'inline') {
showGallery()
}
}
}
}

View file

@ -47,8 +47,6 @@
{% block content %}
{% endblock %}
{}
<script src="{% static "js/jquery.js" %}"></script>
<script src="{% static "js/foundation.js" %}"></script>
{% compress js file base %}

View file

@ -10,33 +10,34 @@
<h6 class="page-header"><a href="{{ gallery.content.all.0.get_absolute_url }}">Back to {{ gallery.content.all.0.title }}</a></h6>
{% endif %}
<h5>{{ gallery.title }}</h5>
<ul class="slider1">
{% for photo in gallery.public %}
<li id="slide-{{photo.slug}}">
<img src="{{ photo.get_display_url }}" alt="{{ photo.title }}" loading="lazy">
<p>
{{ photo.caption|safe }}
{% if photo.caption %}<br>{%endif%}
{% if request.user.is_staff %}<a href="{{ photo.image.url }}" class="original-link" target="_blank" >Link to original file</a>{% endif %}
</p>
</li>
{% endfor %}
</ul>
{% with gallery.public.0 as photo %}
<div class="gallery-main-stage">
<div class="photo-container">
<div class="image">
<img src="{{ photo.get_display_url }}" alt="{{ photo.title }}" class="main-image" alt="{{ photo.title }}">
</div>
<button class="prev nav-btn"> Prev</button>
<button class="next nav-btn">Next </button>
<a class="download disabled" target="_blank" download title="download original">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 304 384"><path fill="currentColor" d="M299 128L149 277L0 128h85V0h128v128h86zM0 320h299v43H0v-43z"/></svg>
</a>
</div>
<div class="caption">{{ photo.caption_html }}</div>
</div>
{% endwith %}
</div>
<div class="medium-3 columns">
<br>
<p>{% trans "Other photos" %}:</p>
<div>
<div class="inline-gallery">
{% for photo in gallery.public %}
<div style="float: left; padding: 4px">
<a href="{{ photo.get_absolute_url }}" class="select-image" data-id="{{forloop.counter}}">
<img src="{{ photo.get_thumbnail_url }}" class="thumbnail" alt="{{ photo.title }}">
<a href="{{ gallery.get_absolute_url }}#{{forloop.counter}}">
<img src="{{ photo.get_thumbnail_url }}" class="thumbnail photo" alt="{{ photo.title }}" data-caption="{{ photo.caption_html }}"{% if request.user.is_staff %} data-orig="{{ photo.image.url }}"{% endif %}>
</a>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}