Symfony 7.4 / Twig / Doctrine DBAL auf herkömmlichem PHP-Webhosting. Versionierte Blockdokumente (v1-v3) mit unveränderlichen Revisionen, getrennten Entwürfen/Veröffentlichungen und optimistischer Konflikterkennung. Visueller Editor mit Strukturbaum, Live-Vorschau, responsiven Gerätewerten, Abschnittsvorlagen, Bildmediathek, Galerien und Effekten. Öffentliche Ausgabe ohne Editor-JavaScript. Geprüft: 41 PHP-Tests / 155 Assertions, 10 JavaScript-Modelltests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
31 lines
2.3 KiB
Twig
31 lines
2.3 KiB
Twig
{% set type = block.type %}
|
|
{% set props = block.props|default({}) %}
|
|
{% set layout = block.layout|default({}) %}
|
|
{% set designClasses = '' %}
|
|
{% for device, settings in layout.design|default({}) %}
|
|
{% for key, value in settings %}{% set designClasses = designClasses ~ ' d-' ~ device ~ '-' ~ key ~ '-' ~ value %}{% endfor %}
|
|
{% endfor %}
|
|
{% for key, value in layout.effects|default({}) %}{% set designClasses = designClasses ~ ' fx-' ~ key ~ '-' ~ value %}{% endfor %}
|
|
{% if type in ['section', 'row', 'column'] %}
|
|
{% set tag = type == 'section' ? 'section' : 'div' %}
|
|
<{{ tag }} id="{{ block.id }}" class="block-{{ type }} tone-{{ layout.tone|default('paper') }} width-{{ layout.width|default('normal') }}{{ designClasses }}">
|
|
{% if type == 'section' %}<div class="shell section-inner">{% endif %}
|
|
{% for child in block.children|default([]) %}{% include 'blocks/block.html.twig' with {block: child} only %}{% endfor %}
|
|
{% if type == 'section' %}</div>{% endif %}
|
|
</{{ tag }}>
|
|
{% elseif type == 'heading' %}
|
|
<h{{ props.level }} id="{{ block.id }}" class="{{ designClasses|trim }}">{{ props.text }}</h{{ props.level }}>
|
|
{% elseif type == 'text' %}
|
|
<p id="{{ block.id }}" class="block-text{{ designClasses }}">{{ props.text }}</p>
|
|
{% elseif type == 'button' %}
|
|
<a id="{{ block.id }}" class="button{{ designClasses }}" href="{{ props.href }}">{{ props.text }} <span aria-hidden="true">↗</span></a>
|
|
{% elseif type == 'image' %}
|
|
<figure id="{{ block.id }}" class="block-image{{ designClasses }}"><img src="{{ props.src }}" alt="{{ props.alt }}" width="{{ props.width }}" height="{{ props.height }}" loading="lazy" decoding="async"{% if props.sources|default([]) %} srcset="{% for source in props.sources %}{{ source.src }} {{ source.width }}w{% if not loop.last %}, {% endif %}{% endfor %}" sizes="(max-width: 650px) 100vw, (max-width: 1024px) 50vw, 800px"{% endif %}>{% if props.caption|default('') %}<figcaption>{{ props.caption }}</figcaption>{% endif %}</figure>
|
|
{% elseif type == 'gallery' %}
|
|
<div id="{{ block.id }}" class="block-gallery{{ designClasses }}" role="group" aria-label="Bildergalerie">
|
|
{% for child in block.children|default([]) %}{% include 'blocks/block.html.twig' with {block: child} only %}{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<p>Dieser Inhaltsblock ist derzeit nicht verfügbar.</p>
|
|
{% endif %}
|