muiltiple images in carousel

This commit is contained in:
Priec
2026-06-22 17:40:55 +02:00
parent f724e9763f
commit 125be1798e
9 changed files with 169 additions and 62 deletions

View File

@@ -285,6 +285,10 @@ currency = Currency
category = Category
no-category = No category
image = Image
images = Images
main-image = Main
gallery-hint = The first image is the main one. Drag to reorder, click ✕ to remove.
add-images = Add images
slug = URL slug
slug-auto = generated automatically
position = Position

View File

@@ -285,6 +285,10 @@ currency = Mena
category = Kategória
no-category = Bez kategórie
image = Obrázok
images = Obrázky
main-image = Hlavný
gallery-hint = Prvý obrázok je hlavný. Potiahnutím zmeníte poradie, krížikom obrázok odstránite.
add-images = Pridať obrázky
slug = URL adresa
slug-auto = vygeneruje sa automaticky
position = Poradie

File diff suppressed because one or more lines are too long

View File

@@ -126,14 +126,57 @@
{{ ui::textarea(name="description", id="description", rows="5", value=v_desc) }}
</div>
<div class="space-y-1.5">
<label for="image" class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="image", lang=lang | default(value='sk')) }}</label>
{% if product and product.image %}
<img src="/images/{{ product.image }}" alt="" class="size-24 rounded-radius object-cover">
{% endif %}
{{ ui::file_input(name="image", id="image", accept="image/*") }}
{# --- Images gallery ------------------------------------------------------- #}
{# The first image is the product's main image; the rest feed the storefront #}
{# carousel. Existing images are reorderable (drag) and removable; the kept set #}
{# is submitted in order as repeated `existing_images` ids, and newly chosen #}
{# files (repeated `image` parts) are appended after them by the controller. #}
<script id="images-data" type="application/json">{% if product %}{{ product.images | json_encode() | safe }}{% else %}[]{% endif %}</script>
<div class="space-y-2" x-data="imageGallery(JSON.parse(document.getElementById('images-data').textContent))">
<span class="text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ t(key="images", lang=lang | default(value='sk')) }}</span>
<p class="{{ sublabel }}">{{ t(key="gallery-hint", lang=lang | default(value='sk')) }}</p>
<template x-if="images.length">
<div class="flex flex-wrap gap-3">
<template x-for="(im, i) in images" :key="im.id">
<div draggable="true"
@dragstart="dragIndex = i"
@dragover.prevent
@drop.prevent="onDrop(i)"
:class="dragIndex === i ? 'opacity-50' : ''"
class="group relative size-24 cursor-move overflow-hidden rounded-radius border border-outline dark:border-outline-dark">
<input type="hidden" name="existing_images" :value="im.id">
<img :src="`/images/${im.image_id}`" alt="" class="size-full object-cover">
<span x-show="i === 0"
class="absolute left-1 top-1 rounded-radius bg-primary px-1.5 py-0.5 text-[10px] font-semibold text-on-primary dark:bg-primary-dark dark:text-on-primary-dark">{{ t(key="main-image", lang=lang | default(value='sk')) }}</span>
<button type="button" @click="remove(i)"
class="absolute right-1 top-1 flex size-5 items-center justify-center rounded-full bg-surface/70 text-xs text-danger opacity-0 transition group-hover:opacity-100 dark:bg-surface-dark/70"
title="{{ t(key='delete', lang=lang | default(value='sk')) }}"></button>
</div>
</template>
</div>
</template>
<label for="image" class="block text-xs font-medium text-on-surface/70 dark:text-on-surface-dark/70">{{ t(key="add-images", lang=lang | default(value='sk')) }}</label>
{{ ui::file_input(name="image", id="image", accept="image/*", attrs='multiple') }}
</div>
<script>
function imageGallery(initial) {
return {
images: (initial || []).map(im => ({ id: im.id, image_id: im.image_id })),
dragIndex: null,
onDrop(i) {
if (this.dragIndex === null || this.dragIndex === i) { this.dragIndex = null; return; }
const moved = this.images.splice(this.dragIndex, 1)[0];
this.images.splice(i, 0, moved);
this.dragIndex = null;
},
remove(i) { this.images.splice(i, 1); },
};
}
</script>
{{ ui::checkbox(name="published", id="published", label=t(key="published", lang=lang | default(value='sk')), checked=v_pub) }}
<div class="flex gap-3 pt-2">