diff --git a/core/themes/olivero/components/teaser/teaser.component.yml b/core/themes/olivero/components/teaser/teaser.component.yml new file mode 100644 index 0000000000000000000000000000000000000000..5fb91c2024013a2fa35efb1dc1b5ea4fbf83f308 --- /dev/null +++ b/core/themes/olivero/components/teaser/teaser.component.yml @@ -0,0 +1,44 @@ +# This is so your IDE knows about the syntax for fixes and autocomplete. +$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json + +# The human readable name. +name: Teaser + +# Status can be: "experimental", "stable", "deprecated", "obsolete". +status: stable + +# Schema for the props. We support www.json-schema.org. Learn more about the +# syntax there. +props: + type: object + properties: + attributes: + type: Drupal\Core\Template\Attribute + title: Attributes + description: Wrapper attributes. + +# Slots always hold arbitrary markup. We know that beforehand, so no need for +# a schema for slots. +slots: + # The key is the name of the slot. In your template you will use + # {% block content %}. + content: + title: Content + required: true + description: The teaser content + image: + title: Image + required: false + description: Teaser image + meta: + title: Meta + required: false + description: Teaser meta + prefix: + title: Prefix + required: false + description: Contextual links slot + title: + title: Title content + required: false + description: Teaser title diff --git a/core/themes/olivero/components/teaser/teaser.css b/core/themes/olivero/components/teaser/teaser.css new file mode 100644 index 0000000000000000000000000000000000000000..1db0a4466c37389a0087ccec7da3a9fab29a1004 --- /dev/null +++ b/core/themes/olivero/components/teaser/teaser.css @@ -0,0 +1,100 @@ +/* + * DO NOT EDIT THIS FILE. + * See the following change record for more information, + * https://www.drupal.org/node/3084859 + * @preserve + */ +.teaser { + position: relative; /* Anchor after pseudo-element. */ + padding-block-end: var(--sp1-5); +} +.teaser::after { + position: absolute; + inset-block-end: 0; + width: var(--sp3); + height: 0; + content: ""; + /* Intentionally not using CSS logical properties. */ + border-top: solid 2px var(--color--gray-95); +} +@media (min-width: 62.5rem) { + .teaser { + padding-block-end: var(--sp3); + } +} +.teaser__content { + display: grid; + grid-auto-rows: max-content; + gap: var(--sp); +} +.teaser__content .field:not(:last-child) { + margin-block-end: 0; +} +@media (min-width: 62.5rem) { + .teaser__content { + gap: var(--sp2); + } +} +.teaser__image { + flex-shrink: 0; + margin: 0; +} +.teaser__image:empty { + display: none; +} +.teaser__image:empty + .teaser__title { + flex-basis: auto; +} +.teaser__image a { + display: block; +} +.teaser__image img { + width: var(--sp3-5); + height: var(--sp3-5); + object-fit: cover; + border-radius: 50%; +} +@media (min-width: 62.5rem) { + .teaser__image img { + width: var(--grid-col-width); + height: var(--grid-col-width); + } +} +@media (min-width: 62.5rem) { + .teaser__image { + position: absolute; + inset-block-start: 0; + inset-inline-start: calc(-1 * ((var(--grid-col-width) + var(--grid-gap)))); + margin: 0; + } +} +.teaser__meta { + margin-block-end: var(--sp); +} +.teaser__title { + margin-block: 0; + flex-basis: calc(100% - var(--sp4-5)); + color: var(--color-text-neutral-loud); + font-size: 1.5rem; + line-height: var(--line-height-base); +} +@media (min-width: 62.5rem) { + .teaser__title { + flex-basis: auto; + font-size: var(--sp2); + line-height: var(--sp3); + } +} +.teaser__top { + display: flex; + flex-wrap: nowrap; + align-items: center; + margin: 0; + gap: var(--sp1); + margin-block-end: var(--sp1); +} +@media (min-width: 62.5rem) { + .teaser__top { + position: relative; /* Anchor the image */ + } +} diff --git a/core/themes/olivero/components/teaser/teaser.pcss.css b/core/themes/olivero/components/teaser/teaser.pcss.css new file mode 100644 index 0000000000000000000000000000000000000000..ff07f8c06542c7ce8c15624105fec8256e193dec --- /dev/null +++ b/core/themes/olivero/components/teaser/teaser.pcss.css @@ -0,0 +1,101 @@ +@import "../../css/base/media-queries.pcss.css"; + +.teaser { + position: relative; /* Anchor after pseudo-element. */ + padding-block-end: var(--sp1-5); + + &::after { + position: absolute; + inset-block-end: 0; + width: var(--sp3); + height: 0; + content: ""; + /* Intentionally not using CSS logical properties. */ + border-top: solid 2px var(--color--gray-95); + } + + @media (--lg) { + padding-block-end: var(--sp3); + } +} + +.teaser__content { + display: grid; + grid-auto-rows: max-content; + gap: var(--sp); + + .field:not(:last-child) { + margin-block-end: 0; + } + + @media (--lg) { + gap: var(--sp2); + } +} + +.teaser__image { + flex-shrink: 0; + margin: 0; + + &:empty { + display: none; + + & + .teaser__title { + flex-basis: auto; + } + } + + & a { + display: block; + } + + & img { + width: var(--sp3-5); + height: var(--sp3-5); + object-fit: cover; + border-radius: 50%; + + @media (--lg) { + width: var(--grid-col-width); + height: var(--grid-col-width); + } + } + + @media (--lg) { + position: absolute; + inset-block-start: 0; + inset-inline-start: calc(-1 * ((var(--grid-col-width) + var(--grid-gap)))); + margin: 0; + } +} + +.teaser__meta { + margin-block-end: var(--sp); +} + +.teaser__title { + margin-block: 0; + flex-basis: calc(100% - var(--sp4-5)); + color: var(--color-text-neutral-loud); + font-size: 24px; + line-height: var(--line-height-base); + + @media (--lg) { + flex-basis: auto; + font-size: var(--sp2); + line-height: var(--sp3); + } +} + +.teaser__top { + display: flex; + flex-wrap: nowrap; + align-items: center; + margin: 0; + gap: var(--sp1); + margin-block-end: var(--sp1); + + @media (--lg) { + position: relative; /* Anchor the image */ + } +} diff --git a/core/themes/olivero/components/teaser/teaser.twig b/core/themes/olivero/components/teaser/teaser.twig new file mode 100644 index 0000000000000000000000000000000000000000..ee1fe240d38e85412d327c09e38cf07762d14054 --- /dev/null +++ b/core/themes/olivero/components/teaser/teaser.twig @@ -0,0 +1,15 @@ +<article{{ attributes.addClass('teaser') }}> + <header> + {% block prefix %}{% endblock %} + <div class="teaser__meta"> + {% block meta %}{% endblock %} + </div> + <div class="teaser__top"> + <div class="teaser__image">{% block image %}{% endblock %}</div> + {% block title %}{% endblock %} + </div> + </header> + <div class="teaser__content"> + {% block content %}{% endblock %} + </div> +</article> diff --git a/core/themes/olivero/css/components/field.css b/core/themes/olivero/css/components/field.css index d4fad4c5b8e26981ae71257e7a636f7dca544571..17c474ee2b56b07abfcc973d7c4fc8d7e18e0907 100644 --- a/core/themes/olivero/css/components/field.css +++ b/core/themes/olivero/css/components/field.css @@ -14,20 +14,6 @@ margin-block-end: var(--sp2); } -.node--view-mode-teaser .field { - margin-block-end: var(--sp); -} - -.node--view-mode-teaser .field:last-child { - margin-block-end: 0; -} - -@media (min-width: 62.5rem) { - .node--view-mode-teaser .field { - margin-block-end: var(--sp2); - } -} - .field__label { font-weight: bold; } diff --git a/core/themes/olivero/css/components/field.pcss.css b/core/themes/olivero/css/components/field.pcss.css index 7c08eaf127dc02f8b66aa9ad5b34a11909ea7cdf..f2f9d691346744639570a6a8d7a468ae02f0b4cb 100644 --- a/core/themes/olivero/css/components/field.pcss.css +++ b/core/themes/olivero/css/components/field.pcss.css @@ -9,18 +9,6 @@ margin-block-end: var(--sp2); } -.node--view-mode-teaser .field { - margin-block-end: var(--sp); - - &:last-child { - margin-block-end: 0; - } - - @media (--lg) { - margin-block-end: var(--sp2); - } -} - .field__label { font-weight: bold; } diff --git a/core/themes/olivero/css/components/node-teaser.css b/core/themes/olivero/css/components/node-teaser.css index 103ca2ec8815cb31e154171345db17827b36ed57..b47415116eb43450c8967b0d0428b7f704318e1f 100644 --- a/core/themes/olivero/css/components/node-teaser.css +++ b/core/themes/olivero/css/components/node-teaser.css @@ -10,21 +10,6 @@ * Node Teaser specific styles. */ -.node--view-mode-teaser { - position: relative; /* Anchor after pseudo-element. */ - margin-block-end: var(--sp1-5); -} - -.node--view-mode-teaser::after { - position: absolute; - inset-block-end: 0; - width: var(--sp3); - height: 0; - content: ""; - /* Intentionally not using CSS logical properties. */ - border-top: solid 2px var(--color--gray-95); -} - .node--view-mode-teaser .node__meta { margin-block-end: var(--sp); } @@ -34,80 +19,6 @@ font-weight: bold; } -.node--view-mode-teaser .node__top-wrapper { - display: flex; - flex-wrap: wrap; - align-items: center; - margin: 0; -} - -@media (min-width: 62.5rem) { - .node--view-mode-teaser .node__top-wrapper { - position: relative; /* Anchor the image */ - } -} - -.node--view-mode-teaser .primary-image { - flex-shrink: 0; - margin: 0; - margin-block-end: var(--sp1); - margin-inline-end: var(--sp1); - - /* Ensure title does not wrap under image until necessary. */ -} - -:is(.node--view-mode-teaser .primary-image) + .node__title { - flex-basis: calc(100% - var(--sp4-5)); -} - -@media (min-width: 62.5rem) { - :is(.node--view-mode-teaser .primary-image) + .node__title { - flex-basis: auto; - } -} - -.node--view-mode-teaser .primary-image a { - display: block; -} - -.node--view-mode-teaser .primary-image img { - width: var(--sp3-5); - height: var(--sp3-5); - object-fit: cover; - border-radius: 50%; -} - -@media (min-width: 62.5rem) { - .node--view-mode-teaser .primary-image img { - width: var(--grid-col-width); - height: var(--grid-col-width); - } -} - -@media (min-width: 62.5rem) { - .node--view-mode-teaser .primary-image { - position: absolute; - inset-block-start: 0; - inset-inline-start: calc(-1 * ((var(--grid-col-width) + var(--grid-gap)))); - margin: 0; - } -} - -.node--view-mode-teaser .node__title { - margin: 0; - margin-block-end: var(--sp1); - color: var(--color-text-neutral-loud); - font-size: 1.5rem; - line-height: var(--line-height-base); -} - -@media (min-width: 62.5rem) { - .node--view-mode-teaser .node__title { - font-size: var(--sp2); - line-height: var(--sp3); - } -} - .node--view-mode-teaser .field--tag-ref { margin-block-start: var(--sp1); margin-block-end: 0; @@ -124,13 +35,3 @@ margin-block-start: var(--sp2); } } - -@media (min-width: 62.5rem) { - .node--view-mode-teaser { - margin-block-end: var(--sp3); - } -} - -.views-row:last-child .node--view-mode-teaser { - margin-block-end: 0; -} diff --git a/core/themes/olivero/css/components/node-teaser.pcss.css b/core/themes/olivero/css/components/node-teaser.pcss.css index 1d045f46d2ea8784d4b1ac625c3383d8c8a15bd8..ec6492c2a363994e5dbcf07a8d8acbdfeb4e157b 100644 --- a/core/themes/olivero/css/components/node-teaser.pcss.css +++ b/core/themes/olivero/css/components/node-teaser.pcss.css @@ -6,19 +6,6 @@ @import "../base/media-queries.pcss.css"; .node--view-mode-teaser { - position: relative; /* Anchor after pseudo-element. */ - margin-block-end: var(--sp1-5); - - &::after { - position: absolute; - inset-block-end: 0; - width: var(--sp3); - height: 0; - content: ""; - /* Intentionally not using CSS logical properties. */ - border-top: solid 2px var(--color--gray-95); - } - & .node__meta { margin-block-end: var(--sp); @@ -28,69 +15,6 @@ } } - & .node__top-wrapper { - display: flex; - flex-wrap: wrap; - align-items: center; - margin: 0; - - @media (--lg) { - position: relative; /* Anchor the image */ - } - } - - & .primary-image { - flex-shrink: 0; - margin: 0; - margin-block-end: var(--sp1); - margin-inline-end: var(--sp1); - - /* Ensure title does not wrap under image until necessary. */ - & + .node__title { - flex-basis: calc(100% - var(--sp4-5)); - - @media (--lg) { - flex-basis: auto; - } - } - - & a { - display: block; - } - - & img { - width: var(--sp3-5); - height: var(--sp3-5); - object-fit: cover; - border-radius: 50%; - - @media (--lg) { - width: var(--grid-col-width); - height: var(--grid-col-width); - } - } - - @media (--lg) { - position: absolute; - inset-block-start: 0; - inset-inline-start: calc(-1 * ((var(--grid-col-width) + var(--grid-gap)))); - margin: 0; - } - } - - & .node__title { - margin: 0; - margin-block-end: var(--sp1); - color: var(--color-text-neutral-loud); - font-size: 24px; - line-height: var(--line-height-base); - - @media (--lg) { - font-size: var(--sp2); - line-height: var(--sp3); - } - } - & .field--tag-ref { margin-block-start: var(--sp1); margin-block-end: 0; @@ -105,12 +29,4 @@ margin-block-start: var(--sp2); } } - - @media (--lg) { - margin-block-end: var(--sp3); - } -} - -.views-row:last-child .node--view-mode-teaser { - margin-block-end: 0; -} +} \ No newline at end of file diff --git a/core/themes/olivero/css/layout/views.css b/core/themes/olivero/css/layout/views.css index e97620b1ed0e3125cd1a31dad8a01e52948e3206..9594194e744f8e82c4fd64d3ff57cee316f6b277 100644 --- a/core/themes/olivero/css/layout/views.css +++ b/core/themes/olivero/css/layout/views.css @@ -10,16 +10,16 @@ * Styles for views. */ -.view > * { - margin-block-end: var(--sp2); -} - -.view > *:last-child { - margin-block-end: 0; +.view, +.view-content { + display: grid; + gap: var(--sp2); + grid-template-rows: max-content; } @media (min-width: 43.75rem) { - .view > * { - margin-block-end: var(--sp3); + .view, + .view-content { + gap: var(--sp3); } } diff --git a/core/themes/olivero/css/layout/views.pcss.css b/core/themes/olivero/css/layout/views.pcss.css index cbc6f03f479b098ea91fcee7fef2bbc43da1bdd8..3bedc2d9a4ec7625c3c8c0e42c328d7b42b326e5 100644 --- a/core/themes/olivero/css/layout/views.pcss.css +++ b/core/themes/olivero/css/layout/views.pcss.css @@ -5,16 +5,13 @@ @import "../base/media-queries.pcss.css"; -.view { - & > * { - margin-block-end: var(--sp2); +.view, +.view-content { + display: grid; + gap: var(--sp2); + grid-template-rows: max-content; - &:last-child { - margin-block-end: 0; - } - - @media (--md) { - margin-block-end: var(--sp3); - } + @media (--md) { + gap: var(--sp3); } } diff --git a/core/themes/olivero/templates/content/node--teaser.html.twig b/core/themes/olivero/templates/content/node--teaser.html.twig index 8720f2f473abcc6578da01be8d8b55c720ee1e5f..a6a0fc7cd6bfe120fc4136328bf8daa9dc105fdf 100644 --- a/core/themes/olivero/templates/content/node--teaser.html.twig +++ b/core/themes/olivero/templates/content/node--teaser.html.twig @@ -78,10 +78,27 @@ ] %} -<article{{ attributes.addClass(classes) }}> - <header> + +{% embed "olivero:teaser" with { + attributes: attributes.addClass(classes), + author_attributes, + author_name, + content, + date, + display_submitted, + label, + metadata, + title_attributes, + title_prefix, + title_suffix, + read_more, + url, + } only %} + {% block prefix %} {{ title_prefix }} {{ title_suffix }} + {% endblock %} + {% block meta %} {% if display_submitted %} <div class="node__meta"> <span{{ author_attributes }}> @@ -90,16 +107,16 @@ {{ metadata }} </div> {% endif %} + {% endblock %} + {% block image %}{{~ content.field_image ~}}{% endblock %} + {% block title %} {% if label and not page %} - <div class="node__top-wrapper"> - {{ content.field_image }} - <h2{{ title_attributes.addClass('node__title') }}> - <a href="{{ url }}" rel="bookmark">{{ label }}</a> - </h2> - </div> + <h2{{ title_attributes.addClass('node__title', 'teaser__title') }}> + <a href="{{ url }}" rel="bookmark">{{ label }}</a> + </h2> {% endif %} - </header> - <div{{ content_attributes.addClass('node__content') }}> + {% endblock %} + {% block content %} {{ content|without('field_image', 'links') }} - </div> -</article> + {% endblock %} +{% endembed %} diff --git a/core/themes/olivero/templates/field/field--node--field-image.html.twig b/core/themes/olivero/templates/field/field--node--field-image.html.twig deleted file mode 100644 index 77ce43a4dcc1fc84cd70fcf30ac18d192393755a..0000000000000000000000000000000000000000 --- a/core/themes/olivero/templates/field/field--node--field-image.html.twig +++ /dev/null @@ -1,26 +0,0 @@ -{# -/** - * @file - * Theme override for the image field. - * - * Available variables: - * - attributes: HTML attributes for the containing element. - * - label_hidden: Whether to show the field label or not. - * - title_attributes: HTML attributes for the title. - * - label: The label for the field. - * - multiple: TRUE if a field can contain multiple items. - * - items: List of all the field items. Each item contains: - * - attributes: List of HTML attributes for each item. - * - content: The field item's content. - * - entity_type: The entity type to which the field belongs. - * - field_name: The name of the field. - * - field_type: The type of the field. - * - label_display: The display settings for the label. - * - * - * @see template_preprocess_field() - */ -#} - -{% extends 'field.html.twig' %} -{% set attributes = attributes.addClass('primary-image') %}