feat: add image gallery content element with configurable columns and backend preview
All checks were successful
Build / build (push) Successful in 4m21s
Build / deploy-stage (push) Successful in 2m41s
Build / switch-stage (push) Successful in 2m4s

This commit is contained in:
2025-06-16 13:50:41 +02:00
parent c4d01f2a47
commit 37300492dc
5 changed files with 155 additions and 1 deletions

View File

@@ -0,0 +1,26 @@
name: cloonar/imagegallery
typeName: cloonar_imagegallery
group: default
prefixFields: false
fields:
- identifier: header
useExistingField: true
- identifier: image
type: File
properties:
allowed: [jpg, jpeg, png, gif, webp]
multiple: true
useExistingField: true
- identifier: columns
type: Select
renderType: selectSingle
default: 1
items:
- label: LLL:EXT:base/ContentBlocks/ContentElements/imagegallery/language/labels.xlf:columns.1
value: 1
- label: LLL:EXT:base/ContentBlocks/ContentElements/imagegallery/language/labels.xlf:columns.2
value: 2
- label: LLL:EXT:base/ContentBlocks/ContentElements/imagegallery/language/labels.xlf:columns.3
value: 3
- label: LLL:EXT:base/ContentBlocks/ContentElements/imagegallery/language/labels.xlf:columns.5
value: 5

View File

@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file datatype="plaintext" original="labels.xlf" source-language="en" product-name="cloonar/imagegallery">
<header/>
<body>
<trans-unit id="title">
<source>Image Gallery</source>
</trans-unit>
<trans-unit id="description">
<source>A gallery of images with configurable columns</source>
</trans-unit>
<trans-unit id="columns.1">
<source>1 Column</source>
</trans-unit>
<trans-unit id="columns.2">
<source>2 Columns</source>
</trans-unit>
<trans-unit id="columns.3">
<source>3 Columns</source>
</trans-unit>
<trans-unit id="columns.5">
<source>5 Columns</source>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -0,0 +1,39 @@
<html
xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers"
data-namespace-typo3-fluid="true"
>
<f:layout name="Preview"/>
<f:section name="Header">
<be:link.editRecord uid="{data.uid}" table="{data.mainType}">
<f:if condition="{data.header}">
<f:then><strong>{data.header}</strong></f:then>
</f:if>
</be:link.editRecord>
</f:section>
<f:section name="Content">
<f:if condition="{data.image}">
<div class="row">
<f:for each="{data.image}" as="image" iteration="iterator">
<f:if condition="{iterator.index} < 3">
<div class="col-4">
<f:image image="{image}" width="100" height="auto" treatIdAsReference="1" alt="Preview image" />
</div>
</f:if>
</f:for>
</div>
<f:if condition="{data.image -> f:count()} > 3">
<p>+ {f:math.subtract(a: '{data.image -> f:count()}', b: '3')} more images</p>
</f:if>
<p>
<f:switch expression="{data.columns}">
<f:case value="2">2 Columns</f:case>
<f:case value="3">3 Columns</f:case>
<f:case value="5">5 Columns</f:case>
<f:defaultCase>1 Column</f:defaultCase>
</f:switch>
</p>
</f:if>
</f:section>
</html>

View File

@@ -0,0 +1,63 @@
<f:layout name="Default" />
<f:section name="Header"></f:section>
<f:section name="Main">
<f:if condition="{data.header}">
<h2 class="text-center mb-8">{data.header}</h2>
</f:if>
<f:if condition="{data.image}">
<f:variable name="columnClass">
<f:switch expression="{data.columns}">
<f:case value="2">md:grid-cols-2</f:case>
<f:case value="3">md:grid-cols-3</f:case>
<f:case value="5">md:grid-cols-5</f:case>
<f:defaultCase>md:grid-cols-1</f:defaultCase>
</f:switch>
</f:variable>
<div class="grid grid-cols-1 {columnClass} gap-6 md:gap-8">
<f:for each="{data.image}" as="image">
<div class="relative">
<f:if condition="{image.link}">
<f:then>
<f:link.typolink parameter="{image.link}" class="block w-full h-full">
<picture class="block w-full h-full">
<source
type="image/webp"
srcset="{f:uri.image(image:image, width:'320', cropVariant:'default', fileExtension:'webp')} 320w,
{f:uri.image(image:image, width:'768', cropVariant:'default', fileExtension:'webp')} 768w"
sizes="(max-width: 767px) 90vw, 33vw" />
<img
src="{f:uri.image(image:image, width:'768', cropVariant:'default')}"
srcset="{f:uri.image(image:image, width:'320', cropVariant:'default')} 320w,
{f:uri.image(image:image, width:'768', cropVariant:'default')} 768w"
sizes="(max-width: 767px) 90vw, 33vw"
alt="{image.alternative}"
class="w-full h-full object-cover"
/>
</picture>
</f:link.typolink>
</f:then>
<f:else>
<picture class="block w-full h-full">
<source
type="image/webp"
srcset="{f:uri.image(image:image, width:'320', cropVariant:'default', fileExtension:'webp')} 320w,
{f:uri.image(image:image, width:'768', cropVariant:'default', fileExtension:'webp')} 768w"
sizes="(max-width: 767px) 90vw, 33vw" />
<img
src="{f:uri.image(image:image, width:'768', cropVariant:'default')}"
srcset="{f:uri.image(image:image, width:'320', cropVariant:'default')} 320w,
{f:uri.image(image:image, width:'768', cropVariant:'default')} 768w"
sizes="(max-width: 767px) 90vw, 33vw"
alt="{image.alternative}"
class="w-full h-full object-cover"
/>
</picture>
</f:else>
</f:if>
</div>
</f:for>
</div>
</f:if>
</f:section>