diff --git a/web/modules/custom/server_style_guide/images/sand-1980x1060.jpg b/web/modules/custom/server_style_guide/images/sand-1980x1060.jpg new file mode 100644 index 000000000..02b9b400c Binary files /dev/null and b/web/modules/custom/server_style_guide/images/sand-1980x1060.jpg differ diff --git a/web/modules/custom/server_style_guide/server_style_guide.services.yml b/web/modules/custom/server_style_guide/server_style_guide.services.yml new file mode 100644 index 000000000..f55ddb79b --- /dev/null +++ b/web/modules/custom/server_style_guide/server_style_guide.services.yml @@ -0,0 +1,5 @@ +services: + stream_wrapper.server_style_guide: + class: Drupal\server_style_guide\StreamWrapper\StyleGuideStream + tags: + - { name: stream_wrapper, scheme: server-style-guide } diff --git a/web/modules/custom/server_style_guide/src/Controller/StyleGuideController.php b/web/modules/custom/server_style_guide/src/Controller/StyleGuideController.php index 66405d8a5..feeb06b1c 100644 --- a/web/modules/custom/server_style_guide/src/Controller/StyleGuideController.php +++ b/web/modules/custom/server_style_guide/src/Controller/StyleGuideController.php @@ -24,6 +24,7 @@ use Drupal\server_general\ThemeTrait\QuoteThemeTrait; use Drupal\server_general\ThemeTrait\SearchThemeTrait; use Drupal\server_general\WebformTrait; +use Drupal\server_style_guide\ThemeTrait\Enum\IdTypeEnum; use Drupal\server_style_guide\ThemeTrait\StyleGuideElementWrapThemeTrait; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -618,9 +619,10 @@ protected function getTextStyles(): array { */ protected function getHeroImage(): array { $url = Url::fromRoute(''); + $image = $this->buildResponsiveImage('hero', 'server-style-guide://sand-1980x1060.jpg'); return $this->buildElementHeroImage( - $this->buildImage($this->getPlaceholderImage(1600, 400)), + $image, $this->getRandomTitle(), $this->getRandomTitle(), Link::fromTextAndUrl('Learn more', $url), @@ -772,6 +774,34 @@ protected function buildImage(string $url) { ]; } + /** + * Build a responsive image render array using responsive_image theme. + * + * Uses the server_style_guide:// stream wrapper which maps to the module's + * images/ directory, allowing Drupal image styles to process module-bundled + * images without copying them to public://. + * + * @param string $responsive_image_style_id + * The responsive image style ID (e.g. 'hero'). + * @param string $uri + * The image uri. + * @param string $alt + * Alt text for the image. + * + * @return array + * A render array using the responsive_image theme. + */ + private function buildResponsiveImage(string $responsive_image_style_id, string $uri, string $alt = ''): array { + return [ + '#theme' => 'responsive_image', + '#uri' => $uri, + '#responsive_image_style_id' => $responsive_image_style_id, + '#attributes' => [ + 'alt' => $alt, + ], + ]; + } + /** * Build text with HTML. * @@ -814,15 +844,15 @@ protected function buildProcessedText(string $text) { * The height of the image. * @param string $id * The ID of the image. Or a seed. - * @param string $id_type + * @param \Drupal\server_style_guide\ThemeTrait\Enum\IdTypeEnum $id_type * The type of the ID, either 'id' or 'seed'. * * @return string * URL with placeholder. */ - protected function getPlaceholderImage(int $width, int $height, string $id = '', string $id_type = 'id') { + protected function getPlaceholderImage(int $width, int $height, string $id = '', IdTypeEnum $id_type = IdTypeEnum::Id) { if (!empty($id)) { - return "https://picsum.photos/{$id_type}/{$id}/{$width}/{$height}.jpg"; + return "https://picsum.photos/{$id_type->value}/{$id}/{$width}/{$height}.jpg"; } return "https://picsum.photos/{$width}/{$height}.jpg"; } @@ -881,7 +911,7 @@ protected function getRelatedContent(int $num = 5, bool $is_featured = FALSE): a for ($i = 0; $i < $num; $i++) { $elements[] = call_user_func( [$this, $func], - $this->buildImage($this->getPlaceholderImage(300, 200, "card_image_$i", 'seed')), + $this->buildImage($this->getPlaceholderImage(300, 200, "card_image_$i", IdTypeEnum::Seed)), $this->getRandomTitle(), Url::fromRoute(''), $this->buildProcessedText('Decorate one package of cauliflower in six teaspoons of plain vinegar. Try flavoring the crême fraîche gingers with clammy rum and fish sauce, simmered.'), diff --git a/web/modules/custom/server_style_guide/src/StreamWrapper/StyleGuideStream.php b/web/modules/custom/server_style_guide/src/StreamWrapper/StyleGuideStream.php new file mode 100644 index 000000000..652bd5468 --- /dev/null +++ b/web/modules/custom/server_style_guide/src/StreamWrapper/StyleGuideStream.php @@ -0,0 +1,56 @@ +t('Style guide module files'); + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->t('Read-only image files bundled with the server_style_guide module.'); + } + + /** + * {@inheritdoc} + */ + public function getDirectoryPath(): string { + // Two levels up from src/StreamWrapper/ lands at the module root. + return dirname(__DIR__, 2) . '/images'; + } + + /** + * {@inheritdoc} + */ + public function getExternalUrl(): string { + global $base_url; + $path = str_replace('\\', '/', $this->getTarget()); + $path = UrlHelper::encodePath($path); + $module_dir = dirname(__DIR__, 2); + $relative_path = substr($module_dir, strlen(DRUPAL_ROOT) + 1); + return "{$base_url}/{$relative_path}/images/{$path}"; + } + +} diff --git a/web/modules/custom/server_style_guide/src/ThemeTrait/Enum/IdTypeEnum.php b/web/modules/custom/server_style_guide/src/ThemeTrait/Enum/IdTypeEnum.php new file mode 100644 index 000000000..21410fbd7 --- /dev/null +++ b/web/modules/custom/server_style_guide/src/ThemeTrait/Enum/IdTypeEnum.php @@ -0,0 +1,13 @@ +