Add videos: library, block and section background

Videos join the media library as their own table (schema v28), with a
video block and a looping background on sections. video.js starts loops
only while visible, offers a pause button and leaves the still image for
reduced motion and data saving.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PWYm8kjAWmZaB2QB2xuBhU
This commit is contained in:
kantarciandClaude Opus 5.5 committed 2026-11-05 05:23:17 +00:00
1 parent 592e3d5342
commit 76613b9f8e
25 files changed
+674 -20

No files matched your search

+17 -1
View File
@@ -8,11 +8,16 @@
{% 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 }}{{ block.anchor|default('') ? ' has-anchor' : '' }}">
{% set backgroundVideo = type == 'section' ? props.backgroundVideo|default('') : '' %}
{% set backgroundWebm = type == 'section' ? props.backgroundVideoWebm|default('') : '' %}
<{{ tag }} id="{{ block.id }}" class="block-{{ type }} tone-{{ layout.tone|default('paper') }} width-{{ layout.width|default('normal') }}{{ designClasses }}{{ block.anchor|default('') ? ' has-anchor' : '' }}{{ backgroundVideo or backgroundWebm ? ' has-video' : '' }}">
{% if block.anchor|default('') %}<span id="{{ block.anchor }}" class="block-anchor" aria-hidden="true"></span>{% endif %}
{% if backgroundVideo or backgroundWebm %}{# Dekoration: Die Sektion behält ihr Hintergrundbild, es bleibt stehen, bis das Video läuft. #}
<video class="section-video" muted loop playsinline preload="{{ editing|default(false) ? 'metadata' : 'none' }}" aria-hidden="true" tabindex="-1"{{ editing|default(false) ? '' : ' data-video-loop' }}>{% if backgroundWebm %}<source src="{{ backgroundWebm }}" type="video/webm">{% endif %}{% if backgroundVideo %}<source src="{{ backgroundVideo }}" type="{{ backgroundVideo ends with '.webm' ? 'video/webm' : 'video/mp4' }}">{% endif %}</video>{% endif %}
{% if type == 'section' %}<div class="shell section-inner">{% endif %}
{% for child in block.children|default([]) %}{% include 'blocks/block.html.twig' with {block: child, editing: editing|default(false), postLists: postLists|default({}), forms: forms|default({}), breadcrumbs: breadcrumbs|default([]), navigation: navigation|default({}), sections: sections|default({}), richText: richText|default(false), richHeadings: richHeadings|default(false), neighbours: neighbours|default({}), eagerImage: eagerImage|default(null), inHeader: inHeader|default(false)} only %}{% endfor %}
{% if type == 'section' %}</div>{% endif %}
{% if (backgroundVideo or backgroundWebm) and not editing|default(false) %}{% include 'blocks/video-toggle.html.twig' only %}{% endif %}
</{{ tag }}>
{% elseif type == 'heading' %}
<h{{ props.level }} id="{{ block.id }}" class="{{ designClasses|trim }}">{% if richHeadings|default(false) %}{{ props.text|raw }}{% else %}{{ props.text }}{% endif %}</h{{ props.level }}>
@@ -271,6 +276,17 @@
</div>
{% endif %}
{% endif %}
{% elseif type == 'video' %}
{% set source = props.src|default('') %}
{% if source == '' %}
{% if editing|default(false) %}<p id="{{ block.id }}" class="block-unavailable{{ designClasses }}" role="note">Video: unter Inhalt ein Video wählen.</p>{% endif %}
{% else %}
{% set looping = props.mode|default('player') == 'loop' %}
<figure id="{{ block.id }}" class="block-video{{ designClasses }}">
<video class="video-media"{% if looping %} muted loop playsinline preload="{{ editing|default(false) ? 'metadata' : 'none' }}"{{ editing|default(false) ? '' : ' data-video-loop' }}{% else %} controls playsinline preload="metadata"{% endif %}{% if props.poster|default('') %} poster="{{ props.poster }}"{% endif %}{% if props.title|default('') %} aria-label="{{ props.title }}"{% elseif looping %} aria-hidden="true"{% else %} aria-label="{{ 'Video'|kant_t }}"{% endif %}>{% if props.srcWebm|default('') %}<source src="{{ props.srcWebm }}" type="video/webm">{% endif %}<source src="{{ source }}" type="{{ source ends with '.webm' ? 'video/webm' : 'video/mp4' }}"></video>
{% if looping and not editing|default(false) %}{% include 'blocks/video-toggle.html.twig' only %}{% endif %}
</figure>
{% endif %}
{% elseif type == 'html' %}
{# Markup des Betreibers, unveraendert. Geprueft wurde es beim Speichern (CustomCode::checkHtml),
setzen darf es nur ein Administrator - deshalb steht hier `raw` und keine Filterung. #}