ixm_blocks-1.0.x-dev/modules/ixm_blocks_hero/templates/block--ixm-blocks-hero.html.twig
modules/ixm_blocks_hero/templates/block--ixm-blocks-hero.html.twig
{#
@file
Template for a hero block with configurable carousel options.
Available variables for themers:
- configuration: An array of block configuration settings, including:
- 'id': A unique identifier for the block.
- 'provider': The module or theme providing the block.
- content: Renderable content elements of the block, such as field values.
- attributes: HTML attributes for the main block wrapper.
- carousel_type: The type of carousel, either 'bootstrap' (default) or 'swiper'.
- carousel_classes: Additional classes for the carousel container.
- carousel_attributes: HTML attributes for the carousel wrapper.
- navigation: Boolean indicating whether to show navigation arrows (default: true).
- pagination: Boolean indicating whether to show pagination indicators (default: true).
- scrollbar: Boolean indicating whether to show a scrollbar (default: false).
- hero_items: The content items for the hero slides.
- variant: The color variant of the block ('light' or 'dark'), determined by CSS classes.
Macros:
- bootstrap_carousel: Renders a Bootstrap carousel.
- swiper_carousel: Renders a Swiper.js carousel.
- hero_slide: Renders a single slide for both carousel types.
- carousel_control: Renders navigation controls for carousels.
#}
{% import _self as macros %}
{{ attach_library('ixm_blocks_hero/hero-styles') }}
{% set hero_id = ('carousel-' ~ configuration['id'])|clean_id %}
{% set hero_items = content.field_entity_reference_paragraph|filter((value, key) => key|first != '#') %}
{# Initialize default carousel classes & variables. #}
{% set carousel_type = carousel_type|default('bootstrap') %}
{% if carousel_type is same as ('swiper') %}
{{ attach_library('ixm_blocks_hero/hero-swiper') }}
{% endif %}
{% set carousel_classes = carousel_classes|default() %}
{% set carousel_attributes = carousel_attributes|default(create_attribute({})) %}
{% set carousel_item_attributes = carousel_item_attributes|default(create_attribute({})) %}
{% set navigation = navigation|default(true) %}
{% set pagination = pagination|default(true) %}
{% set scrollbar = scrollbar|default(false) %}
{% set variant = 'light' %}
{% if 'carousel-dark' in carousel_classes %}
{% set variant = 'dark' %}
{% endif %}
{%
set classes = [
'block',
'block-' ~ configuration.provider|clean_class,
'block-' ~ plugin_id|clean_class,
'position-relative',
]
%}
<div{{ attributes.addClass(classes) }}>
{% if label %}
<h3{{ title_attributes.addClass('mb-5') }}>{{ label }}</h3>
{% endif %}
{{ title_prefix }}
{{ title_suffix }}
{# Render carousel based on type #}
{% block hero_content %}
{% if hero_items|length > 1 %}
{% if carousel_type == 'bootstrap' %}
{{ macros.bootstrap_carousel(hero_id, hero_items, variant, carousel_classes, carousel_attributes, navigation, pagination, carousel_item_attributes) }}
{% elseif carousel_type == 'swiper' %}
{{ macros.swiper_carousel(hero_id, hero_items, variant, carousel_classes, carousel_attributes, navigation, pagination, scrollbar) }}
{% endif %}
{% else %}
{# Render a single slide without a carousel #}
<div class="hero-banner-wrapper">
{% for key, item in hero_items %}
{% set media_items = item['#media_items'] ?? [] %}
{% for media in media_items %}
{{ macros.hero_slide(item, variant, media) }}
{% endfor %}
{% endfor %}
</div>
{% endif %}
{% endblock %}
</div>
{# Bootstrap Carousel Macro #}
{% macro bootstrap_carousel(hero_id, hero_items, variant, carousel_classes, carousel_attributes, navigation, pagination, carousel_item_attributes) %}
<div id="{{ hero_id }}" {{ carousel_attributes.addClass(['hero-carousel', 'carousel', 'slide'], carousel_classes) }}>
{# Indicators #}
{% if pagination %}
<div class="carousel-indicators">
{% for key, item in hero_items %}
<button type="button" data-bs-target="#{{ hero_id }}" data-bs-slide-to="{{ loop.index - 1 }}" {% if loop.first %}class="active" aria-current="true"{% endif %} aria-label="Slide {{ loop.index }}"></button>
{% endfor %}
</div>
{% endif %}
{# Slides #}
<div class="carousel-inner">
{% for key, item in hero_items %}
{% set media_items = item['#media_items'] ?? [] %}
{% for media in media_items %}
<div class="carousel-item{{ loop.parent.key is same as (0) ? ' active' }}" {{ carousel_item_attributes }}>
{{ _self.hero_slide(item, variant, media) }}
</div>
{% endfor %}
{% endfor %}
</div>
{# Controls #}
{% if navigation %}
{{ macros.carousel_control(hero_id, 'prev', 'Previous') }}
{{ macros.carousel_control(hero_id, 'next', 'Next') }}
{% endif %}
</div>
{% endmacro %}
{# Swiper Carousel Macro #}
{% macro swiper_carousel(hero_id, hero_items, variant, carousel_classes, carousel_attributes, navigation, pagination, scrollbar) %}
<div {{ carousel_attributes.addClass(['hero-swiper', 'swiper-container', 'overflow-x-hidden'], carousel_classes) }}>
<div class="swiper-wrapper">
{% for key, item in hero_items %}
{% set media_items = item['#media_items'] ?? [] %}
{% for media in media_items %}
<div class="swiper-slide">
{{ macros.hero_slide(item, variant, media) }}
</div>
{% endfor %}
{% endfor %}
</div>
{# Swiper Navigation #}
{% if navigation %}
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
{% endif %}
{% if pagination %}
<div class="swiper-pagination"></div>
{% endif %}
{% if scrollbar %}
<div class="swiper-scrollbar"></div>
{% endif %}
</div>
{% endmacro %}
{# Hero Slide Macro (Shared) #}
{% macro hero_slide(item, variant, media, title_prefix, title_suffix) %}
{% set banner_attr = create_attribute() %}
{%
set banner_classes = [
'hero__banner',
'd-flex flex-column position-relative overflow-hidden justify-content-end pb-5',
'hero__gradient_vertical hero__gradient_horizontal',
variant is same as ('dark') ? 'text-dark bg-light' : 'text-light bg-dark',
]
%}
<div{{ banner_attr.addClass(banner_classes) }}>
<div class="container position-relative hero__banner-content py-5">
<div class="row">
<div class="col-12 col-lg-8" role="region" aria-label="{{ 'Hero Banner'|t }}">
{% block content %}
{% if item['#paragraph'].field_title %}
<h1>{{ item['#paragraph'].field_title.value }}</h1>
{% endif %}
{% if item['#paragraph'].field_body %}
<div class="d-none d-lg-block hero__banner-body lead">
{{ item['#paragraph'].field_body.value|raw }}
</div>
{% endif %}
{# buttons #}
{% if item['#paragraph'].field_links is not empty %}
<div class="row flex-wrap mx-n2 mt-5">
{% set numLinksIndex = item['#paragraph'].field_links|length - 1 %}
{% for i in 0..numLinksIndex %}
<div class="col-auto px-2 cta-link my-2">
{% block content_buttons %}
<a href="{{ item['#paragraph'].field_links[i].uri.toString() }}"
class="btn btn-outline-{{ variant is same as ('dark') ? 'dark' : 'light' }} btn-lg rounded-pill">
{{ item['#paragraph'].field_links[i].title }}
</a>
{% endblock %}
</div>
{% endfor %}
</div>
{% endif %}
{% endblock %}
</div>
{# unmute/mute/play/pause buttons #}
{% if media.type is not same as('image') %}
{% block audio_buttons %}
<div class="col-auto d-none d-lg-flex align-items-end ml-auto ms-auto">
{# Create attributes dynamically with create_attribute #}
{% set audio_controls_attributes = create_attribute({
class: [
'hero__banner--audio-controls',
'px-4',
'py-2',
'rounded-pill',
hero_items|length > 1 ? 'is-playing' : '',
'is-muted',
variant is same as ('dark') ? 'bg-light' : 'bg-dark',
'bg-opacity-50',
]
}) %}
<div{{ audio_controls_attributes }}>
<div class="d-flex gap-2">
{% for button in ['unmute', 'mute', 'pause', 'play'] %}
<button class="btn link-{{ variant is same as ('dark') ? 'dark' : 'light' }} link-opacity-75 link-opacity-100-hover rounded-circle border-0 mx-0 px-2 focus-ring hero__banner--btn-{{ button }}" aria-label="{{ button|capitalize }}">
{% include '@ixm_blocks_hero/images/btn-' ~ button ~ '.svg' %}
</button>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
{% endif %}
</div>
</div>
{% if media.type == 'image' %}
<div class="hero__banner-image">
{% block hero_image %}
<picture class="w-100 h-100">
<source srcset="{{ media.mobile_image }}" media="(max-width: 768px)">
<img src="{{ media.desktop_image }}" alt="{{ media.alt }}" class="w-100 h-100 object-fit-cover">
</picture>
{% endblock %}
</div>
{% else %}
<div class="hero__banner-video hero__banner-video--{{ media.type|clean_class }}">
{% if media.type == 'youtube_video' %}
{% block hero_youtube %}
<div class="hero__banner-video--youtube-player d-none d-lg-block">
<div id="hero__banner-video--youtube"></div>
</div>
<img class="d-block d-lg-none hero__banner--img" src="https://img.youtube.com/vi/{{ media.youtubeId }}/maxresdefault.jpg" alt="{{ content.field_title.0['#context'].value|render|trim|striptags }}" />
{% endblock %}
{% elseif media.type == 'vimeo_video' %}
{% block hero_vimeo %}
<iframe class="hero__banner-video--vimeo-player" src="https://player.vimeo.com/video/{{ media.vimeoId }}" width="640" height="360" frameborder="0" allowfullscreen allow="autoplay; encrypted-media"></iframe>
{% endblock %}
{% elseif media.type == 'local_video' %}
{% block hero_html5 %}
<video class="hero__banner-video--html5-player" {% if hero_items|length is same as(1) %}autoplay{% endif %} loop muted>
<source src="{{ media.url }}" type="video/mp4">
</video>
{% endblock %}
{% endif %}
</div>
{% endif %}
{% block hero_preloader %}
<div class="hero__banner-video--preloader">
{% include '@ixm_blocks_hero/images/preloader.svg' %}
</div>
{% endblock %}
</div>
{% endmacro %}
{% macro carousel_control(hero_id, class, label) %}
{% set class = class|clean_class %}
<button class="carousel-control carousel-control-{{ class }}" type="button" data-bs-target="#{{ hero_id }}" data-bs-slide="{{ class }}">
<span class="carousel-control-{{ class }}-icon" aria-hidden="true"></span>
<span class="visually-hidden">{{ label|t }}</span>
</button>
{% endmacro %}
