diff --git a/modules/oe_whitelabel_helper/oe_whitelabel_helper.module b/modules/oe_whitelabel_helper/oe_whitelabel_helper.module old mode 100644 new mode 100755 index 6874592cc..9d69802fd --- a/modules/oe_whitelabel_helper/oe_whitelabel_helper.module +++ b/modules/oe_whitelabel_helper/oe_whitelabel_helper.module @@ -7,9 +7,68 @@ declare(strict_types = 1); +use Drupal\Core\Template\Attribute; + /** * Implements hook_locale_translation_projects_alter(). */ function oe_whitelabel_helper_locale_translation_projects_alter(&$projects) { $projects['oe_whitelabel_helper']['info']['interface translation server pattern'] = drupal_get_path('module', 'oe_whitelabel_helper') . '/translations/%project-%language.po'; } + +/** + * Theme preprocess function for grid_field_formatter. + * + * This function essentially extends the core field module theming methods, in + * particular template_preprocess_field. It also introduces new field template + * suggestions such as: + * - field--two-column.tpl.php + * - field--two-column--[FIELD_TYPE].tpl.php + * - field--two-column--[FIELD_NAME].tpl.php + * - field--two-column--[FIELD_NAME]--[BUNDLE].tpl.php. + * + * @see field--two-column.tpl.php + */ +function oe_whitelabel_helper_field_formatter(&$variables, $hook) { + // Extend the core field module theming functions. + template_preprocess_field($variables, $hook); + + // Add colummns number. + $number_of_columns = $variables['element']['#columns']; + $variables['columns'] = $number_of_columns; + + // Build row attributes. + $variables['row_attributes'] = new Attribute([ + 'class' => ['row'], + ]); + + // Build column layout number. + $variables['column_layout'] = floor(12 / $number_of_columns); +} + +/** + * Implements hook_theme_suggestions_HOOK(). + */ +function oe_whitelabel_helper_theme_suggestions_field__two_column(array $variables) { + $suggestions = []; + $element = $variables['element']; + + $suggestions[] = 'field__two_column' . $element['#field_type']; + $suggestions[] = 'field__two_column' . $element['#field_name']; + $suggestions[] = 'field__two_column' . $element['#entity_type'] . '__' . $element['#bundle']; + $suggestions[] = 'field__two_column' . $element['#entity_type'] . '__' . $element['#field_name']; + $suggestions[] = 'field__two_column' . $element['#entity_type'] . '__' . $element['#field_name'] . '__' . $element['#bundle']; + + return $suggestions; +} + +/** + * Implements hook_theme(). + */ +function oe_whitelabel_helper_theme() { + return [ + 'field_oe_whitelabel_double_column_formatter' => [ + 'render element' => 'element', + ], + ]; +} diff --git a/modules/oe_whitelabel_helper/src/Plugin/field_group/FieldGroupFormatter/MultiColumn.php b/modules/oe_whitelabel_helper/src/Plugin/field_group/FieldGroupFormatter/MultiColumn.php new file mode 100644 index 000000000..4e642469e --- /dev/null +++ b/modules/oe_whitelabel_helper/src/Plugin/field_group/FieldGroupFormatter/MultiColumn.php @@ -0,0 +1,272 @@ +moduleHandler = $module_handler; + $this->entityFieldManager = $entity_field_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $plugin_id, + $plugin_definition, + $configuration['group'], + $configuration['settings'], + $configuration['label'], + $container->get('module_handler'), + $container->get('entity_field.manager') + ); + } + + /** + * {@inheritdoc} + */ + public static function defaultContextSettings($context): array { + return [ + 'first_column' => '', + 'second_column' => '', + 'hide_table_if_empty' => FALSE, + ] + parent::defaultSettings(); + } + + /** + * {@inheritdoc} + */ + public function settingsForm(): array { + $form = parent::settingsForm(); + + $form['first_column'] = [ + '#title' => $this->t('First column classes'), + '#description' => $this->t('Add custom classes to the first column.'), + '#type' => 'textfield', + '#default_value' => $this->getSetting('first_column'), + ]; + $form['second_column'] = [ + '#title' => $this->t('Second column classes'), + '#description' => $this->t('Add custom classes to the second column.'), + '#type' => 'textfield', + '#default_value' => $this->getSetting('second_column'), + ]; + + $form['hide_table_if_empty'] = [ + '#title' => $this->t('Hide the table if empty'), + '#description' => $this->t('Do not output any table or container markup if there are no rows with values.'), + '#type' => 'checkbox', + '#default_value' => $this->getSetting('hide_table_if_empty'), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary(): array { + $summary = parent::settingsSummary(); + $summary[] = $this->t('Display results as a 2 column table.'); + + return $summary; + } + + /** + * {@inheritdoc} + */ + public function preRender(&$element, $rendering_object): void { + parent::preRender($element, $rendering_object); + + $element['#mode'] = $this->context; + // Allow modules to alter the rows, useful for removing empty rows. + $children = Element::children($element, TRUE); + $this->moduleHandler->alter('field_group_table_rows', $element, $children); + + if ($this->getSetting('hide_table_if_empty')) { + field_group_remove_empty_display_groups($element, []); + if ($element == []) { + return; + } + } + + // Elements wrapper. + $element['#type'] = 'container'; + $element['#attributes']['class'][] = 'my-3'; + + // Print the fieldset title. + $element['fieldset_title']['#type'] = 'markup'; + $element['fieldset_title']['#markup'] = '

' . $this->group->label . '

'; + + // Fieldset data container. + $element['fieldset']['data']['#type'] = 'container'; + $element['fieldset']['data']['#attributes']['class'][] = 'row'; + + // Set additional classes per column. + $classes = ['col-12', 'col-md-6']; + if ($this->getSetting('first_column')) { + $first_column_classes = array_merge($classes, [$this->getSetting('first_column')]); + } + + if ($this->getSetting('second_column')) { + $second_column_classes = array_merge($classes, [$this->getSetting('second_column')]); + } + // Columns container. + $element['fieldset']['data']['first_column']['#type'] = 'container'; + $element['fieldset']['data']['first_column']['#attributes'] = [ + 'class' => $this->getSetting('first_column') ? $first_column_classes : $classes, + ]; + $element['fieldset']['data']['second_column']['#type'] = 'container'; + $element['fieldset']['data']['second_column']['#attributes'] = [ + 'class' => $this->getSetting('second_column') ? $second_column_classes : $classes, + ]; + + $this->buildFieldsetColumns($element, $children); + } + + /** + * Build the columns of the fieldset. + */ + protected function buildFieldsetColumns(array &$element, array $children): void { + // Number of items in the first columns. + $first_column_elements = array_slice($children, 0, ceil(count($children) / 2)); + // Build fieldset column(s). + foreach ($children as $key => $field_name) { + $column = in_array($field_name, $first_column_elements) ? 'first_column' : 'second_column'; + if ($row = $this->buildRow($element, $field_name)) { + $element['fieldset']['data'][$column][$field_name] = $row; + } + unset($element[$field_name]); + } + } + + /** + * Build the row for requested element. + * + * @param array $element + * Rendering array of an element. + * @param string $field_name + * The name of currently handling field. + * + * @return array + * Table row definition on success or an empty array otherwise. + */ + protected function buildRow(array $element, string $field_name): array { + $item = $this->getRowItem($element, $field_name); + $build = []; + + if (!$item) { + return $build; + } + $item['#attributes'] = ['class' => 'col-12 col-md-6']; + $build = $item; + + return $build; + } + + /** + * Return item definition array. + * + * @param array $element + * Rendering array. + * @param string $field_name + * Item field machine name. + * + * @return array + * Item definition array on success or empty array otherwise. + */ + protected function getRowItem(array $element, string $field_name): array { + $item = $element[$field_name] ?? []; + $is_empty = !is_array($item) || !array_intersect($this->renderApiProperties, array_keys($item)); + + if ($is_empty && $this->getSetting('always_show_field_value') && isset($element['#entity_type'], $element['#bundle'])) { + $field_definitions = $this->entityFieldManager->getFieldDefinitions($element['#entity_type'], $element['#bundle']); + $field_definition = $field_definitions[$field_name] ?? NULL; + + if ($field_definition instanceof FieldConfigInterface) { + $is_empty = FALSE; + + $item = [ + '#title' => $field_definition->label(), + '#label_display' => 'above', + '#markup' => Xss::filter($this->getSetting('empty_field_placeholder')), + ]; + } + } + + $item['#attributes']['class'] = ['row']; + return $is_empty ? [] : $item; + } + +} diff --git a/modules/oe_whitelabel_helper/src/Plugin/field_group/templates/field--two-column.html.twig b/modules/oe_whitelabel_helper/src/Plugin/field_group/templates/field--two-column.html.twig new file mode 100755 index 000000000..700147dc5 --- /dev/null +++ b/modules/oe_whitelabel_helper/src/Plugin/field_group/templates/field--two-column.html.twig @@ -0,0 +1,49 @@ +{# +/** + * @file + * Default template for a field. + */ +#} +{% + set classes = [ + bundle|clean_class ~ '__' ~ field_name_clean|clean_class, + label_display == 'inline' ? 'd-flex', +] +%} +{% + set title_classes = [ + 'field__label', + 'col-12', + 'col-md-6', + label_display == 'visually_hidden' ? 'visually-hidden', +] +%} + +{% if label_hidden %} + {% if multiple %} + + {% for item in items %} + {{ item.content }} + {% endfor %} + + {% else %} + {% for item in items %} + {{ item.content }} + {% endfor %} + {% endif %} +{% else %} + + + {{ label }}{% if label_display == 'inline' %}:{% endif %} + + {% if multiple %} +
+ {% endif %} + {% for item in items %} + {{ item.content }}
+ {% endfor %} + {% if multiple %} + + {% endif %} + +{% endif %} diff --git a/modules/oe_whitelabel_user_profile/README.md b/modules/oe_whitelabel_user_profile/README.md new file mode 100755 index 000000000..798a6b75e --- /dev/null +++ b/modules/oe_whitelabel_user_profile/README.md @@ -0,0 +1,9 @@ +# OpenEuropa Whitelabel User Profile + +This module offers additional functionality to the User Profile feature. + +Here is an overview of the features it offers: + +## User Profile Management block + +A block providing a link to the user profile management. diff --git a/modules/oe_whitelabel_user_profile/oe_whitelabel_user_profile.info.yml b/modules/oe_whitelabel_user_profile/oe_whitelabel_user_profile.info.yml new file mode 100755 index 000000000..c97ae2fc1 --- /dev/null +++ b/modules/oe_whitelabel_user_profile/oe_whitelabel_user_profile.info.yml @@ -0,0 +1,5 @@ +name: OpenEuropa Whitelabel User Profile +type: module +description: Adds additional functionality to the user profile. +package: OpenEuropa Whitelabel Theme +core_version_requirement: ^8.9 || ^9.1 diff --git a/modules/oe_whitelabel_user_profile/src/Plugin/Block/UserProfileCta.php b/modules/oe_whitelabel_user_profile/src/Plugin/Block/UserProfileCta.php new file mode 100644 index 000000000..c5b1eae8d --- /dev/null +++ b/modules/oe_whitelabel_user_profile/src/Plugin/Block/UserProfileCta.php @@ -0,0 +1,79 @@ +getConfiguration(); + $uid = \Drupal::routeMatch()->getRawParameter('user'); + + $title = $this->t('Manage Profile'); + if (!empty($config['link_title'])) { + $title = $config['link_title']; + } + + $url = Url::fromUserInput("/user/{$uid}/edit"); + $link_options = [ + 'attributes' => [ + 'class' => [ + 'text-decoration-none', + 'text-reset', + ], + ], + ]; + $url->setOptions($link_options); + $link = Link::fromTextAndUrl($title, $url); + + return [ + '#markup' => $link->toString(), + ]; + } + + /** + * {@inheritdoc} + */ + public function blockForm($form, FormStateInterface $form_state): array { + $form = parent::blockForm($form, $form_state); + + $config = $this->getConfiguration(); + + $form['link_title'] = [ + '#type' => 'textfield', + '#title' => $this->t('Title'), + '#description' => $this->t('Title for the User Profile link'), + '#default_value' => $config['link_title'] ?? $this->t('Manage Profile'), + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function blockSubmit($form, FormStateInterface $form_state): void { + parent::blockSubmit($form, $form_state); + $values = $form_state->getValues(); + $this->configuration['link_title'] = $values['link_title']; + } + +} diff --git a/modules/oe_whitelabel_user_profile/templates/block--oe-whitelabel-user-profile.html.twig b/modules/oe_whitelabel_user_profile/templates/block--oe-whitelabel-user-profile.html.twig new file mode 100644 index 000000000..c38d98cdc --- /dev/null +++ b/modules/oe_whitelabel_user_profile/templates/block--oe-whitelabel-user-profile.html.twig @@ -0,0 +1,39 @@ +{# +/** + * @file + * Theme override to display a block. + * + * Available variables: + * - plugin_id: The ID of the block implementation. + * - label: The configured label of the block if visible. + * - configuration: A list of the block's configuration values. + * - label: The configured label for the block. + * - label_display: The display settings for the label. + * - provider: The module or other provider that provided this block plugin. + * - Block plugin specific settings will also be stored here. + * - content: The content of this block. + * - attributes: array of HTML attributes populated by modules, intended to + * be added to the main container tag of this template. + * - id: A valid HTML ID and guaranteed unique. + * - title_attributes: Same as attributes, except applied to the main title + * tag that appears in the template. + * - title_prefix: Additional output populated by modules, intended to be + * displayed in front of the main title tag that appears in the template. + * - title_suffix: Additional output populated by modules, intended to be + * displayed after the main title tag that appears in the template. + * + * @see template_preprocess_block() + */ +#} +{% + set classes = [ + 'block', + 'block-' ~ configuration.provider|clean_class, + 'block-' ~ plugin_id|clean_class, + ] +%} + + {% block content %} + {{ content }} + {% endblock %} + diff --git a/oe_whitelabel.theme b/oe_whitelabel.theme old mode 100644 new mode 100755 index b42c7187f..a5f7f545d --- a/oe_whitelabel.theme +++ b/oe_whitelabel.theme @@ -130,3 +130,54 @@ function oe_whitelabel_preprocess(&$variables) { $variables['bcl_component_library'] = theme_get_setting('component_library') ?? 'eu'; $variables['bcl_header_style'] = theme_get_setting('header_style') ?? 'standard'; } + +/** + * Implements hook_preprocess(). + */ +function oe_whitelabel_preprocess_pattern_card(array &$variables): void { + if ($variables['variant'] !== 'user_profile') { + return; + } + + $variables['horizontal'] = TRUE; + + // Multiple fields can be added to the same area, + // we need to print them inline. + $cards_fields = [ + 'title', + 'subtitle', + 'content', + 'image', + ]; + + foreach ($cards_fields as $card_field) { + if (array_key_exists('#sources', $variables[$card_field])) { + for ($i = 0; $i < count($variables[$card_field]['#sources']); $i++) { + $variables[$card_field]['#sources'][$i]['#attributes']['class'][] = 'd-inline'; + // Add margin left for the subsequent elements after the first. + if ($i > 0) { + $variables[$card_field]['#sources'][$i]['#attributes']['class'][] = 'ms-2'; + } + } + } + } + + $variables['title'] = [ + 'content' => $variables['title'], + 'tag' => "h2", + 'classes' => "fw-bold", + ]; + + $variables['subtitle'] = [ + 'content' => $variables['subtitle'], + 'tag' => "div", + 'classes' => "mb-4 mt-4 text-muted", + ]; + + $variables['image'] = [ + 'path' => $variables['image'][0]['#markup'] ?? '', + 'alt' => "alt img", + 'position' => "top", + 'classes' => "card-img-top", + ]; +} diff --git a/templates/patterns/card/card.ui_patterns.yml b/templates/patterns/card/card.ui_patterns.yml new file mode 100755 index 000000000..f860557fb --- /dev/null +++ b/templates/patterns/card/card.ui_patterns.yml @@ -0,0 +1,135 @@ +card: + label: "Card" + description: "A card is a flexible and extensible content container. It includes options for headers and footers, a wide variety of content, contextual background colors, and powerful display options. https://v5.getbootstrap.com/docs/5.0/components/card" + variants: + default: + label: Default + horizontal: + label: Horizontal + search: + label: Search + user_profile: + label: User Profile + settings: + style: + type: select + label: Card style + options: + primary: primary + secondary: secondary + success: success + danger: danger + warning: warning + info: info + light: light + dark: dark + border_variant: + type: select + label: Card border style + options: + primary: primary + secondary: secondary + success: success + danger: danger + warning: warning + info: info + light: light + dark: dark + text_color: + type: select + label: Card text color + options: + dark: dark + white: white + horizontal: + type: boolean + label: "Horizontal" + description: "Horizontal card" + preview: false + call_to_action_button_variant: + type: select + label: Call to action button variant + options: + primary: primary + secondary: secondary + success: success + danger: danger + warning: warning + info: info + light: light + dark: dark + fields: + title: + type: "array" + label: "Title" + description: "Card title [content, tag, classes]" + preview: + content: "Title card" + tag: "h5" + subtitle: + type: "array" + label: "Subtitle" + description: "Card subtitle [content, tag, classes]" + preview: + content: "Subtitle card" + classes: "mb-2" + text: + type: "array" + label: "Text" + description: "Card text [content, tag, classes]" + preview: + content: "Text card with longer text which is supported" + classes: "mb-2" + image: + type: "array" + label: "Image" + description: "Card image [path, alt, position]" + preview: + path: "https://placeimg.com/1000/500/arch" + alt: "Alternative text for card image" + position: "top" + rounded: 3 + content: + type: "render" + label: "Content" + description: "Card content" + preview: "" + card_header: + type: "render" + label: "Card header" + description: "Card header content" + preview: "Header of card" + card_footer: + type: "render" + label: "Card footer" + description: "Card footer content" + preview: "Footer of card" + call_to_action_button: + type: "render" + label: "Call to action button" + description: "Add a call to action button" + preview: "" + horizontal_grid: + type: "array" + label: "Horizontal grid" + description: "Horizontal grid layout [left_col, right_col, gutter]" + extra_classes_body: + type: "text" + label: "Extra classes for card body" + preview: "body-class" + extra_classes_header: + type: "text" + label: "Extra classes for card header" + preview: "header-class" + extra_classes_footer: + type: "text" + label: "Extra classes for card footer" + preview: "footer-class" + badges: + type: "array" + label: "Badges for the card" + preview: + - label: "Primary badge" + - label: "Secondary badge" + assistive_text: "Assistive text for secondary badge" + rounded_pill: true diff --git a/templates/patterns/card/pattern-card--variant-user-profile.html.twig b/templates/patterns/card/pattern-card--variant-user-profile.html.twig new file mode 100644 index 000000000..2e36ccb92 --- /dev/null +++ b/templates/patterns/card/pattern-card--variant-user-profile.html.twig @@ -0,0 +1,237 @@ +{% spaceless %} + {# Parameters: + - title (object) (default: {}) + format: { + content: '', + tag: '', + classes: '' + } + - subtitle (object) (default: {}) + format: { + content: '', + tag: '', + classes: '' + } + - text (object) (default: {}) + format: { + content: '', + tag: '', + classes: '' + } + - content (string) (default: '') + - image (object) (default: {}) + format: { + path (string), + alt (string), + position (string) + rounded (integer) + } + - horizontal (boolean) (default: false) + - horizontal_grid (object) (default: {}) + format: { + left_col_classes (default: 'col-4') + right_col_classes (default: 'col-8') + gutter (default: '') + } + - variant (string) (default: '') + - border_variant (string) (default: '') + - text_color (string) (default: '') + options: ['dark', 'white'] + - card_header (string) (default: '') + - card_footer (string) (default: '') + - call_to_action_button (string) (default: '') + - extra_classes_body (string) (default: '') + - extra_classes_header (string) (default: '') + - extra_classes_footer (string) (default: '') + - badges (array of badge object) (default: []) + #} + + {% set _title = title|default({}) %} + {% set _subtitle = subtitle|default({}) %} + {% set _text = text|default({}) %} + {% set _content = content|default('') %} + {% set _image = image|default({}) %} + {% set _variant = variant|default('') %} + {% set _horizontal = horizontal|default(false) %} + {% set _horizontal_grid = horizontal_grid|default({ + left_col_classes: 'col-6 col-md-3 offset-3 offset-md-0', + right_col_classes: 'col-md-9' + }) %} + {% set _border_variant = border_variant|default('') %} + {% set _text_color = text_color|default('') %} + {% set _card_header = card_header|default('') %} + {% set _card_footer = card_footer|default('') %} + {% set _call_to_action_button = call_to_action_button|default('') %} + {% set _call_to_action_button_variant = call_to_action_button_variant|default('') %} + {% set _extra_classes_body = extra_classes_body|default('') %} + {% set _extra_classes_header = extra_classes_header|default('') %} + {% set _extra_classes_footer = extra_classes_footer|default('') %} + {% set _badges = badges|default([]) %} + {% set _body_classes = body_classes ? body_classes ~ ' user_profile-body' : 'user_profile-body' %} + {% set _classes = ['user_profile', 'border-0', 'mb-md-3'] %} + {% if _text_color is not empty %} + {% set _classes = _classes|merge(['text-' ~ _text_color]) %} + {% endif %} + {% if _variant is not empty %} + {% set _classes = _classes|merge(['bg-' ~ _variant]) %} + {% endif %} + {% if _border_variant is not empty %} + {% set _classes = _classes|merge(['border-' ~ _border_variant]) %} + {% endif %} + + {% if _extra_classes_body is not empty %} + {% set _body_classes = _body_classes ~ ' ' ~ _extra_classes_body %} + {% endif %} + + {% set _header_classes = 'user_profile-header' %} + {% if _extra_classes_header is not empty %} + {% set _header_classes = _header_classes ~ ' ' ~ _extra_classes_header %} + {% endif %} + + {% set _footer_classes = 'user_profile-footer' %} + {% if _extra_classes_footer is not empty %} + {% set _footer_classes = _footer_classes ~ ' ' ~ _extra_classes_footer %} + {% endif %} + + {% set _row_classes = 'row' %} + {% if _horizontal_grid.gutter is not empty %} + {% set _row_classes = _row_classes ~ ' g-' ~ _horizontal_grid.gutter %} + {% endif %} + + {% set attributes = attributes.addClass(_classes) %} +
+
+
+ {% if _card_header is not empty %} +
+ {{- _card_header -}} +
+ {% endif %} + {% if _horizontal %} +
+ {% endif %} + {% if _image is not empty and _image.position != 'bottom' %} + {% if _image.classes is not empty %} + {% set _img_class = _image.classes ~ ' user_profile-img-top' %} + {% else %} + {% set _img_class = 'user_profile-img-top' %} + {% endif %} + {% if _image.position == 'background' %} + {% set _img_class = 'user_profile-img' %} + {% endif %} + {% if _image.rounded is not empty %} + {% set _img_class = _img_class ~ ' rounded-' ~ _image.rounded %} + {% endif %} + {% if _horizontal %} +
+ {% endif %} + {{ _image.alt }} + {% if _horizontal %} +
+ {% endif %} + {% if _image.position == 'background' %} +
+ {% endif %} + {% endif %} + {% if _horizontal %} +
+ {% endif %} +
+ {%- if _badges is not empty and _badges is iterable -%} +
+ {% for _badge in _badges %} + {% if _badge.attributes is empty %} + {% set _badge = _badge|merge({ + attributes: create_attribute() + }) %} + {% endif %} + {% if not loop.last %} + {% set _badge = _badge|merge({ + attributes: _badge.attributes.addClass('me-2') + }) + %} + {% endif %} + {% include '@oe-bcl/bcl-badge/badge.html.twig' with _badge only %} + {% endfor %} +
+ {%- endif -%} + {%- if _title is not empty -%} + {% set _title_tag = _title.tag ?? 'h5' %} + <{{ _title_tag }} + class='card-title{{ title.classes ? ' ' ~ title.classes }}' + {% if _title.attributes is not empty and _title.attributes is iterable %} + {% for attribute in _title.attributes %} + {{ create_attribute().set(attribute.name, attribute.value) }} + {% endfor %} + {% endif %} + > + {{- title.content -}} + + {%- endif -%} + {%- if _subtitle is not empty -%} + {% set _subtitle_tag = _subtitle.tag ?? 'h6' %} + <{{ _subtitle_tag }} + class='card-subtitle{{ _subtitle.classes ? ' ' ~ _subtitle.classes }}' + > + {{- _subtitle.content -}} + + {%- endif -%} + {%- if _text is not empty -%} + {% set _text_tag = _text.tag ?? 'p' %} + <{{ _text_tag }} + class='card-text{{ _text.classes ? ' ' ~ _text.classes }}' + > + {{- _text.content -}} + + {%- endif -%} + {%- if _content is not empty -%} + {{- _content -}} + {%- endif -%} +
+ {% if _horizontal %} +
+ {% endif %} + {% if _image is not empty %} + {% if _image.position == 'background' %} +
+ {% endif %} + {% if _image.position == 'bottom' %} + {% if _horizontal %} +
+ {% endif %} + {{ _image.alt }} + {% if _horizontal %} +
+ {% endif %} + {% endif %} + {% endif %} + {% if _horizontal %} +
+ {% endif %} + {% if _card_footer is not empty %} + + {% endif %} +
+
+
+
+ {{ pattern('button', { + variant: _call_to_action_button_variant, + label: _call_to_action_button, + }) }} +
+
+
+{% endspaceless %}