Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -619,8 +619,24 @@ protected function getTextStyles(): array {
protected function getHeroImage(): array {
$url = Url::fromRoute('<front>');

$image_dimensions = [
'mobile' => [
'1x' => [768, 576],
'2x' => [1536, 1152],
],
'md' => [
'1x' => [1024, 580],
'2x' => [1536, 1160],
],
'lg' => [
'1x' => [1440, 800],
'2x' => [2880, 1600],
],
];
$image = $this->buildResponsiveImage($image_dimensions, 'image_item', 'seed');

return $this->buildElementHeroImage(
$this->buildImage($this->getPlaceholderImage(1600, 400)),
$image,
$this->getRandomTitle(),
$this->getRandomTitle(),
Link::fromTextAndUrl('Learn more', $url),
Expand Down Expand Up @@ -772,6 +788,93 @@ protected function buildImage(string $url) {
];
}

/**
* Build a responsive image using a <picture> element with breakpoint sources.
*
* Uses server_theme breakpoints to produce <source> elements per breakpoint.
* Each breakpoint key maps to srcset multipliers (1x, 2x) with
* [width, height].
*
* @param array $image_dimensions
* Dimensions keyed by breakpoint, subkeyed by multiplier. Example:
* @code
* [
* 'mobile' => ['1x' => [400, 300], '2x' => [800, 600]],
* 'sm' => ['1x' => [640, 480], '2x' => [1280, 960]],
* 'md' => ['1x' => [768, 576], '2x' => [1536, 1152]],
* 'lg' => ['1x' => [1024, 768], '2x' => [2048, 1536]],
* ]
* @endcode
* @param string $id
* The placeholder image ID or seed.
* @param string $id_type
* The type of the ID, either 'id' or 'seed'.
* @param string $alt
* Alt text.
*
* @return array
* A render array for a <picture> element.
*/
private function buildResponsiveImage(array $image_dimensions, string $id = '', string $id_type = 'id', string $alt = ''): array {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • string should normally be replaced with an enum
  • Can we call an actual responsive image, like used in the Themetrits / PEVB, instead of building one ourselves?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string should normally be replaced with an enum

I've created enum for $id_type. $id and $alt can have any value, so keeping those as string.

  • Can we call an actual responsive image, like used in the Themetrits / PEVB, instead of building one ourselves?

@amitaibu PEVB uses drupal media/image entity to build responsive images. But shouldn't we avoid Drupal entities in StyleGuideController (to avoid any database dependency and just using placeholder data)?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming there's a low level method that recieves a file, and creates the image style from it. Can you check that please

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amitaibu To create a responsive image we use:

[
      '#theme' => 'responsive_image',
      '#uri' => $file_uri,
]

The file uri needs to be from a file stream in Drupal's local filesystem i.e. either public:// or private://.

A file in modules is in neither such stream. We'll need to temporarily copy file directly to public:// to build it's image styles, which will copy a new file on every /style-guide page request (or we'll need to hardcode a filename for public://)

We do have an alternative. We can create a custom stream wrapper for style guide module server_style_guide:// which can process files from web/modules/custom/server_style_guide/images/ to create responsive image styles.
I'd recommend this option as we have responsive images in most of our components and currently style guide displays static images for all of them.

$breakpoint_media_queries = [
'2xl' => 'all and (min-width: 1536px)',
'xl' => 'all and (min-width: 1280px)',
'lg' => 'all and (min-width: 1024px)',
'md' => 'all and (min-width: 768px)',
'sm' => 'all and (min-width: 640px)',
'mobile' => '',
];

$sources = [];
// Iterate from largest to smallest so the browser picks the first match.
foreach ($breakpoint_media_queries as $breakpoint => $media_query) {
if (!isset($image_dimensions[$breakpoint])) {
continue;
}

$srcset_parts = [];
foreach ($image_dimensions[$breakpoint] as $multiplier => $dimensions) {
[$width, $height] = $dimensions;
$url = $this->getPlaceholderImage($width, $height, $id, $id_type);
$srcset_parts[] = "$url {$multiplier}";
}

$source = [
'#type' => 'html_tag',
'#tag' => 'source',
'#attributes' => [
'srcset' => implode(', ', $srcset_parts),
],
];
if (!empty($media_query)) {
$source['#attributes']['media'] = $media_query;
}
$sources[] = $source;
}

// Fallback <img> using the mobile 1x dimensions.
$fallback_breakpoint = isset($image_dimensions['mobile']) ? 'mobile' : array_key_first($image_dimensions);
$fallback_dimensions = $image_dimensions[$fallback_breakpoint]['1x'];
[$fallback_width, $fallback_height] = $fallback_dimensions;

$sources[] = [
'#type' => 'html_tag',
'#tag' => 'img',
'#attributes' => [
'src' => $this->getPlaceholderImage($fallback_width, $fallback_height, $id, $id_type),
'alt' => $alt,
'width' => $fallback_width,
'height' => $fallback_height,
],
];

return [
'#type' => 'html_tag',
'#tag' => 'picture',
'sources' => $sources,
];
}

/**
* Build text with HTML.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ server_theme.xl:
- 2x
# 2xl breakpoint - 1536px and up.
server_theme.2xl:
label: xl
label: 2xl
mediaQuery: 'all and (min-width: 1536px)'
weight: 5
multipliers:
Expand Down
Loading