Kleine Anleitung für CMS-Gallery

Englisch below!

Hallo.

Ich poste hier ein kleines Tutorial für eine Gallery innerhalb des artikels.md
Da Elements keine Gallery Componente hat, die mit dem CMS funktioniert, habe ich was gebastelt. Hintergrund: Auf meinem Projekt soll man im Blogteil einen Artikel erstellen können, der auch eine kleine Gallery enthalten soll, z.B. für ein Ereignis etc. Da bietet sich Frontmatter dafür an und so habe ich die Felder erstellt: Bild 1 und 2:


Da ich keine Componente fand, die es so umsetzt, wie ich es will (mehrere Artikel mit Bildern, die in verschiedenen Ordner befinden, und dies mittels CMS umsetzbar) ging ich so vor:

Am Ende von der Typography Componente mit {{item.body}} darin. setzte ich einen Container. Darin legte ich eine Markdown-Componente, die den folgenden Code beinhaltet:

<div
class=""
x-data="{
    i: 0,
    open: false,
    srcs: [],

    init() {
        this.srcs = Array.prototype.map.call(
            this.$refs.thumbs.querySelectorAll('img'),
            function (img) {
                return img.getAttribute('src');
            }
        );
    },

    show(n) {
        this.i = n;
        this.open = true;
    },

    prev() {
        this.i = (this.i - 1 + this.srcs.length) % this.srcs.length;
    },

    next() {
        this.i = (this.i + 1) % this.srcs.length;
    },

    closeLightbox() {
        this.open = false;
    }
}"
>

<div
    x-ref="thumbs"
    class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
>
    {% for bild in item.gallery %}
        <a
            href="#"
            @click.prevent="show({{ loop.index0 }})"
            class="cursor-zoom-in block"
        >
            <img
                src="{{ bild.image }}"
                alt="{{ bild.alt|default('') }}"
                class="w-full h-auto bg-[#EAE2DB]"
            >
        </a>
    {% endfor %}
</div>

<template x-teleport="body">
    <div
        x-show="open"
        style="display:none"
        class="fixed inset-0 z-[100] flex items-center justify-center bg-black/90"
        @click.self="closeLightbox()"
        @keydown.escape.window="closeLightbox()"
        @keydown.arrow-left.window="prev()"
        @keydown.arrow-right.window="next()"
    >

        <button
            @click.stop="prev()"
            class="absolute left-4 text-white text-5xl opacity-80 hover:opacity-100"
            aria-label="Zur&uuml;ck"
        >
            &#8249;
        </button>

        <img
            :src="srcs[i]"
            alt=""
            class="max-h-[85vh] max-w-[90vw] object-contain rounded"
        >

        <button
            @click.stop="next()"
            class="absolute right-4 text-white text-5xl opacity-80 hover:opacity-100"
            aria-label="Weiter"
        >
            &#8250;
        </button>

        <button
            @click="closeLightbox()"
            class="absolute top-4 right-6 text-white text-3xl opacity-80 hover:opacity-100"
            aria-label="Schlie&szlig;en"
        >
            &#10005;
        </button>

        <span
            class="absolute top-4 left-6 text-white text-sm"
            x-text="(i + 1) + ' / ' + srcs.length"
        >
        </span>

    </div>
</template>

</div>

WICHTIG: Nicht eingerückt einfügen. Dann funktioniert es nicht.

Warum Markdown? Die HTML Componente kann keine {{xy.z}} Angaben umsetzen - warum auch immer. Nur die MD-Componente setzte dies richtig um, wenn der Code nicht zu viel nach Rechts eingerückt ist. Am Beginn der Entwicklung war kein Lightbox Funktionalität vorhanden. Ich habe die KI zu Hilfe genommen, die dann diesen Code generierte. Wenn sich jemand auskennt, bitte um Verbesserungen.

Viel Spass damit.

Gruss Romano

english
Hello.

I’m posting a quick tutorial here for a gallery within article.md.
Since Elements doesn’t have a gallery component that works with the CMS, I put something together myself. The background: For my project, I wanted to be able to create blog articles that include a small gallery—for an event, for example. Frontmatter is perfect for this, so I created the following fields for Image 1 and Image 2:


Since I couldn’t find a component that implemented this exactly the way I wanted (handling multiple articles with images located in different folders, all manageable via the CMS), I proceeded as follows:

I placed a container at the end of the Typography component (which contains {{item.body}}). In it I put a Markdown component that contains the following code:

<various
class=""
x-data="{ 
i: 0, 
open: false, 
srcs: [], 

init() { 
this.srcs = Array.prototype.map.call( 
this.$refs.thumbs.querySelectorAll('img'), 
function (img) { 
return img.getAttribute('src'); 
} 
); 
}, 

show(n) { 
this.i = n; 
this.open = true; 
}, 

prev() { 
this.i = (this.i - 1 + this.srcs.length) % this.srcs.length; 
}, 

next() { 
this.i = (this.i + 1) % this.srcs.length; 
}, 

closeLightbox() { 
this.open = false; 
}
}"
>

<various 
x-ref="thumbs" 
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
> 
{% for image in item.gallery %} 
<a 
href="#" 
@click.prevent="show({{ loop.index0 }})" 
class="cursor-zoom-in block" 
> 
<img 
src="{{ image.image }}" 
alt="{{ image.alt|default('') }}" 
class="w-full h-auto bg-[#EAE2DB]" 
> 
</a> 
{% endfor %}
</div>

<template x-teleport="body"> 
<various 
x-show="open" 
style="display:none" 
class="fixed inset-0 z-[100] flex items-center justify-center bg-black/90" 
@click.self="closeLightbox()" 
@keydown.escape.window="closeLightbox()" 
@keydown.arrow-left.window="prev()" 
@keydown.arrow-right.window="next()" 
> 

<button 
@click.stop="prev()" 
class="absolute left-4 text-white text-5xl opacity-80 hover:opacity-100" 
aria-label="Previous"
>
&#8249; 
</button>

<img
:src="srcs[i]"
alt=""
class="max-h-[85vh] max-w-[90vw] object-contain rounded"
>

<button
@click.stop="next()"
class="absolute right-4 text-white text-5xl opacity-80 hover:opacity-100"
aria-label="Next"
>
&#8250; 
</button>

<button
@click="closeLightbox()"
class="absolute top-4 right-6 text-white text-3xl opacity-80 hover:opacity-100"
aria-label="Close"
>
&#10005; 
</button>

<span
class="absolute top-4 left-6 text-white text-sm"
x-text="(i + 1) + ' / ' + srcs.length"
>
</span>

</div>
</template>

</div>

IMPORTANT: Do not insert with indentation. Otherwise, it won’t work.

Why Markdown? The HTML component cannot process {{xy.z}} expressions—for whatever reason. Only the MD component handles this correctly, provided the code isn’t indented too far to the right. There was no lightbox functionality at the start of development; I enlisted the help of AI, which generated this code. If anyone is knowledgeable about this, please feel free to suggest improvements.

Have fun with it.

Best regards, Romano