Short guide for CMS-Gallery

Englisch below!

Hello.

I’m posting a quick tutorial here for adding a gallery inside artikels.md.
Since Elements doesn’t have a gallery component that works with the CMS, I built something myself. Background: For my project, I wanted users to be able to create blog articles that can include a small gallery, for example for an event, etc. Frontmatter is perfect for this, so I created these fields: Image 1 and 2:


Since I couldn’t find a component that did exactly what I wanted (multiple articles with images in various folders, manageable via the CMS), I proceeded as follows:

At the end of the Typography component with {{item.body}} inside, I placed a container. Inside, I put a Markdown component containing the following code:

<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="Back"
        >
            &#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: Don’t indent when inserting. Otherwise, it won’t work.

Why Markdown? The HTML component can’t process {{xy.z}} for some reason. Only the MD component renders it properly, as long as the code isn’t indented too far to the right. At the beginning, there was no lightbox functionality—I asked AI for help and it generated this code. If anyone knows this stuff, feel free to suggest improvements.

Have fun with it.

Best, 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