Add gallery
parent
66afbb611a
commit
f15dcf4ca7
|
|
@ -0,0 +1,10 @@
|
|||
/* Styles für Blogpost-Zusammenfassungen */
|
||||
li.post {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.post-summary {
|
||||
margin-top: 0.5rem;
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/* Image Gallery Styles */
|
||||
.image-gallery {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
margin: 20px auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gallery-slider {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.slide {
|
||||
display: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.slide.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.slide img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.gallery-navigation {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.prev-slide, .next-slide {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
padding: 16px;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
border-radius: 50%;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.prev-slide:hover, .next-slide:hover {
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.prev-slide {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.next-slide {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.gallery-indicator {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.dot {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
margin: 0 5px;
|
||||
background-color: #bbb;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
transition: background-color 0.3s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dot.active {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
.slide-caption {
|
||||
padding: 10px;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.prev-slide, .next-slide {
|
||||
font-size: 18px;
|
||||
padding: 12px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
function showSlide(galleryId, slideIndex) {
|
||||
const slides = document.querySelectorAll(`#${galleryId} .slide`);
|
||||
const dots = document.querySelectorAll(`#${galleryId} .dot`);
|
||||
|
||||
// Hide all slides
|
||||
slides.forEach(slide => {
|
||||
slide.classList.remove('active');
|
||||
});
|
||||
|
||||
// Remove active class from all dots
|
||||
dots.forEach(dot => {
|
||||
dot.classList.remove('active');
|
||||
});
|
||||
|
||||
// Show the selected slide and activate dot
|
||||
slides[slideIndex].classList.add('active');
|
||||
dots[slideIndex].classList.add('active');
|
||||
}
|
||||
|
||||
function moveSlide(galleryId, direction) {
|
||||
const slides = document.querySelectorAll(`#${galleryId} .slide`);
|
||||
let currentIndex = 0;
|
||||
|
||||
// Find current active slide
|
||||
slides.forEach((slide, index) => {
|
||||
if (slide.classList.contains('active')) {
|
||||
currentIndex = index;
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate new index
|
||||
let newIndex = currentIndex + direction;
|
||||
if (newIndex < 0) newIndex = slides.length - 1;
|
||||
if (newIndex >= slides.length) newIndex = 0;
|
||||
|
||||
// Show the new slide
|
||||
showSlide(galleryId, newIndex);
|
||||
}
|
||||
|
||||
// Handle keyboard navigation
|
||||
document.addEventListener('keydown', function(event) {
|
||||
// Only handle if a gallery is present
|
||||
const galleries = document.querySelectorAll('.image-gallery');
|
||||
if (galleries.length === 0) return;
|
||||
|
||||
// Find gallery with active slide
|
||||
let activeGalleryId = null;
|
||||
galleries.forEach(gallery => {
|
||||
const activeSlide = gallery.querySelector('.slide.active');
|
||||
if (activeSlide) {
|
||||
activeGalleryId = gallery.id;
|
||||
}
|
||||
});
|
||||
|
||||
if (!activeGalleryId) return;
|
||||
|
||||
// Left arrow
|
||||
if (event.keyCode === 37) {
|
||||
moveSlide(activeGalleryId, -1);
|
||||
}
|
||||
// Right arrow
|
||||
else if (event.keyCode === 39) {
|
||||
moveSlide(activeGalleryId, 1);
|
||||
}
|
||||
});
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
{{- if (not (in (.Site.Params.excludedTypes | default (slice "page")) .Type)) -}}
|
||||
<li class="post">
|
||||
<a href="{{ .RelPermalink }}">{{.Title}}</a> <span class="meta">{{ dateFormat ":date_medium" .Date }}{{ if .Draft }} <span class="draft-label">DRAFT</span> {{ end }}</span>
|
||||
<p class="post-summary">{{ .Summary | plainify | truncate 200 }}</p>
|
||||
</li>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,16 @@
|
|||
<link id="darkModeStyle" rel="stylesheet" type="text/css" href="{{ $darkstyle.Permalink }}" {{ if eq .Site.Params.mode "auto" }}media="(prefers-color-scheme: dark)"{{ end }} {{ if eq .Site.Params.mode "toggle" }}disabled{{ end }} />
|
||||
{{- end -}}
|
||||
|
||||
<!-- Load gallery resources -->
|
||||
{{ $galleryCss := resources.Get "css/gallery.css" | minify | fingerprint }}
|
||||
<link rel="stylesheet" href="{{ $galleryCss.RelPermalink }}">
|
||||
{{ $galleryJs := resources.Get "js/gallery.js" | minify | fingerprint }}
|
||||
<script defer src="{{ $galleryJs.RelPermalink }}"></script>
|
||||
|
||||
<!-- Custom styles -->
|
||||
{{ $customstyle := resources.Get "css/custom.css" | fingerprint }}
|
||||
<link rel="stylesheet" type="text/css" href="{{ $customstyle.RelPermalink }}" />
|
||||
|
||||
<!-- Mathjax support -->
|
||||
{{- if .Site.Params.mathjax | default false -}}
|
||||
<script type="text/javascript"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
{{ $id := default (printf "gallery-%d" (now.UnixNano)) (.Get "id") }}
|
||||
<div class="image-gallery" id="{{ $id }}">
|
||||
<div class="gallery-slider">
|
||||
{{ $images := .Inner | transform.Unmarshal }}
|
||||
{{ range $index, $image := $images }}
|
||||
<div class="slide{{ if eq $index 0 }} active{{ end }}" data-index="{{ $index }}">
|
||||
<img src="{{ $image.src }}" alt="{{ $image.alt | default "" }}">
|
||||
<div class="gallery-navigation">
|
||||
<div class="prev-slide" onclick="moveSlide('{{ $id }}', -1)">❮</div>
|
||||
<div class="next-slide" onclick="moveSlide('{{ $id }}', 1)">❯</div>
|
||||
</div>
|
||||
{{ if $image.caption }}
|
||||
<div class="slide-caption">{{ $image.caption | markdownify }}</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="gallery-indicator">
|
||||
{{ range $index, $image := $images }}
|
||||
<span class="dot{{ if eq $index 0 }} active{{ end }}" onclick="showSlide('{{ $id }}', {{ $index }})"></span>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
Loading…
Reference in New Issue