Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ae22590
Add ranking, ranking-deck, and image SDCs
kevdevlu Jul 24, 2026
aae1e13
Wire az_ranking paragraph rendering through the new SDCs (#5813)
kevdevlu Jul 24, 2026
d0054c6
Rename image SDC to ranking-image; restore WebP/scale image delivery
kevdevlu Jul 27, 2026
00b6552
Ship a placeholder image via az_media for SDC examples
kevdevlu Jul 27, 2026
f3d0b80
Extract AZRankingComponentBuilder; fix widget preview reorder bug
kevdevlu Jul 27, 2026
bc9d351
Decouple ranking-image focal-point cropping from original width/height
kevdevlu Jul 27, 2026
2461419
Fix ESLint/PHPCS/PHPStan CI failures
kevdevlu Jul 27, 2026
27e2444
Merge branch 'main' into issue/5813
kevdevlu Jul 27, 2026
ac14e8d
Remove canvas dependency for prod
kevdevlu Jul 28, 2026
00add74
Make hover preview in Canvas Library display with correct aspect ratio
kevdevlu Jul 28, 2026
2690e51
Restore media/file cache tags for ranking images
kevdevlu Jul 28, 2026
87e3a46
Fall back to the media item's alt text for ranking images
kevdevlu Jul 31, 2026
2d81377
Internal Placeholder Service
kevdevlu Aug 5, 2026
1bbbefe
Make ranking-image purely decorative (no alt text)
kevdevlu Aug 5, 2026
9a85ad7
heading style adjustments
kevdevlu Aug 6, 2026
9cb2961
Clarify Comments, Remove dead code, Refactor ranking-image.js
kevdevlu Aug 6, 2026
a98198b
Fix empty ranking saving, and Not being able to remove all rankings i…
kevdevlu Aug 7, 2026
6d35d74
Ranking styles: description/source typography, card padding, image ra…
kevdevlu Aug 7, 2026
6e7a713
Prevent TwigFilter name clash with twig_tweak on www_barrio
kevdevlu Aug 7, 2026
1c3ebdd
Add pb-4 to ranking decks to match legacy formatter code
kevdevlu Aug 9, 2026
2b60bd2
Add period to comment to pass phpcs
kevdevlu Aug 9, 2026
477162c
`issue/5813` Sub-branch: Adopt Canvas's object image shape for rankin…
kevdevlu Aug 9, 2026
51e1c71
Merge branch 'main' into issue/5813
kevdevlu Aug 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions components/ranking-deck/ranking-deck.component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
name: Ranking Deck
status: experimental
description: A responsive grid of Ranking cards with per-breakpoint columns and consistent spacing. Drop Ranking components into the rankings slot.
props:
type: object
properties:
columns_desktop:
type: string
title: Rankings per row on desktop
description: How many rankings appear per row on desktop. Additional rankings wrap to a new row.
enum:
- '1'
- '2'
- '3'
- '4'
meta:enum:
'1': '1'
'2': '2'
'3': '3'
'4': 4 (default)
examples:
- '4'
columns_tablet:
type: string
title: Rankings per row on tablet
description: How many rankings appear per row on tablet.
enum:
- '1'
- '2'
- '3'
- '4'
meta:enum:
'1': '1'
'2': 2 (default)
'3': '3'
'4': '4'
examples:
- '2'
columns_phone:
type: string
title: Rankings per row on phone
description: How many rankings appear per row on phone.
enum:
- '1'
- '2'
- '3'
- '4'
meta:enum:
'1': 1 (default)
'2': '2'
'3': '3'
'4': '4'
examples:
- '1'
utility_classes:
type: array
title: Utility Classes
description: Additional Bootstrap utility classes for the deck wrapper, e.g. bottom spacing (mb-4) before the next item on the page.
items:
type: string
examples:
- - mb-4
slots:
rankings:
title: Rankings
description: The Ranking cards (or other content) laid out by the deck grid.
86 changes: 86 additions & 0 deletions components/ranking-deck/ranking-deck.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Ranking Deck component.
*
* A CSS grid for Ranking cards. The deck owns the layout, not the cards -
* how many columns show at each breakpoint comes from the modifier classes
* below.
*
* The 1.5rem gap matches the spacing pb-4 gave in the legacy markup, kept so
* decks look the same after the port. Grid items stretch to fill their row
* by default, which is what makes cards match heights without anything
* setting a height.
*/

.az-ranking-deck {
display: grid;
gap: 1.5rem;
/*
* Make every row as tall as the tallest row, so they look uniform within
* the whole deck.
*/
grid-auto-rows: 1fr;
}

/*
* Grid items start at min-width: auto, so a long unbroken word - a URL in a
* source line, say - can push its column wider than the track it was given
* and skew the whole row. Zero lets the item shrink and wrap instead.
*/
.az-ranking-deck > * {
min-width: 0;
}

/* Phone (base). */
.az-ranking-deck--phone-1 {
grid-template-columns: repeat(1, 1fr);
}

.az-ranking-deck--phone-2 {
grid-template-columns: repeat(2, 1fr);
}

.az-ranking-deck--phone-3 {
grid-template-columns: repeat(3, 1fr);
}

.az-ranking-deck--phone-4 {
grid-template-columns: repeat(4, 1fr);
}

/* Tablet. */
@media (min-width: 768px) {
.az-ranking-deck--tablet-1 {
grid-template-columns: repeat(1, 1fr);
}

.az-ranking-deck--tablet-2 {
grid-template-columns: repeat(2, 1fr);
}

.az-ranking-deck--tablet-3 {
grid-template-columns: repeat(3, 1fr);
}

.az-ranking-deck--tablet-4 {
grid-template-columns: repeat(4, 1fr);
}
}

/* Desktop. */
@media (min-width: 992px) {
.az-ranking-deck--desktop-1 {
grid-template-columns: repeat(1, 1fr);
}

.az-ranking-deck--desktop-2 {
grid-template-columns: repeat(2, 1fr);
}

.az-ranking-deck--desktop-3 {
grid-template-columns: repeat(3, 1fr);
}

.az-ranking-deck--desktop-4 {
grid-template-columns: repeat(4, 1fr);
}
}
58 changes: 58 additions & 0 deletions components/ranking-deck/ranking-deck.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{#
/**
* @file
* Template for the az_quickstart Ranking Deck component.
*
* Renders one <div> that arranges whatever is placed in its `rankings` slot
* into a CSS grid:
*
* <div class="az-ranking-deck az-ranking-deck--desktop-4
* az-ranking-deck--tablet-2 az-ranking-deck--phone-1">
*
* The deck owns the layout, not the cards inside it. How many columns show
* at each breakpoint comes from those modifier classes, so a Ranking card
* never has to know how many siblings it has.
*
* Props:
* - columns_desktop: Rankings per row on desktop (1-4). Defaults to 4.
* - columns_tablet: Rankings per row on tablet (1-4). Defaults to 2.
* - columns_phone: Rankings per row on phone (1-4). Defaults to 1.
* - utility_classes: Additional Bootstrap utility classes for the deck
* wrapper (e.g. bottom spacing).
*
* Slots:
* - rankings: The Ranking cards (or other content) placed in the grid.
*/
#}
{% set attributes = attributes|default(create_attribute()) %}

{#
If a column count is missing or is not 1-4, fall back to a safe default.
Rationale: the classes further down are built by sticking the number on
the end of a string, so a value like '7' would produce
az-ranking-deck--desktop-7, which no CSS matches. The next breakpoint down
then wins by default - a bad desktop value leaves the deck on its tablet
count, and only a deck with all three broken drops to one column.
#}
{% set allowed = ['1', '2', '3', '4'] %}
{% set columns_desktop = columns_desktop|default('4') in allowed ? columns_desktop|default('4') : '4' %}
{% set columns_tablet = columns_tablet|default('2') in allowed ? columns_tablet|default('2') : '2' %}
{% set columns_phone = columns_phone|default('1') in allowed ? columns_phone|default('1') : '1' %}
{% set utility_classes = utility_classes|default([]) %}
{% if utility_classes is not iterable %}
{% set utility_classes = [utility_classes] %}
{% endif %}

{% set deck_classes = [
'az-ranking-deck',
'az-ranking-deck--desktop-' ~ columns_desktop,
'az-ranking-deck--tablet-' ~ columns_tablet,
'az-ranking-deck--phone-' ~ columns_phone,
] %}
{% if utility_classes %}
{% set deck_classes = deck_classes|merge(utility_classes) %}
{% endif %}

<div{{ attributes.addClass(deck_classes) }}>
{{ rankings }}
</div>
112 changes: 112 additions & 0 deletions components/ranking-image/ranking-image.component.yml
Comment thread
kevdevlu marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json
name: Ranking Image
status: experimental
description: A decorative, layout-aware image backed by the media library. Works standalone on a page, or dropped into a Ranking Deck alongside Ranking cards.
props:
type: object
properties:
image:
title: Image
description: Pick an image from the media library.
type: object
required:
- src
properties:
src:
title: Image URL
type: string
format: uri-reference
contentMediaType: image/*
x-allowed-schemes:
- http
- https
alt:
title: Alternative text
type: string
width:
title: Image width
type: integer
height:
title: Image height
type: integer
examples:
- src: https://placehold.co/1000x500
alt: ''
width: 1000
height: 500
width_span_desktop:
type: string
title: Width Span (Desktop)
description: How many grid columns this image spans on desktop when placed inside a Ranking Deck (or any other CSS grid layout). Has no effect outside a grid layout. Keep at or below the deck's "Rankings per row on desktop" setting, or the image will overflow into extra columns.
enum:
- '1'
- '2'
- '3'
- '4'
meta:enum:
'1': 1 column
'2': 2 columns (default)
'3': 3 columns
'4': 4 columns
examples:
- '2'
width_span_tablet:
type: string
title: Width Span (Tablet)
description: How many grid columns this image spans on tablet. Keep at or below the deck's "Rankings per row on tablet" setting, or the image will overflow into extra columns.
enum:
- '1'
- '2'
- '3'
- '4'
meta:enum:
'1': 1 column
'2': 2 columns (default)
'3': 3 columns
'4': 4 columns
examples:
- '2'
width_span_phone:
type: string
title: Width Span (Phone)
description: How many grid columns this image spans on phone. Keep at or below the deck's "Rankings per row on phone" setting, or the image will overflow into extra columns.
enum:
- '1'
- '2'
- '3'
- '4'
meta:enum:
'1': 1 column (default)
'2': 2 columns
'3': 3 columns
'4': 4 columns
examples:
- '1'
focal_x:
type: number
title: Focal Point X
description: Horizontal focal point, as a fraction of the image's width from the left (0 = left edge, 1 = right edge). Keeps this point visible when the image is cropped to fill its container. Leave unset for default centered cropping.
minimum: 0
maximum: 1
examples:
- 0.5
focal_y:
type: number
title: Focal Point Y
description: Vertical focal point, as a fraction of the image's height from the top (0 = top edge, 1 = bottom edge). Keeps this point visible when the image is cropped to fill its container. Leave unset for default centered cropping.
minimum: 0
maximum: 1
examples:
- 0.5
utility_classes:
type: array
title: Utility Classes
description: Additional Bootstrap utility classes for the image wrapper, e.g. bottom spacing (mb-4) before the next item on the page. Not needed when the image is placed inside a Ranking Deck.
items:
type: string
examples:
- - mb-0
libraryOverrides:
dependencies:
- core/drupal
- core/once
Loading
Loading