From 152c5d4e209a0b412bd996dfb46b7d6064ed58a7 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 10 Aug 2026 14:18:10 +1000 Subject: [PATCH 1/8] Served banner and card images through image styles as WebP. Banner backgrounds and featured images were resolved with no image style, so the original upload was served: the homepage hero alone was a 5.8MB 3840x2094 PNG, and 61 such files totalling 109MB were reachable across the site. The hero now resolves through a new 'banner_background' style and lands at 11KB. The 'civictheme_*' styles gain the 'image_convert' effect already used by 'large' and 'wide', so processed images ship as WebP too. 'social_share' is left alone for crawler compatibility. The banner background is painted by CSS and so is discovered late; it is now preloaded at high priority. --- config/default/csp.settings.yml | 3 - .../default/image.style.banner_background.yml | 21 +++ .../image.style.civictheme_campaign.yml | 6 + .../image.style.civictheme_event_card.yml | 6 + .../default/image.style.civictheme_medium.yml | 6 + ...image.style.civictheme_navigation_card.yml | 6 + .../image.style.civictheme_promo_card.yml | 6 + ...mage.style.civictheme_publication_card.yml | 6 + .../image.style.civictheme_slider_slide.yml | 6 + .../image.style.civictheme_subject_card.yml | 6 + config/default/seckit.settings.yml | 4 +- web/modules/custom/do_base/do_base.module | 68 +++++++ .../custom/do_base/do_base.services.yml | 5 + .../src/Twig/ImageDimensionsExtension.php | 162 ++++++++++++++++ .../includes/modules/settings.xmlsitemap.php | 13 ++ .../fonts/lexend/lexend-latin-ext.woff2 | Bin 0 -> 34548 bytes .../assets/fonts/lexend/lexend-latin.woff2 | Bin 0 -> 39692 bytes .../fonts/rubik/rubik-italic-latin-ext.woff2 | Bin 0 -> 21080 bytes .../fonts/rubik/rubik-italic-latin.woff2 | Bin 0 -> 36440 bytes .../assets/fonts/rubik/rubik-latin-ext.woff2 | Bin 0 -> 19288 bytes .../assets/fonts/rubik/rubik-latin.woff2 | Bin 0 -> 35324 bytes .../components/00-base/fonts/fonts.scss | 61 ++++++ .../01-atoms/image/image.component.yml | 35 ++++ .../components/01-atoms/image/image.twig | 40 ++++ .../pagination/pagination.component.yml | 146 +++++++++++++++ .../02-molecules/pagination/pagination.twig | 177 ++++++++++++++++++ .../mobile-navigation-trigger.component.yml | 28 +++ .../mobile-navigation-trigger.twig | 30 +++ .../03-organisms/promo/promo.component.yml | 70 +++++++ .../components/03-organisms/promo/promo.twig | 115 ++++++++++++ .../drevops/components/variables.base.scss | 22 +-- .../components/variables.components.scss | 2 - web/themes/custom/drevops/drevops.theme | 7 + web/themes/custom/drevops/includes/banner.inc | 28 +++ web/themes/custom/drevops/includes/page.inc | 29 +++ 35 files changed, 1095 insertions(+), 19 deletions(-) create mode 100644 config/default/image.style.banner_background.yml create mode 100644 web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php create mode 100644 web/sites/default/includes/modules/settings.xmlsitemap.php create mode 100644 web/themes/custom/drevops/assets/fonts/lexend/lexend-latin-ext.woff2 create mode 100644 web/themes/custom/drevops/assets/fonts/lexend/lexend-latin.woff2 create mode 100644 web/themes/custom/drevops/assets/fonts/rubik/rubik-italic-latin-ext.woff2 create mode 100644 web/themes/custom/drevops/assets/fonts/rubik/rubik-italic-latin.woff2 create mode 100644 web/themes/custom/drevops/assets/fonts/rubik/rubik-latin-ext.woff2 create mode 100644 web/themes/custom/drevops/assets/fonts/rubik/rubik-latin.woff2 create mode 100644 web/themes/custom/drevops/components/00-base/fonts/fonts.scss create mode 100644 web/themes/custom/drevops/components/01-atoms/image/image.component.yml create mode 100644 web/themes/custom/drevops/components/01-atoms/image/image.twig create mode 100644 web/themes/custom/drevops/components/02-molecules/pagination/pagination.component.yml create mode 100644 web/themes/custom/drevops/components/02-molecules/pagination/pagination.twig create mode 100644 web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.component.yml create mode 100644 web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.twig create mode 100644 web/themes/custom/drevops/components/03-organisms/promo/promo.component.yml create mode 100644 web/themes/custom/drevops/components/03-organisms/promo/promo.twig diff --git a/config/default/csp.settings.yml b/config/default/csp.settings.yml index 6e8cd5dc..a82fa1c6 100644 --- a/config/default/csp.settings.yml +++ b/config/default/csp.settings.yml @@ -27,7 +27,6 @@ enforce: - unsafe-inline sources: - 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/' - - 'https://fonts.googleapis.com/' - 'https://cdn.jsdelivr.net/gh/cferdinandi/tabby@12.0.3/dist/css/tabby-ui.min.css' - 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.12/codemirror.css' - 'https://unpkg.com/tippy.js@6.3.7/dist/tippy.css' @@ -48,8 +47,6 @@ enforce: base: none font-src: base: self - sources: - - 'https://fonts.gstatic.com' connect-src: base: self sources: diff --git a/config/default/image.style.banner_background.yml b/config/default/image.style.banner_background.yml new file mode 100644 index 00000000..b9dd095d --- /dev/null +++ b/config/default/image.style.banner_background.yml @@ -0,0 +1,21 @@ +uuid: 199c29c4-f94f-463c-9c3d-34693e08c00f +langcode: en +status: true +dependencies: { } +name: banner_background +label: 'Banner background (1920 wide, WebP)' +effects: + ebbff644-9a41-4bbb-8aae-5a9e75fc60f9: + uuid: ebbff644-9a41-4bbb-8aae-5a9e75fc60f9 + id: image_scale + weight: 1 + data: + width: 1920 + height: null + upscale: false + a4de6937-9de6-4ef4-a664-eaf57d7bd23c: + uuid: a4de6937-9de6-4ef4-a664-eaf57d7bd23c + id: image_convert + weight: 2 + data: + extension: webp diff --git a/config/default/image.style.civictheme_campaign.yml b/config/default/image.style.civictheme_campaign.yml index b54382e0..5a70b4a4 100644 --- a/config/default/image.style.civictheme_campaign.yml +++ b/config/default/image.style.civictheme_campaign.yml @@ -17,3 +17,9 @@ effects: width: 600 height: 600 crop_type: focal_point + 73cdd7e6-446a-49e9-8d76-4f00844e8565: + uuid: 73cdd7e6-446a-49e9-8d76-4f00844e8565 + id: image_convert + weight: 3 + data: + extension: webp diff --git a/config/default/image.style.civictheme_event_card.yml b/config/default/image.style.civictheme_event_card.yml index b6a8f814..222ac504 100644 --- a/config/default/image.style.civictheme_event_card.yml +++ b/config/default/image.style.civictheme_event_card.yml @@ -17,3 +17,9 @@ effects: width: 600 height: 600 crop_type: focal_point + 35a011ef-3bec-4c38-8df8-41d5ecb4ec61: + uuid: 35a011ef-3bec-4c38-8df8-41d5ecb4ec61 + id: image_convert + weight: 3 + data: + extension: webp diff --git a/config/default/image.style.civictheme_medium.yml b/config/default/image.style.civictheme_medium.yml index 67e8014b..28855327 100644 --- a/config/default/image.style.civictheme_medium.yml +++ b/config/default/image.style.civictheme_medium.yml @@ -17,3 +17,9 @@ effects: width: 220 height: 220 crop_type: focal_point + 6aac0b1d-d05e-4dbe-9eb7-1c6b8cc1391b: + uuid: 6aac0b1d-d05e-4dbe-9eb7-1c6b8cc1391b + id: image_convert + weight: 3 + data: + extension: webp diff --git a/config/default/image.style.civictheme_navigation_card.yml b/config/default/image.style.civictheme_navigation_card.yml index f1ee4c91..18d26e77 100644 --- a/config/default/image.style.civictheme_navigation_card.yml +++ b/config/default/image.style.civictheme_navigation_card.yml @@ -17,3 +17,9 @@ effects: width: 600 height: 600 crop_type: focal_point + ca8eb0c2-63fc-40b1-bcd9-3ea02c99a0f2: + uuid: ca8eb0c2-63fc-40b1-bcd9-3ea02c99a0f2 + id: image_convert + weight: 3 + data: + extension: webp diff --git a/config/default/image.style.civictheme_promo_card.yml b/config/default/image.style.civictheme_promo_card.yml index b8fed98e..7d6177d6 100644 --- a/config/default/image.style.civictheme_promo_card.yml +++ b/config/default/image.style.civictheme_promo_card.yml @@ -17,3 +17,9 @@ effects: width: 600 height: 600 crop_type: focal_point + 2c66c544-d990-474c-8918-9d21e217b258: + uuid: 2c66c544-d990-474c-8918-9d21e217b258 + id: image_convert + weight: 3 + data: + extension: webp diff --git a/config/default/image.style.civictheme_publication_card.yml b/config/default/image.style.civictheme_publication_card.yml index e4c01d70..b78b1200 100644 --- a/config/default/image.style.civictheme_publication_card.yml +++ b/config/default/image.style.civictheme_publication_card.yml @@ -17,3 +17,9 @@ effects: width: 600 height: 600 crop_type: focal_point + 83c1bf53-447c-408d-8d01-352705f4b064: + uuid: 83c1bf53-447c-408d-8d01-352705f4b064 + id: image_convert + weight: 3 + data: + extension: webp diff --git a/config/default/image.style.civictheme_slider_slide.yml b/config/default/image.style.civictheme_slider_slide.yml index 32ca5613..b8ac2e93 100644 --- a/config/default/image.style.civictheme_slider_slide.yml +++ b/config/default/image.style.civictheme_slider_slide.yml @@ -17,3 +17,9 @@ effects: width: 600 height: 600 crop_type: focal_point + a0941e41-8d54-47b1-b53f-1df40d9fded3: + uuid: a0941e41-8d54-47b1-b53f-1df40d9fded3 + id: image_convert + weight: 3 + data: + extension: webp diff --git a/config/default/image.style.civictheme_subject_card.yml b/config/default/image.style.civictheme_subject_card.yml index 527ee967..ada9fce0 100644 --- a/config/default/image.style.civictheme_subject_card.yml +++ b/config/default/image.style.civictheme_subject_card.yml @@ -17,3 +17,9 @@ effects: width: 600 height: 600 crop_type: focal_point + b361ccb1-d7c8-4af4-92fc-0ef29face70f: + uuid: b361ccb1-d7c8-4af4-92fc-0ef29face70f + id: image_convert + weight: 3 + data: + extension: webp diff --git a/config/default/seckit.settings.yml b/config/default/seckit.settings.yml index b01d61b1..9395eb5c 100644 --- a/config/default/seckit.settings.yml +++ b/config/default/seckit.settings.yml @@ -8,13 +8,13 @@ seckit_xss: default-src: "'self'" script-src: "'self' https://www.googletagmanager.com https://www.gstatic.com https://www.recaptcha.net https://www.google.com https://cdnjs.cloudflare.com https://cdn.jsdelivr.net/gh/cferdinandi/tabby@12.0.3/dist/js/tabby.min.js https://unpkg.com/@popperjs/core@2.11.6/dist/umd/popper.js https://unpkg.com/tippy.js@6.3.7/dist/tippy.umd.js" object-src: "'none'" - style-src: "'self' https://cdnjs.cloudflare.com/ajax/libs/highlight.js/ 'unsafe-inline' https://fonts.googleapis.com/ https://cdn.jsdelivr.net/gh/cferdinandi/tabby@12.0.3/dist/css/tabby-ui.min.css https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.12/codemirror.css https://unpkg.com/tippy.js@6.3.7/dist/tippy.css https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" + style-src: "'self' https://cdnjs.cloudflare.com/ajax/libs/highlight.js/ 'unsafe-inline' https://cdn.jsdelivr.net/gh/cferdinandi/tabby@12.0.3/dist/css/tabby-ui.min.css https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.12/codemirror.css https://unpkg.com/tippy.js@6.3.7/dist/tippy.css https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" img-src: "'self' data:" media-src: "'self'" frame-src: "'self' https://www.youtube.com https://www.recaptcha.net https://www.google.com" frame-ancestors: "'none'" child-src: '' - font-src: "'self' https://fonts.gstatic.com" + font-src: "'self'" connect-src: "'self' https://www.googletagmanager.com https://www.google-analytics.com https://www.recaptcha.net https://www.google.com" report-uri: /report-csp-violation upgrade-req: true diff --git a/web/modules/custom/do_base/do_base.module b/web/modules/custom/do_base/do_base.module index cfd55278..91a9506b 100644 --- a/web/modules/custom/do_base/do_base.module +++ b/web/modules/custom/do_base/do_base.module @@ -8,7 +8,11 @@ declare(strict_types=1); use Drupal\csp\Csp; +use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Site\Settings; +use Drupal\file\FileInterface; +use Drupal\image\Entity\ImageStyle; +use Drupal\media\MediaInterface; /** * Implements hook_mail_alter(). @@ -28,6 +32,70 @@ function do_base_mail_alter(array &$message): void { function do_base_page_attachments(array &$attachments): void { _do_base_attach_preview_link_robots($attachments); _do_base_attach_csp_nonce($attachments); + _do_base_attach_banner_preload($attachments); +} + +/** + * Preloads the banner background image. + * + * The banner paints its background from CSS, so the browser cannot discover the + * file until the stylesheet has been fetched and parsed. + */ +function _do_base_attach_banner_preload(array &$attachments): void { + $url = _do_base_banner_background_url(); + + if ($url === NULL) { + return; + } + + $attachments['#attached']['html_head_link'][] = [ + [ + 'rel' => 'preload', + 'href' => $url, + 'as' => 'image', + 'fetchpriority' => 'high', + ], + ]; +} + +/** + * Resolves the styled URL of the current node's banner background. + * + * @return string|null + * The URL, or NULL when there is no node, no background, or the file cannot + * be processed into a derivative. + */ +function _do_base_banner_background_url(): ?string { + $route_match = \Drupal::routeMatch(); + $node = $route_match->getParameter('node_revision') ?: $route_match->getParameter('node'); + + if (!$node instanceof FieldableEntityInterface || !$node->hasField('field_c_n_banner_background')) { + return NULL; + } + + $media = $node->get('field_c_n_banner_background')->entity; + if (!$media instanceof MediaInterface) { + return NULL; + } + + $source_field = $media->getSource()->getConfiguration()['source_field'] ?? NULL; + if (empty($source_field) || !$media->hasField($source_field)) { + return NULL; + } + + $file = $media->get($source_field)->entity; + if (!$file instanceof FileInterface) { + return NULL; + } + + $style = ImageStyle::load('banner_background'); + // A vector has no derivative, so the stylesheet requests the original and a + // preload of anything else would fetch the file twice. + if (!$style instanceof ImageStyle || !$style->supportsUri($file->getFileUri())) { + return NULL; + } + + return $style->buildUrl($file->getFileUri()); } /** diff --git a/web/modules/custom/do_base/do_base.services.yml b/web/modules/custom/do_base/do_base.services.yml index 19076cfb..24995679 100644 --- a/web/modules/custom/do_base/do_base.services.yml +++ b/web/modules/custom/do_base/do_base.services.yml @@ -4,6 +4,11 @@ services: arguments: ['@theme.manager'] tags: - { name: twig.extension } + do_base.twig.image_dimensions: + class: Drupal\do_base\Twig\ImageDimensionsExtension + arguments: ['@image.factory', '@stream_wrapper_manager', '@entity_type.manager', '%app.root%'] + tags: + - { name: twig.extension } do_base.theme_color_subscriber: class: Drupal\do_base\EventSubscriber\ThemeColorSubscriber arguments: ['@class_resolver', '@theme_handler'] diff --git a/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php b/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php new file mode 100644 index 00000000..212f76df --- /dev/null +++ b/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php @@ -0,0 +1,162 @@ +streamWrapperManager->getViaScheme('public')?->getDirectoryPath(); + + if (!empty($public_path) && str_starts_with($path, $public_path . '/')) { + return $this->managedFile(urldecode(substr($path, strlen($public_path) + 1))); + } + + return $this->vector($path); + } + + /** + * Resolves dimensions for a file in the public files directory. + * + * Dimensions are calculated from the source file and the style's own + * transform rather than measured on the derivative, so they are correct even + * on the request that generates that derivative for the first time. + * + * @param string $relative + * Path relative to the public files directory. + * + * @return array + * Associative array of 'width' and 'height', or empty. + */ + protected function managedFile(string $relative): array { + $style = NULL; + + if (preg_match('~^styles/([^/]+)/[^/]+/(.+)$~', $relative, $matches) === 1) { + $style = $this->entityTypeManager->getStorage('image_style')->load($matches[1]); + $relative = $matches[2]; + } + + // A convert effect appends its own extension to the source file name, so a + // derivative path is not always a source path. + $candidates = [$relative]; + $trimmed = preg_replace('~\.[a-z0-9]+$~i', '', $relative); + if (!empty($trimmed) && $trimmed !== $relative) { + $candidates[] = $trimmed; + } + + foreach ($candidates as $candidate) { + $uri = 'public://' . $candidate; + $image = $this->imageFactory->get($uri); + + if (!$image->isValid()) { + continue; + } + + $dimensions = ['width' => $image->getWidth(), 'height' => $image->getHeight()]; + + if ($style instanceof ImageStyleInterface) { + $style->transformDimensions($dimensions, $uri); + } + + if (empty($dimensions['width']) || empty($dimensions['height'])) { + return []; + } + + return $dimensions; + } + + return []; + } + + /** + * Resolves dimensions declared inside an SVG shipped with an extension. + * + * No image toolkit can measure a vector, so the ratio is read from the + * markup. Only the ratio matters here: the rendered size comes from CSS, and + * the attributes exist so the browser can reserve the right shape. + * + * @param string $path + * Path relative to the web root. + * + * @return array + * Associative array of 'width' and 'height', or empty. + */ + protected function vector(string $path): array { + if (!str_ends_with(strtolower($path), '.svg')) { + return []; + } + + $file = $this->appRoot . '/' . $path; + if (!is_file($file) || !is_readable($file)) { + return []; + } + + $markup = file_get_contents($file, FALSE, NULL, 0, 2048); + if ($markup === FALSE) { + return []; + } + + if (preg_match('~viewBox\s*=\s*["\']\s*[\d.+-]+[,\s]+[\d.+-]+[,\s]+([\d.]+)[,\s]+([\d.]+)~i', $markup, $matches) !== 1) { + return []; + } + + $width = (int) round((float) $matches[1]); + $height = (int) round((float) $matches[2]); + + if ($width <= 0 || $height <= 0) { + return []; + } + + return ['width' => $width, 'height' => $height]; + } + +} diff --git a/web/sites/default/includes/modules/settings.xmlsitemap.php b/web/sites/default/includes/modules/settings.xmlsitemap.php new file mode 100644 index 00000000..6f61c2e0 --- /dev/null +++ b/web/sites/default/includes/modules/settings.xmlsitemap.php @@ -0,0 +1,13 @@ +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 z zR0yL~VOWL1S>y&1{TxT8n~I>cQd(iLipz!o#>WOQphXA=Zum$*MDrrooQN`(2vkrt zfd(|A=)f_E0Kz>gps5!F3{_%+HpRvATOl^+ilvIjlNwFdIQX=eI_+-#_2I(-Ja+AH zsA@~eW4Lq$r<*Z`0qjQ+A+F=GxaKE>z#d7uVjR>@OE-jrV%b*0(300eAJ=L+n6tbW zW!<-)s&K&=*1@IkPr3C!Ja&r}n;@xz|j>MB2vA*@mBBh4&IKH%X`J=^0mF6We zZvC|xg$#mpKWb!dtLU1-?GzW6!Zq?NuUehQ?XjU6ylzGbDGW;(z#~D%NgO@cLaWy5 z&$e9#qp=NN2Ma=K=gh2sq^sO?1nml7o)hT%9JmT>O!G#BNjYz>bcnD*io1wEIc2MV zL&-}4^Yu684AZh5x7FzJx~zbEyz!O$x@x~4MwM#V5;%ASL?mPsR5bMJoj9Nd6AQZx z2Nw^&1_2=vF-d2xA|nUYq^Lz%n~Iu-mX4l*v0Fh*b(z(&u(Gk|z>&z(l-!)TSjLqb zcOE<~=Ve7}h08Ubmg1$Mz_d+gV&6CzZYa1rU`M2Qw-z1Z|7inCF? zO%iOD=s#O*CCO+Osbndc&1;`D=`zU3Wmc=dOP-?0B}cAp^5iS9y%!bc?islM=uDoF zLc?_4@UM|dl_^(YkG=M(wBLdJJ@he$99HE>0o7{Msw>!_-)PXNNwXHMj%q99nB#?= z&|XA`PF=d4q;#ski|Q%nv|bxFm6TOf)oc}aNkdah8>FMFrw=yhC3g*>uQ+I=eY!U2`TWIr0+9rfDO4Jr!DO*HTpnK_6sf9-B~o>nhNhObj;@}*fuWJHiK$sk zoXXs?YgVkXb8vEjxp{c`_yq)oghfQf#MMct*Pv08X2nCY3Wps8q-WmITsX#vJzTQx zrxtLZBtFijydBOyNhbaol>%CdNcVT0_Zze3-;2V*@1N5S=NXC({qZ-&g)ToN{HqlT zFPJmoJ-Pjt7pVxyiMbiU>jp*H+%pd#U61mZZR@*u4Lx1+Qj~VYA03ZsOQfGCWg&$~ zSyG9n%KR=1a(_-39~DLQsN8FXUC#f|TeU{2+QVUbayvJBsY=DF6ho{E(_s*)EsBS; z9?$^SJwWdWq z1@7pj;InNY_hJuMztSm}u0v&d7`wC=jqxOkJJ~(b_V*TjBPT8D>~cr3F`=hKw6|dH zu}CP4-3cyl=r0#taoKAhaPiNi6T9Fr*>dIoc^(6Wax##i?##~4*=^Y{)LSU~q|c$A zQig-b%Wx)oEm_4K&kEf<8Du4&u)oIW1#sRn}j!|Pz6X!j0hb-p}AGHrp^=ARR%81bF~czun951 zvf3NWD1hj;0>W}&4RqU(tXt)+H_^kek7|?+%u#(I8qT9}Gp&G$U?W!{fvM9(NPkTKcaU?1Jr_TfJHh+{m%5wDQ$clb*D+Lv3tH$A|PKaXXL>f89t z9!djR>5!7aZ=D4s!i@9j`TO@T#<+Zlep^=KXtBQx zl@kbA%5TcRb%Z5}nV&_C5}`;n-ju!!M4Kv@fI3%t@EFkwe;A5~<8>P!O?D(gq_h12 z^8qU~VmYbBgPu^GsE(s74r(-4NzCzqX2qs)G>d1=S>MYn5bE9d-MwIvw~>{Iy@#8$Jt|ZCJ6ul09LV8y#N3J literal 0 HcmV?d00001 diff --git a/web/themes/custom/drevops/assets/fonts/lexend/lexend-latin.woff2 b/web/themes/custom/drevops/assets/fonts/lexend/lexend-latin.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..0968c152f1c0d617a90bd843fa3d510c336af085 GIT binary patch literal 39692 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 literal 0 HcmV?d00001 diff --git a/web/themes/custom/drevops/assets/fonts/rubik/rubik-italic-latin-ext.woff2 b/web/themes/custom/drevops/assets/fonts/rubik/rubik-italic-latin-ext.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..89c79bc5cb2c892b91ec72c825bec03a11bc1740 GIT binary patch literal 21080 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 aHs+U2Nk1Zg6_sj@lEgJcm%oz+0000B^J~rk literal 0 HcmV?d00001 diff --git a/web/themes/custom/drevops/assets/fonts/rubik/rubik-latin-ext.woff2 b/web/themes/custom/drevops/assets/fonts/rubik/rubik-latin-ext.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..fad279ba452a129f24d4e4b4f372cb813b958f7b GIT binary patch literal 19288 zcmV)FK)=6tPew8T0RR91083Z^6aWAK0JN+C07~Ql0RR9100000000000000000000 z0000QgLfOs9vp=RKS)+VQiNnbO;$ltGX`KkQ&d4zfgC3)0E8YdToDKg`bgwF3xiMq zFzf&UHUcCAha3bT1%*lnj{qBWrWcrQ+Gy_t*$oiQuiw3@jgbgp<3NCUKb{SyVdDTy z^WHrB|Noq%GKMDACj|gR-9AV#5+!Tv4P&0Z6kqYc6^KL)-dH_hBv#{*xPoRB8n`Dt zJt}5K0i%REOXJa&2K}78ck(AJ$}-cj<&K?hb-_PK14RJ%BOw-bz>g;=^cA)Xj&wgdr&Pq5D-IZDRaM{y0 zFiwY!DzxUp@l04d2geSjPd!WpSdLZIJMcQ!H3Z&>HF4xW?#x2_cN=u5yEVLaf@_7 zia^~|74|ZpZ_^<_m88hx~ktRRu@HC zFu{~?9M_g*>L8`ZtsOVZywtg{;!q+J4a&F+-1}C-jieQ~@{-gfmg<#42h!h_C1c$5v6CtZW(dADJC z(LGq+Fbj(i5JE(F)MYkTU31%A_k3;^0<3@l$xHzV7XR9s+t@sbTB|c)R$F_~Emf+u zy5|R>kj;61Ab4iXd@Q4jx_*B1ze!Vx|iizkw)bS9g_Vm@QU zGUGT2Jibtzl#-TRATKIb>S2V?3z{ftmo;Bt$?k-t`uVBZ`!dd&I02F26e=aC>boNXe;*Xy|m zIfG@PA@ZP*&ix1`@`yq~$441+Z&v2>9ZYrG#Fm<79RQ3ez;Q$LPpe*pG&Ae}W^7sW zGdA{DVYUPInEf631S0zp`^euhzyJaV5;Vk@KmuRF4SjnlPQ_GMqCJdJ;XZPELlL== z8r)#UMt_AL~DIeZ}m{ubxI@ZQnL&yky=toBos^Q9o3OsU@+qy&NVEWm+*O<632hyjkro2 z1E=Fu{0v{iCrxSjmTnx2*@@GH9m4k8*3&`*1H*^>&L{ku_j!TSFi#L=*T=G%29{7w zDJ2w=#jRW;io)b8clZZRJ~jg~0AOeOzke~?Hr<>qu~(HfaGqmgwChkC+nW)JncJ(pDjuwxjQmteF;6@*6cpIE zw^!~Tju{UA07PvTE5^q>@#nz)|7>hbX~_j#vTFk5>Gx;PL@zjs9n-^i^6NOI(l}R- z#Ov^mX8&j{0;1T{)>RDQYq1wZKe6};go8)j3}@1$O)#=ri+Rla6IDW&<@f`RVX5E} z-3-7$75Mp@Fc+@+=1@*F(I!P&Ag3|Jm>P#t24&>y{eT4g#6k5oz4+zU&lsYHi{Ch*$yG+lQhDGXHQn>jgFp~ zh;o^-I2B0dXZ@mF)NkM)J34Ayf7*{^O&as4jbhQZzf;9|(&^S2-NR3!P>XHj%}IqP zCC7Wb%bw^!m+~iXhn7>~O@HQ>t)tz?%R*GDGAUPbzl0^(^Ght@^KPH=1(`Cx z4^C=8`=gy~wy2p##&}KTm919{Mb`J0;iuSU77gf}JFjSb?jsXh^H@(!G0i6J+)+tQ z_Pc6C#QrQ(_i&%rw`nLYV+PHT{%GS#R3UuxzI0 z0PO;?=X%fE4%tbC;AxUPZ$e}<(EqNF$`HN-<){U4kZaiIKg~4C^XC@6$<7y7Uj%M6 zPlIRHl;5;MVqVWR_4M5HVUr?dIKC`R@)|2@!S;M;M980Im*L_&Uw)=M*w(Y~?|!V! zT%$5Tz$S>0h?o=%fx_Svlt?OS6s>wX21XWEHV!m~8_R>^6%Z7{YY-Kakd%^ zm<^Z+7!K$K zXa%SZs0ho0Q+#O#fa8(#e|;};vD5b6y$L7vxDrXdL+0nRho00cMy?7w}V1h#XeCvppc?bD%C!!hF0@$VY>8al?RaO{5K zoe{pcr@;Lsazfp@i?`5`0j$N=Y7&sIMpnL4E`2N^#kl}V%dm1oW`1aE2wpPszY@jD z>f7g!sT)N{lM{0DN$)%uO_AP{8)GlMD_Q5E?DBoUq&gm2Pg7x^-Jj0~>;H6qLo)Y# zw(+#*$m?`u!qh5GA7{GFRW`jWq~%sR#1!_{b&~rbakP|+m)}A!7`m7WVCj0tk)51) z_w;9<))3B)QJ#n;c*hRU`sd^;b%fyCYRNo>a;U?PZ(#`6ci5E_JnN^{$JUi>Q1AJ0 zU2_w=8HJ5GwSysMlvR1*yC^Rm4`7bNX$eehn9vZ%Ez9MFHtJ}Z<4?URtwx?r);ynP z)HCKA%%wQ}NnUY596OY9%nvw)*-g@gRT%5@CMDO0qOMgcP6>jEeND}aX+BW;sGoyD zG5nLI>6oH6t<^!zNnf|HoIyYL=>g^x`I**pkVg(_6hO=x!m4c2UjeMO9e%f|Ze z{F7qQLc`@2$B;zJg^HPM4~0+8t@Iw2KpG1+4nM_*dZ&o#~a$Drt<^XszE0H~ag760+RFG)1Qa_L=3v-0~`n z{dpyuuxM&U{r$K%IcE%Jg+k3Qcyyx&$qcl@?Vn+4=;Ee;Iv_2*kK0F1w?-a6)IduvnwE@aLBk%Qa>>HslPbzm3?oE$5GP9(mK^!m zq;^UqQ;bJNOKi72Qt9ZWD^o5@r7AfLYUQa{Ps*s-P9|*>I&@O&)^C>q19VWR{RWLH zF>XqQBaSjS?xb3PBSlz+Wr&1m2!=pNhF6${M_7l?a0~OW3E$x!GNB*xp%9889crNz znxP$rp&Cvhmmr2f9hj7q4h$oLlgs^pk`Wc=hmu5#&xDQ0PZ}mE6e2`P!(d=CU}D5k zr7;LLZ$}xn3nU2>BrNIbzdBvSDNuZCjS!nJVlXs_Rgt5J9>_3p^N}HeB1#j4Bq^Hv z4T%kc9b~R%GlhXs&v=+j+5_5@-L_|srplERG2%4I)1gCpa=FCTPoU^N;{z1Q!&?(2K=aZcXL=gpp5L*4y)E%BxF)q<>^ zaev;Z*UEk5DRezE8fG$!*`GXD9wQ}!so@FwFPJuCy1O8}BE^7(EMjrFB>Z?ntHDth zR4YgY-ApwjKOjraZK@_xe~?ZFKWtXjk$oia?L1Hc45NATPc{*EvXiY)aU4t|rpub- zAXv*fHpr%9cjp=*7kI7Y^_mZnCNJ8lvOy$Y=L#z#RX~d&s_JR#1`S$wH`>u?kE_Et ziS4I^1L(DKeBUY%oX$X6L)217y&6dyKqE~wt4WKtfL7YH!(rA=+_sy4F6mi!nD6bi z5A=Vs1?YYQ@F%fDGf;OB=(ZuO3^T&0I}W__CYWT(JpzK=9CeQa|DY3`jHd4soCv74 z(Hf5=!UPG)Agwf^#E21F5Nli9!=vqgne{58NWM8+2qDhrg(IHQ3^nrK#2Y+AIHw2ic5WN)(#abXX6d)xlj%wc7i5k}o3 zKpxk6P-7!M&6z}B`q7H|RM1AJnHvuSfB7|%LQ&F z9()9@2=FK|Nn%LiYN(}-`W{erlO|b;whLsS?c-?ke+KvnJctvQxCK|#gIemSUkxJ|kusu=`tPy;iUVqG0A2knzm4e?q(anQpCw<)Rnlb2rg#u% zqM5EfkA0Jl6*L4*rOE@F%jge1B4GzvZcg*;ja>4`UnXtSxp4-S4O9+_P*5DHyvu+F z?d^Bh5lnkVrMhF?p3v3myh>@`supOFq1PHmEp^nZaaD>`qZCD{M|CPn=?5m$x)%{+66bQ;ii-yyfh+2LSi~f4wNy=cX}*s_!1#z- zmt=z47zA;rWXKk+ox64Fk<>B@G1UN!1B(NWZbtodBN6+Ex;f-nqgDlJj~Lz=ndhdNvhuB*=~YC#>So z@+Ks5ABh}d)HB3rX5SLyi@;}Dt@7|;+}jMpf9}dEkc$SO!9=cb`1pDM-62gh1I2)ff``viLqTE(8qM^=2zf23rKo}(75v`$$hXBR++t(8NnbuTF~U#+bB z4_YAv5lkeDSqhca(AZ2&5v!q<>C-QHwEIk3rF?TTy89*QDiSrB!W~L_gllH5@@9xe7~PWYIt+GBU&MoYDyY!acJe-(^C_?PrAuu z<4@4=Ach{-GL(^Gu+;*F&3N|)RR}P({QB z)!K?)IV?+Uy@+F7X{L-X()8Myu+m1FX|zN{2QF6aAmeSqe^P@+jJxe2yGOqC!khd9 z0iZlUaQmOgHAG|C0<(?HiBCx6^7sOwNSuT6tE4X8WOs!6bm;|6jYS0_PB~&xM9c0Iy>1 zUx7bxU?IB~P#hMWoJ)xElc6-stWT*H0eBnxzY)P9(gmWRVc<$9g#eHd3cvw|X)~~U z0RoWIuYK3EeszDm8*s&|pj#d%(guYALEVd?2L*w9N6wug`*nnP+#mVeh}Ex|!z#~N zoJJ$~);d_^@2`)@f&7T*EKrVVtl&vysZ=Hu#{Gmh2p8fSoD2^UO0@Q!?XTK923sum zX4A7d*@A3|3$9@A4u%I8Yx@NaM11g*_+ZR$nFr2Hxe@Eky2TLwT z261K>S4MDSBo~HrXEYDSAW-lmvq%vy#qi{OsrgXxr{zZ@$R2@qi=Y>#1d&d-144z^ zkEC3bN>#`VC~7THW2rjP>QNc3&}6wr4OVKlR;$%a)@ZR_hmAUIV76H|x;|U=+M);3 zA+ZJ|7{z9_-Jp0QScY&6(wvm)1PdpIplK7MUmTRc6s~c6lad^D!8r(! z4ugntB2?N01=m!`r6VM8oDnvIgI@`cI;}bV(w;#9aK(XwVbs#cHX)?}@C5)p57+@R z?f}tufIwm3egwc_iES_IYKh^v&PK6%r!@>IDy28O!V0XvqUk_fb%cd-E|}h9a-=DG z4P}$X=vq~CX}0=o5{p8v;&eJ}N5lEG;Uu&6@g^j^P zNe*wGPFJIJAnHhcr$*og!er8wxCy1~nuyzEg+i}4U|3#5x%gpBId_zX>98FIDL|e^ zlO-hcw@A?~KsCX(1tDO1;!Ki3=~`C8#Ux|gVuZ9ZPhaT(486B7KK1S%A`Sm?kQICS z5jtiR?beXEh&n;qyF(-$$=Ns*#4+X=kgk$|r%Af&hL_;+g8?BBRQpj=5lWyKWq!6~ zg__6~C6f>WauE|&<=%=GGseP-wIfdt4bLMVD?~hW#6epfyxk6og@M!zWAbL0mHD*>{}IXOx&7DqOz z?BUl$L@6F~lNR}4k#^K)^;9=$EkrrhU7$qMeMd}4!st>k;h3Iq{&=t{I^l-9@&oo3 zgXXB%bCU{e4VGAjCDjZxsH$yNBiabqkhwoq8OkB6P`y3_7o}Ic+HB7-X$)hUb@XyG zsZRDE541B$$~fTEqmZy|zyWF4J%{8y!^92?ehX2NquS6elDrhS-jv-dHG?V2?2dsU z@}{aULD`f@DDjpBt(~5@m`TnTmGEd|M2BBG4LPyd*P>{!NrVZvUu_+Y+eSA&I5qLto$V$yEh)dqwKnDj^QA~~ z(1JfPIObcZipvun-?6t_(NW>{gg)RD4fQc*k9*8JOZQ7%g$c_CO^Q|?w^1p{uf<24 zgT*pl`BV=s#u;L7<^-jT zmF`4`V)d(#**rfNU?X|zTt~s-z3fyTH`)QkROu8!Hl=vJbBf4}VH8e+SRN3JJPhKE zpsfujJKnqSeL&n*Un;bI0TlVCV&%xI^_!_h7(11)w94hBAY!Oa@h5HlsG3}e<(Lv# zTNn}X&JsjEChz+naJysg5K-0akhj1lAIGJfy%eNzDK9gF@uzw#UF>6Oa+ze~$}4PW zo-+kEi@9x=iEZCVi()M?yYti^pd!|&Ko=_0~u<28oT0`ld_erCDV=P;E$c3M)5^my>+%YjGuxm8Vy z8BHsCc~Z_)=tAupY9I{H*(|++2{Q36Zq>{vYErdg@^Qk^`8lDju_zo19Gkae=oA`D z4AJ{}Q7}34xK7Mrb2~Sw?G*cmhi{Cm1nMUb+nAu0zS_`AE`yLW&U&5(RmNDcn&YJi zuviWj@2*7!0yHM4fB55R5-IAF~#rHu1nV@*k?Bc}KwJFAHy_Dbj3`bFK z)T=3WDLJv6W2}M%7uKl*?XY&;RpiB-36@H+!INTv`db8kXyqi37A+q`LP80*0Mj=X zW|A7#4AwF#&0U4Nr6}EF*;xR3+($`O>1vR8{%>=|-W)mtT&6lGDB@ z%I`0pr-483x8u6_u9GinsLKUw0Y|Dqb?Vc5{nc;O+tj7(RIs;BhAxYnVhMOgx-c#(9?SS;GBGAWZo>%5@ENn8WG(il@&@1(?1QV z;I|>N3RR-&k33j`)R2qO8uHn^J?YRI(2o@{!ANlR%Eau4lVg=pmYD=PWnNAuSU7dg zn!CWsyNAm*wFGkNvM#RHBdl8z?kmK7+9tZoUmvgq__Av6xk<)&Vf9DzBG13Nz+AY0 zMPq8UuoIhs3CpQfD;ulDsm%TZF!U^091<;FG<7IB#_^*q z;Rlg%1V?Mg=V%QbtYp@%X)+a*osMmeXYOKf%4EpD&0l!pz|7&Tu;lSH(|`xVa+f%P z+zkR8>Oj8A;PA4MJCTFCcxO4fdS2rJn37My=Z+JJW*Qbsgrm(G@|4?FFbEA+sm37P zp@Q#6RLFf$*k3mI;H51~V;3bF zBIh`bz~--n(CW2C)i7(>N-Nk)sJ7BM1~c!>N3^HHG(B!cd@aHka0wV z>{S#889*sZNxPbu9(~wEU&<54R|;*{H-1ffj?02JxOaIXy-qlWl`-LHe%*>>x!i7l z<2u2pp==P0W!5cE^d$Qi%@(aN6bypS$kahD9vkF(S=fmcFxRnowpknheQwG0S(UEI zCE{j9WM+@Ri2sIOVec#PKTkB%YXg0y=H|ZAKn;vRyO)HM-A1SetC0Jo$$j09{IsD` ziurCbsf{XWMgnXx8s;mr{B6kr^A-Cs>Gi0p?pJ;HXs)eoES_O58=^~^HfpNhUx=nt zeTzB3NgjUZ+P#0bXtB5A3KD<0Vqwbf?YRZ=v_co!{2OJSUfkK2I z@YDV2g-gO^ww2s^syC%S@X!w`et{?6oyaruV_wTN_yJ}>i=dBGrvd_rXn#0&9g|~!CU@Ks z;>nj77=Lic5w{8F6fYaH^vUS#6o%sNlr9Ycv09mQxXj-i9T`Vd@<;7;KAofR(7{!* z&86Le+K)7lqJfGl*vJ+Zb`PL8sKfbOsyTA};dwZLT@T}}PZ#x}WQX}yV{j)@Llo^t z$^Xb>1?@FHwu|e@+O{ZoNH6cU4&4sEN=)A0S<9t8lt3UbQ;ZV&06scg9WS^|Fe zd~=fF<%C>gr+=ug!=?0lsC*g7P`BFv7s!_SLY^-9AT3AU zL52}Q&evJA+Fb3XrR(oNF|`Wa&9DsN*5UNx*JrLdq33H!bnsenN85}py5QtG4M2^S zrZ$9T3rcth7c_@vO>HRg9R|}?2s{Df$e#9=7LG3r_6Wz6O5xaGPl0dYTH5y@I6MK@ zozi6;U}&P^4i+_4J+8y`nrg6EaVIhr@0PzYbzO_?c5SV2YvV=UT7mEYF12+Q!?8pm zZ0t3os5zo>HXuVAdwkwDMXw0g;i3+GprxZxjkZ5r>>z&Aw2m zv!|p7(0GxzRJ1sYYdbV)#CwAaD}@1LC@d{k361klM}q$whQbR6gwXMG6ZR4 zyoGnid8hS<2LDUarPf@mq4b+rC=xu{tWmcVpRI6umm~>aV&TEW?y*};xNjrm*S6=l zw4^u4+H#OI*H)N@ygBe@urT-^v=rBw=D|zrg6_fIZ|MxZORA@d# zEY?4Wd8KP5aLhF)elOZw~DAot7e>i73QlNPVC*jp}O7>pe;8=HCP*0-$;i(B+AwyFe_lA_zpE!IfNv$Sk=#Iype`!+SCe+B? z>Y?-RJKt%(`52s}zi9FTdfE)=;*xW>Dm%V1XuPP|zB>>E$nOyuZu}G8z4&(!@X5JG zANzHX=ybHbi?~fb9 zBagjS{q$od(-BX%j^(=1V=Rr_FEze<`*L$KKj`;W!l7VsAb44ms>f4eQq@vVzT2^@ zow^QD!8OR2>|Pcwsoy{%eAkxxcHtj$z*Xsz^6h|*a;kH;qnBZa?%V2%jT8zk>ibG> zrzT|Y#3k3zYlmKg_N}xJyax2h8~yKk_Yb1zbF-e(u@WSyJdpi2e3&B+&DQA1DGHyJl8O!yFqC?2Ig25Ub7t$lZ@t-}@p9 z%9mE|3x+RUGk5)Y_1OABI9TfM%|gCcrMEObbm?;ljy!Yes;=LfuMN%#yy$nf+6nwU z3(2k5qDpAJcK2qY&tqWOM}C!8Lp4Y!v2T>y&qEY*y+A@f9N355F{IlrC$B|F^o7kU zX9v1kF1)l3@UsQ0{yyH?oy|w^*f|MkE@-NmhdI}IhfaQM^1XL*Wto=gnBS~pt z!QiTw5nxIjRvZ=DyS5pkR5znq>U~amXl=Wo_ir49YW;opek?_xkFQxJ9`CA?vb?6CbXzu6icJ#uj5T})7$~xzn<+83rB~Z z%6LXkIEz_V1lxxr5BA2e{#bAiBVx{w5S@Te8Y{+a{}Ow14PUC; z`$S)#z^bA&JV3`F-3C9+AJ8`%tB=XIcLPAGB; zlC0VGWR09G81GE+LVv1hWh?K`%Uq1LJ;wX1BG;ur(Qdk4K9IM1g!L4xCK{iZ&)%Xa zJuVK<-3ox$X)pJ&<|^l7#R)FN4P!$}=GW2S1yYvR)I-R7T>Aw8RiU>OuKNcT%d)Kv z6q5#CbN2;RUY`Q_=xJ@=ZBL-Fo+29AJVKVEtNaP#hR?&Z^xSSdtCc~&B5oMZ+iuP5 zwrz;RhZ)uA6v(GeYlnP94{ELxW6iMet&A9vv$TSuw3wzuO2s%+VXb}@OPhq8oVeS_ zsg)ChWD>_>|Jq*tH{fwi^Tpz1i@9N!R9e)oNSBO68F|iZ zl=}?xQd?XBe!`YSz(aF%Gt_{qj;fhj#_wF?G61dvN{sUHUomqd<2FT9=2tZ%} zeTt_5(3b$9y84>grUQ2T$u-(6CKD)TH5+)}7GT^l-WF^mQ`)qhv#WO3X0-qtt9TU% z)tHWHM)Uf|S9%*ftsn3{AM{B->1X|)Ap0x)^?pnoi0L>NSL1Gcu~{TCiCSWmI3>#^ z>m}PIhm}C3(jMss=?l^~q#sC6Y8XNwCDa2AL(`xepgW)kpeLZ`pg*94nx|tp3@70x zxE;P2z6!n(K4H9u%tCHO?nNF&o<&|p#i$IOf!>8agg%A7fWCq0v6a|HY$tXhb|v<% zjFcH<&9bSoxw2)lb+V^rFUn3tJMbVr4_}TyfWLu%h<}BDkN+XJ%KPM_@>}Ki${&>< zj=Kmy5hb!jE3t{#O*9jo#E--u#6iWVVuoUY;zq@{%BV80Y*VgLZc)}Mo0WFu0p-u6 zp0tx5GE64Px#UuEEqN|-b$^GPisJzm|y+Hl4`mCm1)2$iQOwz2^ zY}M3g{-gPy=4;JCilm%Wh8m#OQa4f;sh_AL{gcz%qUE)nhn61N+4Q!lxJlVZ-0ZGz zKRkMPZ}ZFM4=vO@OTqa7Bv=Mzb>3vuFEG^Awuxq-^QEOAaQSxx-MP2h>g#MLn~;(a z&^Vc!2zDp}VIn>UiS)s>KgN zs$+(YA-6j*lTYk2FffX!)Ln-I64$(=C%4m^jw~g=DR7EpC z_5Sr^hJ%?#LP2S{LSf!`>EMqsU()mTs#dkktPLzusJ-w1sz}Q*DbdF?@NnWEV(^?aO5%Zih@BYm853>vgueYIEnn zo?`#a&AfY``u^L&p{G>9`eYjqvmoF~Sok4g#8EZ6-%}HW0T0EBr*aZ4;DY}kIeKZg z{gesDOAmpk?XcNz@we-yWtn;yiRPd%{UunN)0vx>`z@R4H7JBwKcjuvdHlZ2@B$7h z4QAWWz~jerfw5}g^pY6o`J8uvo<3OT+T|Qv(J2eX00v?x?pe)Bg57zqlfqG0%>_;> zxHXlv2vP~x<>NK}MP8@X>(p9v5@_%)B5XOg=*aE&+a649vr=Lwg9|w(&N|i763BgJ?L!roFg-%U{^~;(ev!j(m6%M<3kJBp?JKF1oJ%Br6-7+QPU5z z$&+n@!?EL093wO5mB&@5KOs*uqD0cH$la}ch?2y1H{+e7qdN{!UN(ju$Qc}|0p~gB|9%tY`{EaRx7%1FufDX?*0R`{D3%cmr zlNVGx72q@wkTd2BPFdvjQQ!z;TN_F`VOR1C;`Zpsy3AKjs0B5n8yc6wV2K8ez=Tyf zg?deK!J`*&+CoSet(L>gy7JPSZ4FA{7CGCHRWz9p;ax=<5X0_a{dNsG-8qv~CR50# z;v%xj8ga*SZywB-DID_5LVoqtV5ZVENKz^(V|PFI(WatF_O$p7xhJ85zFl%R+DjKL zR|??Nn540tz?|fC+K}AF=5Xe`Vm=vl;9N{5g{&QmaxJrpHKiV2p}){UKF$$zBR8K2 zaTFE~3HL>gr9^E$v2;ih5JvPdeGaZ#3&6Yu^VlvPNoENMA{aeWSjYu5@Gd!7MPW27)+LEZ&!UamT1!ie zClIin3h+q4|73!uYc_YwbzQ?w$}rD$(Rz8?syBF?=6uGgVs*`8;jP-T;VHlv0(KR! z!po~7Z#gf5AcozP*qe-+`TvE`gZ_6$Srd>}*c01~9PwIB-lx_wTC%gZI+1g9p_A|a zXbu5|??XIzXjlo;&fF7NG&xp+MxL$$JA~chZBj^erJ2-7M^W>3W}Z3pZQQ6YjYv#8 z4fwAEb+t2TH3yUkNv}e27&uxW#I)i`1SZD7sBYRnKAr7&m=F%DwCzC9x_@6YrNF2U z0hh6@=}EPY6wHn;-|-5BK+PsFpdhQ+5CwbOdk3BNV{h-%Y*UZKN$hUu52^5JhsvRv zL#t_OfmX%E;RO3|JY@YrU|UP%Vr*X;QZR*8k(nXUE zqVm@XKCdqri!}r}w^2X%SS}n1hP)mdO=CUnF&;#@b$;NXr_T{P_RI}wX97B;hu9M)S6~upXk(~4+JQ0QV{iU z=!Y|Erj?RShBSXc8L@l=JpP4 zvYw9aoEptE#Fqs}e|;}=+Q$`z$|n4m!Eebn917~3JOJ!EC_0j7!+K~_LqtN$wOS&Z zbWS)Nz+vrH4oy0^Hh5+N|L;%(8QiRUf=q3*l66GIjf3R0p2PsJ_umWQ z)>=PO3A=}l8>$$6dV^5|Ci5h;-ootrv;J_Gy@$F)!he4ple@B5!k@-+1qX=&PAC3q z@39T7W|KkKqJ)U3N`;Udzw;spyc$PdFE20P1+a^7Q$*aIRwthn@W$~pgMc7c2+QcIRP9225$96-DbL-WFzTn zyGc>!0|AFk+t{jc)Nc)*F0H>XhR2cjwt{NyiBpYOTuuDLNvEk%WB3Em8!%VkFud#* zATUqDtk_?L)Gof~@5VO1w;|A3V9W(1SPF>vX2Ey)`9N}sXRqP7LGE6O_^wQotY*i( z^SKVKtSdFiRa!@P+`%^Vd7%E0s8J5L;y<}ej=75cRi|kuE|gWlmS5@9Cjx#6kr{V3 zb2XmT9w?WeQLjs{I-7q@U+Ai$h!Fo;88;|wrc4e492t`C;;f`&rZ;O}}c5f5>)_O~zkgZ_4>#9WZ=` z!x+N4Q;AX4*=bXM;Xgm06?P^_h!6=xyev8|T%F%tRD8hvbEuVF*xOqth5`v8z+h*H zUCx(DgW>wXn zOB?FsimHa1+Wjk==6g>eKgqiGKA%mQC!HWWn6ooWE5TI~>Vy#*B&onBK82*Tsu$Xg zn)%{pHVmQ3Z4vwLYOq+lskHRK#WuuL#(r>2m(0U6?3JSML4P1OBSuo#Voiuxjw6jIdJvr|!VoXoC zbbm-~K_}NP^~)>E5W>;?x3Fp5JBzF}A%?nq`g-FN`?v0boAml6}8~(W2xiqK1A_W5(7LWl>`v z_cb9fH`X6hN;O)knhr+eO)3q~?e=b%?E|0B=w8&e;7p-zq#bK)Y;7CvWDs>aK58{| zcqSgdL9Ma@MTqKYu$f^o*sOoREF=*)6g}CI49b7t_pDoR@501TRgpV5V3RoCBRBYC zM6B_NL_o7dx~|7PcC8Bg&G$F3?3w!dYG#|{2pezf&gPPcMkA*!xm>MdagYw!5!(|9 zxoRd9MY@hFy;_~Hju;$B9d|YG9&z?_bg6tl5W=XL5Lmz^rNWGbdu-0Pn0LEW{xy`) zzmOC=>_T8_5?3tCQG{uWGaIcN5AX-(;SV$VF0Yt{4i7Udiei+^4!hzH)PDKOw$A!W z14W4qrWhZ>4%dpb(%Jico0bFp1ATMfzLu{*yit3M{N&4OR6#y#G-_+j9VFPjC z3HpSZfsgCKAP`7|gc454&_D*(JwzL0*yS21)qAc1phrDp4!fn|qhw?iAhV=7CV=eb z$VG*$m%sh){`a(TjtxWz$jm$?L<>n^(1_=XK?LJq8VnV1ipJ_Oc4hIF{)Gpa+45^W z88$KtVWaU8Z04I`a+-~BsFMzt`KLt>pMjjkM7lCPffPCfx1KTMmHPcV0gXlt5HZhV z9dLYx`5x2j%`8>C#;-N)3J?X_JD_xFw#=8A_S6ZTO~AsdBo zq3qeGF>l|brl#lh=w;9iWhMwnVsKZKM`Egg(3r%q8tM9J$JVSuFl0NeNg|w#%{enN zbdA|L0%no({Jduv2Uq@V0!f{alT(5LDA#dlI+h}i6+4lC$k2x{E#$ENVC{ zsyeOEp_1Wz_>kjZpcYWTzc*1NeiEobWH6 zyyElFSX9!;l?+`G^nfT7QVdZ++(My4(`z#7k6h`}i6)&SC;sH4S2CVrpL5`oe6cHg z=7dbOsynq>`-YGiinoc860};U$!8uz*iv)yO(-Zd)};$Q?KQcZpLS*8FMx+NQN8(W zj6@4{#)56zM@b%89j%j;+HMRMRG}$it{~3X1dDoy-9}^gKhspSB4g}ioN%?w^$o{Q zw;Fogk3>ALpnh_`EbMZLA8M@-% ztG1L!v#i`WtpBA2(XW~)ar1sclqiQ=`JY@SGuo?Vr?HT{+u#RGtihcvfNG7Mk#^W9 z|G>-u-M~s_U#EJz#PFq4_ki*#|k_kP_wNWNER&eZn|^!ABA#{VLJ1g6~^ShR5S9EQPKsxLV_3yC}3_hVvxD z+2sZQciP~4qgpzAr-j1Z@V3$I9!Z2V{c4m9v|A79xp$w0CI9pHtvd%%O6dfpH3XZr zI&E^G4!I<~um4*__ryvAJc3lLB?v+>LuPB!tSI3UzY+paCw@|+(f$VW36hXcNgMwt z;!fPTS|vjhl^U|@%yg006N;&)S4TFRTm=S>3<0M>Os?LrCvpf>MYP#gS}^DAhY$nH zm(LUiO|Exk3oqy_F#^;1$I&e_#HBt4KAq-@QuVHB_~7EP*#0x8UQ9XG5Spj6u)#1f zaOAyMV_ii}%5}^J4m^&Y+4&@tWko{9EK|tT6eGrEI|Y07!L4qe0G4j5`nmGt;qvtM zqKcXWE5pzm%os+%jL9bx^pc&ny-iR77z^k0qZCSGy`ID(5!%B`-Lz4nd(0#I<@zZo zwKkt)`nuFojpe7&lVN)%@lw8QTc&9{25eR>1OtO$cXd5@_315Dn8hy?T z^+l&=NCM}3+v`nEM|z_eOomAC?=*9Si!iC6TrTVAe^m1w%CNaDD)wUUvi1WHi@Z_*<=RJ~xpA_6ne#{=1`avgiII9q4risaF zcI`un&1yDVZDWJ{VS@o82g=PRy7??$o|`7M9Aa6ISzJXV67Yk;$#!p=HF{EIGnJNL zGjZ{ptf8_(b&WsZ>41Mt^`crvTbZD)qNwe&2US$Xj+HL1tn$^vOwqtV*3rB5#C&lj9LdyjK~CC(8L>IcGK1&n=tP=IrHHVP#|pSI z4Uy;nfK!P+vT3Uw1+%qvO{lA@J<>fV2*S}}r%^5m^3(*?sNB#HVguiBuHib%9h2TW zwW&E*vs0aXGNh)<4E6M)3ZZD9G9yb@IZ&nrea2bUeqRbj_iC1D^UtL3x{Tcpx0~g+ zJI>`&wb#Xz>&MG(Em~Ms?yd&@x>^?VmU89l0LeNCi0I zBUu9+@sC@|N*MQ$eZFZtmP(Z(erVF76HGlyk0-@@M}$I=$XVfP(34D~p>ose_YfDF zVv*tB+G*10+;9sAbP~JbOyz+zyn_4-jEwqRF3b!Zj4V6bZ6+gzxy7r48n`Agmy0pm zGz_-7Ro}fFPx}V3=jHmfTH1&qqeel`r(lMAtnB zm8!>0)snkO=tXhF!5Z>a9-7|qfQ06(=<0%`_hd3r%?X$Y>)KNrV!cDRIxZz5X5K@3 zHbXu&&(R({lcQNbBZj4Fry`<9E?oeEFro;|*Ae8=&ebXj4+4DNcz(dJkoatx&qv;i zt<3NE#BXyr7wGO%QE6Q;p6L$^Ejc#SC;8jr4(sE&IJFq|vD@m#64>-2i~5#t4>flYV3; zgiv7Y7(nC%t3Qj0pw}K(5pxcgSy0q5tIfN_AM<;|28`VkQ3Jh#5MIr#)av7;?kaG; z>_UtIOBZX)pU$PRwOAzJ_y23dw0Vm=&Ib5+CQmU8{l>I341>-;2}78NMLYvx)}HLH zjYV~_mCO~422~Q?T;BPWn2+-5LQppjBk#Zf5?w>ZB4}Cnr(6zG#p^{ca zLdiLbuoJ;16$NHbsrpU+@0DNj5J|W;N0<2;bpGeR(w}Bc42f+lfH0S$swiezom%~` zjSh&@3kU#`J|Mjk!RHQPe%pn$QLcEF+8mv!w_rncE)u_$H~{v$x-q%Lb)AH_4)T74 z_OM!$XYHR%Q5Xuhh-}yn{|45*m>xnG3MDx(-Em0J@cL(f9hY?v5uaE zm!UX?(QO@6GTN6Yh2v=w*fphS?a`T*{u6l~#`J?Dx>bz!BWz@x)SWSi_|+4v|FBO- zdKhWHTOu~D#TO1=oFA0bCbDi}tE4dbh~AVpoNDp~qwzQm26I&QEm(xu%Lc$JnFHBu zziQJdT{@9UMCT}#lPZs}XRdS#n;z@wH4Ob+_l_WBNKN3hY2##LN>5@)KPzl(6)AN8 z*h>ATUt68(Cev5V!>)&E*BAIt4_y6LB&YSHmrer4pvzrnbg@F6o{uk~8>>>v$ z07#EKNAJ(>dwu7|BP2r30>J0-Z>}#pesRsj4Z0XDxka3yWIzA|K;TZ50D+Pj;yoJ( z&v*5U$;X{~zBKjHW#;&rZ5?|3e@Wy~9@fp}#){2iOfw`7FL?Yp^YJjd@=v1KK`B@Q zv9XrA`Yj~ZA|P6(aI^DJ$BNsUrVM@dY#LV{{Ch$TSJ?T>F_A~Uuy`EPeG$K4u zqALve2Y!a<2Ymh|OwXJEU!e*w9ujyAf%WdYni_@HTAJD0?r5AsWgut~Of>UdZyDa(;gQ+;7T8x(Hr;X7zg z*wlnw5{A<RNE142Yo_f@FPAC@DJ)A>@o5 z8a>h_8ht`)HU`LKX$%sP(-#2-d3=L}hMLGuPv<@ODW!HKyazKaee?7G~#9w(9E z4euweDyM|_garg7%@!ln_AXCGqeL)8mB+*gsBWm=`d>7^0N8 zOi#~cLRW9~AWp1|_kY)40F?GroSZzG&xYhb01EPHNMWKPN>Z{?lnU9OBb8pEQe{%* zs%n4lnW|M~y{dJp)i*RY`PjJTmew{k+dDeb>U3qg)y?{pe|)Z2y}ted^#_NBNAerQ zM#sh{G@5kJH5yO*{J&aVpNlzslQ#YjkWEtC)DgC&GkyI7I{54Cp+Nw zQ#w!2=rTK}>-@svl20sLURhns>am{N$m?Awmh>t6OyJI~ZGCqtRsCx9Mzhs6pwr#m z6W>3Od+3X2xWK}9-j(J;7{%#KHkU6HOXW(nR&O+0?M}DX9}Guhw@6L4fr5~Vgp7#z z%RfsW=yij4crVsrIYU*vm@29Y-|}J<%h?vcmH0OVn17v8-a<4~D}lfCV$4HwY^AM3 z7dvZsN*p<=p<@e0BY7!612ttU1M~o1Tal4T)yWifRbRuoY z8B|6&+wRFKvB+L^bG9M#eO(1UzoC`5IrZ0sgV`fnD5T=mYfA= zXgK-KHt-g_kvHLd%v=aG*FN9CqhE{w8Xrct|i%hl}ka7ydzKDPat`4P_3 zj!{uN0p{KDwqCJs?eN!vM45ml@vn+xFvZ{vYD?9qTB?Gvt0?9tOzWoif4+5O$Q-v0 zT3GYxv0K_k+i2@;gKcmvUD7qUmOVqy&?ozp`d*}w17ELF;Qm!d{L$!_g1}NooAAG? zg!%fW5Y9XrNyDPlSlPIsqY}vUSFah$|73~Ze2kx+Tghqn2HUnadxr@IuhSoQ-@3cT z9+pxGC}mRH8-0p9^w8(5G6h``-?Y#cw?*h%++n7IpLBfA;`9t;io_w5eNZMaB1olf LIIMxSEo2e^`I$Rw literal 0 HcmV?d00001 diff --git a/web/themes/custom/drevops/assets/fonts/rubik/rubik-latin.woff2 b/web/themes/custom/drevops/assets/fonts/rubik/rubik-latin.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..4ba94d14c2241d1fb4fa55af3602de9df0989037 GIT binary patch literal 35324 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 literal 0 HcmV?d00001 diff --git a/web/themes/custom/drevops/components/00-base/fonts/fonts.scss b/web/themes/custom/drevops/components/00-base/fonts/fonts.scss new file mode 100644 index 00000000..edeeb750 --- /dev/null +++ b/web/themes/custom/drevops/components/00-base/fonts/fonts.scss @@ -0,0 +1,61 @@ +// +// Brand webfaces, served from this origin. +// +// Both are variable fonts, so one file covers every weight the design uses. +// The unicode-range values are Google's own subsetting boundaries, kept so a +// visitor reading only Latin text never downloads the extended file. +// + +@font-face { + font-family: 'Lexend'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('#{$ct-assets-directory}fonts/lexend/lexend-latin.woff2') format('woff2'); + unicode-range: u+0000-00ff, u+0131, u+0152-0153, u+02bb-02bc, u+02c6, u+02da, u+02dc, u+0304, u+0308, u+0329, u+2000-206f, u+20ac, u+2122, u+2191, u+2193, u+2212, u+2215, u+feff, u+fffd; +} + +@font-face { + font-family: 'Lexend'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('#{$ct-assets-directory}fonts/lexend/lexend-latin-ext.woff2') format('woff2'); + unicode-range: u+0100-02ba, u+02bd-02c5, u+02c7-02cc, u+02ce-02d7, u+02dd-02ff, u+0304, u+0308, u+0329, u+1d00-1dbf, u+1e00-1e9f, u+1ef2-1eff, u+2020, u+20a0-20ab, u+20ad-20c0, u+2113, u+2c60-2c7f, u+a720-a7ff; +} + +@font-face { + font-family: 'Rubik'; + font-style: normal; + font-weight: 300 900; + font-display: swap; + src: url('#{$ct-assets-directory}fonts/rubik/rubik-latin.woff2') format('woff2'); + unicode-range: u+0000-00ff, u+0131, u+0152-0153, u+02bb-02bc, u+02c6, u+02da, u+02dc, u+0304, u+0308, u+0329, u+2000-206f, u+20ac, u+2122, u+2191, u+2193, u+2212, u+2215, u+feff, u+fffd; +} + +@font-face { + font-family: 'Rubik'; + font-style: normal; + font-weight: 300 900; + font-display: swap; + src: url('#{$ct-assets-directory}fonts/rubik/rubik-latin-ext.woff2') format('woff2'); + unicode-range: u+0100-02ba, u+02bd-02c5, u+02c7-02cc, u+02ce-02d7, u+02dd-02ff, u+0304, u+0308, u+0329, u+1d00-1dbf, u+1e00-1e9f, u+1ef2-1eff, u+2020, u+20a0-20ab, u+20ad-20c0, u+2113, u+2c60-2c7f, u+a720-a7ff; +} + +@font-face { + font-family: 'Rubik'; + font-style: italic; + font-weight: 300 900; + font-display: swap; + src: url('#{$ct-assets-directory}fonts/rubik/rubik-italic-latin.woff2') format('woff2'); + unicode-range: u+0000-00ff, u+0131, u+0152-0153, u+02bb-02bc, u+02c6, u+02da, u+02dc, u+0304, u+0308, u+0329, u+2000-206f, u+20ac, u+2122, u+2191, u+2193, u+2212, u+2215, u+feff, u+fffd; +} + +@font-face { + font-family: 'Rubik'; + font-style: italic; + font-weight: 300 900; + font-display: swap; + src: url('#{$ct-assets-directory}fonts/rubik/rubik-italic-latin-ext.woff2') format('woff2'); + unicode-range: u+0100-02ba, u+02bd-02c5, u+02c7-02cc, u+02ce-02d7, u+02dd-02ff, u+0304, u+0308, u+0329, u+1d00-1dbf, u+1e00-1e9f, u+1ef2-1eff, u+2020, u+20a0-20ab, u+20ad-20c0, u+2113, u+2c60-2c7f, u+a720-a7ff; +} diff --git a/web/themes/custom/drevops/components/01-atoms/image/image.component.yml b/web/themes/custom/drevops/components/01-atoms/image/image.component.yml new file mode 100644 index 00000000..b46e3ef6 --- /dev/null +++ b/web/themes/custom/drevops/components/01-atoms/image/image.component.yml @@ -0,0 +1,35 @@ +$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json +name: Image +status: stable +description: Basic image component +replaces: civictheme:image +props: + type: object + properties: + theme: + type: string + title: Theme + description: Theme variation (light or dark). + enum: + - light + - dark + url: + type: string + title: URL + description: Image URL. + alt: + type: string + title: Alt text + description: Image alt text. + width: + type: ['integer', 'null'] + title: Width + description: Image width. + height: + type: ['integer', 'null'] + title: Height + description: Image height. + modifier_class: + type: string + title: Modifier classes + description: Additional CSS classes. diff --git a/web/themes/custom/drevops/components/01-atoms/image/image.twig b/web/themes/custom/drevops/components/01-atoms/image/image.twig new file mode 100644 index 00000000..b5c60eea --- /dev/null +++ b/web/themes/custom/drevops/components/01-atoms/image/image.twig @@ -0,0 +1,40 @@ +{# +/** + * @file + * CivicTheme Image component. + * + * Resolves the intrinsic dimensions when they are not supplied, so the browser + * can reserve space before the file arrives. + * + * Props: + * - theme: [string] Theme variation (light or dark). + * - url: [string] Image URL. + * - alt: [string] Image alt text. + * - width: [integer,null] Image width. + * - height: [integer,null] Image height. + * - modifier_class: [string] Additional CSS classes. + * - attributes: [Drupal\Core\Template\Attribute] Additional HTML attributes. + */ +#} + +{% set theme_class = 'ct-theme-%s'|format(theme|default('light')) %} +{% set modifier_class = '%s %s'|format(theme_class, modifier_class|default('')) %} +{# Handle Drupal edge case where empty alt may be passed as literal '""' string #} +{% set alt = (alt == '""') ? '' : (alt|default('')) %} + +{% if url is not empty %} + {% if width is empty or height is empty %} + {% set resolved = do_image_dimensions(url) %} + {% set width = width|default(resolved.width|default(null)) %} + {% set height = height|default(resolved.height|default(null)) %} + {% endif %} + + {{ alt }} +{% endif %} diff --git a/web/themes/custom/drevops/components/02-molecules/pagination/pagination.component.yml b/web/themes/custom/drevops/components/02-molecules/pagination/pagination.component.yml new file mode 100644 index 00000000..89dc70d8 --- /dev/null +++ b/web/themes/custom/drevops/components/02-molecules/pagination/pagination.component.yml @@ -0,0 +1,146 @@ +$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json +name: Pagination +status: stable +description: Component for navigating through multiple pages of content +replaces: civictheme:pagination +props: + type: object + properties: + theme: + type: string + title: Theme + description: Theme variation (light or dark). + enum: + - light + - dark + heading_id: + type: string + title: Heading ID + description: Heading ID for accessibility. + items_modifier_class: + type: string + title: Items modifier class + description: Additional classes for pagination items. + items_per_page_title: + type: string + title: Items per page title + description: Items per page field title. + default: 'Items per page' + items_per_page_name: + type: string + title: Items per page name + description: Items per page select field name. + items_per_page_id: + type: string + title: Items per page ID + description: Items per page select field ID. + items_per_page_attributes: + type: Drupal\Core\Template\Attribute + title: Items per page attributes + description: Items per page select element attributes. + use_ellipsis: + type: boolean + title: Use ellipsis + description: Whether ellipsis should be shown. + modifier_class: + type: string + title: Modifier classes + description: Additional CSS classes. + items: + type: object + title: Items + description: Object containing pagination items. + properties: + first: + type: object + title: First page + description: First page link. + properties: + text: + type: string + title: Text + description: Link text. + default: 'First' + href: + type: string + title: URL + description: Link URL. + previous: + type: object + title: Previous page + description: Previous page link. + properties: + text: + type: string + title: Text + description: Link text. + default: 'Prev' + href: + type: string + title: URL + description: Link URL. + pages: + type: object + title: Pages + description: Object containing page links. + next: + type: object + title: Next page + description: Next page link. + properties: + text: + type: string + title: Text + description: Link text. + default: 'Next' + href: + type: string + title: URL + description: Link URL. + last: + type: object + title: Last page + description: Last page link. + properties: + text: + type: string + title: Text + description: Link text. + default: 'Last' + href: + type: string + title: URL + description: Link URL. + items_per_page_options: + type: array + title: Items per page options + description: Options for items per page. + items: + type: object + properties: + type: + type: string + title: Type + description: Option type ('option'). + label: + type: string + title: Label + description: Option label. + value: + type: string + title: Value + description: Option value. + selected: + type: string + title: Selected + description: Whether the option is selected. +slots: + title: + title: Title + description: Active page title. + current: + title: Current page + description: Current page number. + total_pages: + title: Total pages + description: Total pages count. diff --git a/web/themes/custom/drevops/components/02-molecules/pagination/pagination.twig b/web/themes/custom/drevops/components/02-molecules/pagination/pagination.twig new file mode 100644 index 00000000..2fb9a7a4 --- /dev/null +++ b/web/themes/custom/drevops/components/02-molecules/pagination/pagination.twig @@ -0,0 +1,177 @@ +{# +/** + * @file + * CivicTheme Pagination component. + * + * Props: + * - theme: [string] Theme variation (light or dark). + * - heading_id: [string] Heading ID for accessibility. + * - items_modifier_class: [string] Additional classes for pagination items. + * - items_per_page_title: [string] Items per page field title. + * - items_per_page_name: [string] Items per page select field name. + * - items_per_page_id: [string] Items per page select field ID. + * - items_per_page_attributes: [Drupal\Core\Template\Attribute] Items per page select element attributes. + * - use_ellipsis: [boolean] Whether ellipsis should be shown. + * - modifier_class: [string] Additional CSS classes. + * - items: [object] Object containing pagination items. + * Each property contains: + * - first: [object] First page link. + * Each property contains: + * - text: [string] Link text. + * - href: [string] Link URL. + * - previous: [object] Previous page link. + * Each property contains: + * - text: [string] Link text. + * - href: [string] Link URL. + * - pages: [object] Object containing page links. + * - next: [object] Next page link. + * Each property contains: + * - text: [string] Link text. + * - href: [string] Link URL. + * - last: [object] Last page link. + * Each property contains: + * - text: [string] Link text. + * - href: [string] Link URL. + * - items_per_page_options: [array] Options for items per page: + * Each item contains: + * - type: [string] Option type ('option'). + * - label: [string] Option label. + * - value: [string] Option value. + * - selected: [string] Whether the option is selected. + * - attributes: [Drupal\Core\Template\Attribute] Additional HTML attributes. + * + * Slots: + * - title: Active page title. + * - current: Current page number. + * - total_pages: Total pages count. + */ +#} + +{% set items_per_page_title = items_per_page_title|default('Items per page') %} +{% set theme_class = 'ct-theme-%s'|format(theme|default('light')) %} +{% set modifier_class = '%s %s'|format(theme_class, modifier_class|default('')) %} +{% set attributes = attributes is defined and attributes is not null ? attributes : create_attribute({}) %} + +{% if items is not empty %} + +{% endif %} diff --git a/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.component.yml b/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.component.yml new file mode 100644 index 00000000..a96c5701 --- /dev/null +++ b/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.component.yml @@ -0,0 +1,28 @@ +$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json +name: Mobile Navigation Trigger +status: stable +description: Button component for triggering the mobile navigation panel +replaces: civictheme:mobile-navigation-trigger +props: + type: object + properties: + theme: + type: string + title: Theme + description: Theme variation (light or dark). + enum: + - light + - dark + text: + type: string + title: Text + description: Button text. + icon: + type: string + title: Icon + description: Icon symbol name. + default: bars + modifier_class: + type: string + title: Modifier Class + description: Additional CSS classes. diff --git a/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.twig b/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.twig new file mode 100644 index 00000000..aaa9db79 --- /dev/null +++ b/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.twig @@ -0,0 +1,30 @@ +{# +/** + * @file + * CivicTheme Mobile Navigation Trigger component. + * + * Attribute objects are mutable and shared with the caller, so the flyout + * attributes are set on a copy to keep them off the block wrapper. + * + * Props: + * - theme: [string] Theme variation (light or dark). + * - text: [string] Button text. + * - icon: [string] Icon symbol name. + * - modifier_class: [string] Additional CSS classes. + * - attributes: [Drupal\Core\Template\Attribute] Additional HTML attributes. + */ +#} + +{% set modifier_class = 'ct-mobile-navigation-trigger %s'|format(modifier_class|default('')) %} +{% set trigger_attributes = create_attribute(attributes is defined and attributes is not null ? attributes.toArray() : {}) %} + +{% include 'civictheme:button' with { + theme: theme, + kind: 'button', + icon: icon|default('bars'), + icon_placement: 'after', + size: 'small', + text: text, + modifier_class: modifier_class, + attributes: trigger_attributes.setAttribute('data-flyout-open-trigger', '').setAttribute('data-flyout-target', '.ct-mobile-navigation').setAttribute('aria-expanded', 'false'), +} only %} diff --git a/web/themes/custom/drevops/components/03-organisms/promo/promo.component.yml b/web/themes/custom/drevops/components/03-organisms/promo/promo.component.yml new file mode 100644 index 00000000..0bd92409 --- /dev/null +++ b/web/themes/custom/drevops/components/03-organisms/promo/promo.component.yml @@ -0,0 +1,70 @@ +$schema: https://git.drupalcode.org/project/drupal/-/raw/HEAD/core/assets/schemas/v1/metadata.schema.json +name: Promo +status: stable +description: Promotional component with title, content, and call-to-action link +replaces: civictheme:promo +props: + type: object + properties: + theme: + type: string + title: Theme + description: Theme variation (light or dark). + enum: + - light + - dark + is_contained: + type: boolean + title: Contained + description: Whether the content is contained in a container. + vertical_spacing: + type: string + title: Vertical Spacing + description: Vertical spacing for the promo (top, bottom, or both). + enum: + - top + - bottom + - both + - none + with_background: + type: boolean + title: With Background + description: Whether to display with a background. + modifier_class: + type: string + title: Modifier Class + description: Additional CSS classes. + link: + type: object + title: Link + description: Call-to-action link. + properties: + text: + type: string + title: Text + description: Link text. + url: + type: string + title: URL + description: Link URL. + is_new_window: + type: boolean + title: New Window + description: Whether to open link in a new window. + is_external: + type: boolean + title: External + description: Whether the link is external. +slots: + content_top: + title: Content Top + description: Top content area. + title: + title: Title + description: Title text. + content: + title: Content + description: Main content text. + content_bottom: + title: Content Bottom + description: Bottom promo content. diff --git a/web/themes/custom/drevops/components/03-organisms/promo/promo.twig b/web/themes/custom/drevops/components/03-organisms/promo/promo.twig new file mode 100644 index 00000000..2229041a --- /dev/null +++ b/web/themes/custom/drevops/components/03-organisms/promo/promo.twig @@ -0,0 +1,115 @@ +{# +/** + * @file + * CivicTheme Promo component. + * + * Props: + * - theme: [string] Theme variation (light or dark). + * - is_contained: [boolean] Whether the content is contained in a container. + * - vertical_spacing: [string] Vertical spacing for the promo (top, bottom, or both). + * - with_background: [boolean] Whether to display with a background. + * - modifier_class: [string] Additional CSS classes. + * - link: [object] Call-to-action link. + * Each property contains: + * - text: [string] Link text. + * - url: [string] Link URL. + * - is_new_window: [boolean] Whether to open link in a new window. + * - is_external: [boolean] Whether the link is external. + * - attributes: [Drupal\Core\Template\Attribute] Additional HTML attributes. + * + * Slots: + * - content_top: Top content area. + * - title: Title text. + * - content: Main content text. + * - content_bottom: Bottom promo content. + * + * Blocks: + * - content_top_block + * - content_block + * - content_left_block + * - content_right_block + * - content_bottom_block + */ +#} + +{% set with_background_class = with_background ? 'ct-promo--with-background' : '' %} +{% set vertical_spacing_class = vertical_spacing in ['top', 'bottom', 'both'] ? 'ct-vertical-spacing--%s'|format(vertical_spacing) : '' %} +{% set theme_class = 'ct-theme-%s'|format(theme|default('light')) %} +{% set modifier_class = '%s %s %s %s'|format(theme_class, with_background_class, vertical_spacing_class, modifier_class|default('')) %} + +{% set is_contained = is_contained is defined ? is_contained : true %} + +{% if title is not empty or content is not empty %} +
+ {% if is_contained %} +
+
+
+ {% endif %} + {% block content_top_block %} + {% if content_top is not empty %} +
+ {{ content_top }} +
+ {% endif %} + {% endblock %} + + {% block content_block %} +
+ {% block content_left_block %} +
+ {% if title %} + {# The utility class carries the type scale, which would + otherwise come from the heading element itself. #} + {% include 'civictheme:heading' with { + content: title, + level: 2, + theme: theme, + modifier_class: 'ct-promo__title ct-heading-4', + } only %} + {% endif %} + + {% if content is not empty %} + {% include 'civictheme:paragraph' with { + theme: theme, + content: content, + modifier_class: 'ct-promo__content', + } only %} + {% endif %} +
+ {% endblock %} + + {% block content_right_block %} + {% if link %} + + {% endif %} + {% endblock %} +
+ {% endblock %} + + {% block content_bottom_block %} + {% if content_bottom is not empty %} +
+ {{ content_bottom }} +
+ {% endif %} + {% endblock %} + {% if is_contained %} +
+
+
+ {% endif %} +
+{% endif %} diff --git a/web/themes/custom/drevops/components/variables.base.scss b/web/themes/custom/drevops/components/variables.base.scss index 222bd98c..50744dc7 100644 --- a/web/themes/custom/drevops/components/variables.base.scss +++ b/web/themes/custom/drevops/components/variables.base.scss @@ -9,9 +9,6 @@ // // stylelint-disable scss/dollar-variable-pattern -// Example to override existing CivicTheme's palette color and define -// custom colors, which will automatically appear in Storybook. - $ct-colors-brands: ( 'light': ( 'brand1': #00698f, @@ -25,9 +22,7 @@ $ct-colors-brands: ( ) ); -// Example to override existing CivicTheme's palette color variants. $ct-colors: ( - // Override palette color variant. 'light': ( 'success': green, 'custom1': brown, @@ -39,16 +34,19 @@ $ct-colors: ( ), ); -// Example to define 2 custom local fonts which will automatically appear -// in Storybook. +// Both faces are declared in 00-base/fonts/fonts.scss instead. The generator +// this map feeds emits one @font-face per weight, and supports neither the +// variable weight ranges these ship as nor the unicode-range and font-display +// descriptors they need. An empty 'types' list registers the family name +// without emitting anything. $ct-fonts: ( + 'primary': ( + 'family': '"Lexend", sans-serif', + 'types': (), + ), 'secondary': ( 'family': 'Rubik, sans-serif', - 'types': ( - ( - 'uri': 'https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,300..900;1,300..900&display=swap', - ), - ), + 'types': (), ), 'tertiary': ( 'family': 'Roboto, sans-serif', diff --git a/web/themes/custom/drevops/components/variables.components.scss b/web/themes/custom/drevops/components/variables.components.scss index 6105ebcc..e3bcc6e9 100644 --- a/web/themes/custom/drevops/components/variables.components.scss +++ b/web/themes/custom/drevops/components/variables.components.scss @@ -66,8 +66,6 @@ $ct-icon-sizes: ( ), ); -// Example to override component's variable - Back to Top should have a -// 'custom1' colour background. $ct-back-to-top-light-background-color: ct-color-light('custom1'); // diff --git a/web/themes/custom/drevops/drevops.theme b/web/themes/custom/drevops/drevops.theme index e28a0ecc..f83b7691 100644 --- a/web/themes/custom/drevops/drevops.theme +++ b/web/themes/custom/drevops/drevops.theme @@ -42,6 +42,13 @@ function _drevops_block_add_class(array &$variables, string $class): void { $variables['attributes']['class'][] = $class; } +/** + * Implements hook_page_attachments_alter(). + */ +function drevops_page_attachments_alter(array &$attachments): void { + _drevops_attach_font_preloads($attachments); +} + /** * Implements hook_preprocess_HOOK() for container templates. */ diff --git a/web/themes/custom/drevops/includes/banner.inc b/web/themes/custom/drevops/includes/banner.inc index f64c02c6..17a6d945 100644 --- a/web/themes/custom/drevops/includes/banner.inc +++ b/web/themes/custom/drevops/includes/banner.inc @@ -9,7 +9,9 @@ declare(strict_types=1); use Drupal\civictheme\CivicthemeConstants; use Drupal\Component\Render\MarkupInterface; +use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Render\Markup; +use Drupal\media\MediaInterface; /** * Pre-process for Banner block. @@ -49,6 +51,32 @@ function _drevops_preprocess_block__civictheme_banner(array &$variables): void { if (!empty($variables['title']) && is_string($variables['title']) && !($variables['title'] instanceof MarkupInterface)) { $variables['title'] = Markup::create($variables['title']); } + + _drevops_banner_apply_image_styles($variables, $block, $node); +} + +/** + * Re-resolves banner images through image styles. + * + * CivicTheme resolves both of them with no style, which yields the URL of the + * original upload. + * + * @see civictheme_media_image_get_variables() + */ +function _drevops_banner_apply_image_styles(array &$variables, FieldableEntityInterface $block, mixed $node): void { + $background = $node instanceof FieldableEntityInterface ? civictheme_get_field_value($node, 'field_c_n_banner_background', TRUE) : NULL; + $background = $background ?: civictheme_get_field_value($block, 'field_c_b_background_image', TRUE, build: $variables); + + if ($background instanceof MediaInterface) { + $variables['background_image'] = civictheme_media_image_get_variables($background, 'banner_background'); + } + + $featured = $node instanceof FieldableEntityInterface ? civictheme_get_field_value($node, 'field_c_n_banner_featured_image', TRUE, build: $variables) : NULL; + $featured = $featured ?: civictheme_get_field_value($block, 'field_c_b_featured_image', TRUE, build: $variables); + + if ($featured instanceof MediaInterface) { + $variables['featured_image'] = civictheme_media_image_get_variables($featured, 'wide'); + } } /** diff --git a/web/themes/custom/drevops/includes/page.inc b/web/themes/custom/drevops/includes/page.inc index 6a3c8e9f..9f03994b 100644 --- a/web/themes/custom/drevops/includes/page.inc +++ b/web/themes/custom/drevops/includes/page.inc @@ -13,3 +13,32 @@ declare(strict_types=1); function _drevops_preprocess_page(array &$variables): void { $variables['header_is_sticky'] = civictheme_get_theme_config_manager()->load('components.header.is_sticky', FALSE); } + +/** + * Preloads the Latin subset of both brand faces. + * + * A face is only requested once the browser matches a rule that needs it, late + * enough that headings paint in the fallback and then reflow. Only the Latin + * subsets are preloaded, because a preload the page does not use is itself a + * wasted request. + */ +function _drevops_attach_font_preloads(array &$attachments): void { + $theme_path = \Drupal::service('extension.list.theme')->getPath('drevops'); + + $fonts = [ + '/' . $theme_path . '/dist/assets/fonts/lexend/lexend-latin.woff2', + '/' . $theme_path . '/dist/assets/fonts/rubik/rubik-latin.woff2', + ]; + + foreach ($fonts as $font) { + $attachments['#attached']['html_head_link'][] = [ + [ + 'rel' => 'preload', + 'href' => $font, + 'as' => 'font', + 'type' => 'font/woff2', + 'crossorigin' => 'anonymous', + ], + ]; + } +} From 0f4a9edebea7fedd3485bdd75dbc55eedccf6afa Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 10 Aug 2026 15:01:50 +1000 Subject: [PATCH 2/8] Wrote search result titles and descriptions to length. Descriptions were derived from 'field_c_n_summary' unchecked, so 24 pages ran past what a result shows and 2 had none at all. 'MetatagsAlterHook::trimDescriptions()' now cuts all three description tags to 155 characters on a word boundary. It runs on 'hook_metatags_attachments_alter()' because tokens are still unreplaced when the tags themselves are altered. That is a floor rather than a substitute for writing to length, so 'do_base_deploy_set_seo_metatags()' writes an explicit title and description into 'field_n_metatags' for the pages that needed one. It replaces a value only when what it finds falls outside those bounds, leaving later editor wording alone. Blog posts whose alias escaped the pathauto pattern are regenerated, and the two pages with no inbound internal links are given one. Nodes now publish 'WebPage' with its 'BreadcrumbList', which the breadcrumbs already rendered but never declared. --- AGENTS.md | 1 + config/default/core.extension.yml | 1 + .../default/metatag.metatag_defaults.node.yml | 2 + docs/performance.md | 68 ++++ docs/seo.md | 15 +- docs/sitemap.md | 6 + tests/behat/features/metatags.feature | 24 ++ tests/behat/features/xmlsitemap.feature | 12 + .../Drupal/EnvironmentSettingsTest.php | 9 + web/modules/custom/do_base/do_base.deploy.php | 336 ++++++++++++++++++ .../do_base/src/Hook/MetatagsAlterHook.php | 34 ++ .../Kernel/ImageDimensionsExtensionTest.php | 200 +++++++++++ .../src/Kernel/MetatagsAlterHookTest.php | 94 +++++ 13 files changed, 800 insertions(+), 2 deletions(-) create mode 100644 docs/performance.md create mode 100644 web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php diff --git a/AGENTS.md b/AGENTS.md index 77233f15..aa61a263 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -105,6 +105,7 @@ The `docs/` directory contains **what** applies to this project: - `docs/releasing.md` - Version scheme and release process - `docs/sitemap.md` - XML sitemap module, coverage and generation - `docs/seo.md` - Meta tags, social share cards and structured data +- `docs/performance.md` - Image styles, self-hosted fonts and layout stability - `docs/preview-links.md` - sharing unpublished content by link - `docs/faqs.md` - Project-specific FAQs diff --git a/config/default/core.extension.yml b/config/default/core.extension.yml index db840c84..bae9afef 100644 --- a/config/default/core.extension.yml +++ b/config/default/core.extension.yml @@ -101,6 +101,7 @@ module: schema_article: 0 schema_metatag: 0 schema_organization: 0 + schema_web_page: 0 schema_web_site: 0 search_api: 0 search_api_db: 0 diff --git a/config/default/metatag.metatag_defaults.node.yml b/config/default/metatag.metatag_defaults.node.yml index e4f14abb..d57ba7cc 100644 --- a/config/default/metatag.metatag_defaults.node.yml +++ b/config/default/metatag.metatag_defaults.node.yml @@ -11,4 +11,6 @@ tags: description: '[node:summary]' og_updated_time: '[node:changed:custom:c]' og_url: '[node:url]' + schema_web_page_breadcrumb: 'Yes' + schema_web_page_type: WebPage title: '[node:title] | [site:name]' diff --git a/docs/performance.md b/docs/performance.md new file mode 100644 index 00000000..d61e5b01 --- /dev/null +++ b/docs/performance.md @@ -0,0 +1,68 @@ +# Front-end performance + +This document describes what the site does to keep pages light and stable while they load. Meta tags and structured data are covered in [SEO](seo.md). + +## Images always go through an image style + +An image style does two things here: it caps the pixel dimensions, and it converts to WebP. Both matter, because the source files are large brand renders and a 4K PNG hero is several megabytes. + +| Style | Used for | +|---|---| +| `banner_background` | The banner background: scaled to 1920 wide, converted to WebP | +| `civictheme_*` | Cards, campaigns and slides: cropped by the CivicTheme sizes, converted to WebP | +| `wide` | The banner featured image | +| `social_share` | Share cards, deliberately **not** converted, because some social crawlers still handle WebP badly | + +CivicTheme resolves both banner images with no image style at all, which yields the URL of the original upload. `_drevops_banner_apply_image_styles()` re-resolves them. It covers the block field and the node field, because the node's value wins when both are set. + +When adding an image style that renders photographic content, copy the `image_convert` effect from `image.style.large.yml`. A style with only a crop effect ships whatever format was uploaded. + +## Images carry their own dimensions + +Without `width` and `height` a browser cannot reserve space for an image, so every image on the page moves the content under it as it arrives. + +The image component accepts both, but nothing that includes it passes them: the props are built from a media entity, which carries neither. `components/01-atoms/image/image.twig` overrides the CivicTheme component and fills them in through the `do_image_dimensions()` Twig function. + +That function works from the source file and the style's own transform rather than measuring the derivative, so the numbers are right even on the request that generates that derivative for the first time. Vectors have no raster size, so their ratio is read from the `viewBox`; only the ratio matters, since CSS decides the rendered size. + +Components are included from Twig rather than rendered through a render element, so there is no preprocess step and no `#pre_render` to hook. A Twig function called from the template is the only interception point. + +## Overriding a CivicTheme component + +Drupal matches components by name within an extension, so a same-named component in this theme is a new component rather than an override. The `replaces:` key in the `.component.yml` is what makes it an override: + +```yaml +name: Image +replaces: civictheme:image +``` + +Without it the theme's version is simply never used, and the rendered markup keeps saying `data-component-id="civictheme:image"`. + +## Fonts are served from this origin + +Lexend and Rubik ship in `assets/fonts/` and are declared in `components/00-base/fonts/fonts.scss`. Nothing is fetched from `fonts.googleapis.com`, which is why the CSP no longer allows it. + +They are declared by hand rather than through CivicTheme's `$ct-fonts` map, because the generator that map feeds emits one `@font-face` per weight and supports neither the variable weight ranges these faces ship as nor the `unicode-range` and `font-display` descriptors a self-hosted face needs. The map still names the families, with an empty `types` list so it emits nothing. + +Only the Latin subsets are preloaded, by `_drevops_attach_font_preloads()`. The extended subsets are needed by a small minority of pages, and a preload the page does not use is a wasted request. + +Replacing a face means replacing the `woff2` files and the `unicode-range` values together. The ranges are Google's own subsetting boundaries and are what keeps a visitor reading only Latin text from downloading the extended file. + +## The banner background is preloaded + +The banner paints its background from CSS, so the browser cannot discover the file until the stylesheet has been fetched and parsed. On the pages carrying one, that background is the largest contentful paint. + +`_do_base_attach_banner_preload()` emits a `rel="preload"` for it. The URL has to be the one the stylesheet asks for, or the file is fetched twice: the preload resolves the same image style, and skips the whole thing when the file has no derivative. + +## Verifying a change + +```bash +ahoy test-kernel -- --filter=ImageDimensionsExtensionTest +``` + +For the rendered end, check that a page's images carry `width` and `height`, that no request goes to `fonts.googleapis.com`, and that image URLs contain `/styles/`. Lighthouse under mobile emulation is the quickest way to see the three metrics these affect: largest contentful paint, cumulative layout shift, and total byte weight. + +## Related + +- [SEO](seo.md) - meta tags, share cards and structured data +- [Sitemap](sitemap.md) - XML sitemap coverage and generation diff --git a/docs/seo.md b/docs/seo.md index 3a9260c6..bafbcd84 100644 --- a/docs/seo.md +++ b/docs/seo.md @@ -11,7 +11,7 @@ This document describes the meta tags, share cards and structured data the site | `metatag_twitter_cards` | `twitter:*` tags read by X | | `metatag_dc` | Dublin Core tags | | `schema_metatag` | Renders JSON-LD structured data through the same metatag defaults | -| `schema_organization`, `schema_web_site`, `schema_article` | The three Schema.org types this site publishes | +| `schema_organization`, `schema_web_site`, `schema_article`, `schema_web_page` | The Schema.org types this site publishes | | `pathauto` | Readable, stable URL aliases | | `redirect` | Keeps old URLs working after an alias changes | | `redirect_404` | Records 404 paths at `/admin/config/search/redirect/404` so real lost traffic can be turned into redirects | @@ -25,7 +25,7 @@ Deliberately not installed: `yoast_seo` (a heavy analyser on every node form), ` - `title`, `description` and `canonical_url`, from the metatag defaults. - The full Open Graph set: `og:site_name`, `og:type`, `og:url`, `og:title`, `og:description`, `og:image` with `og:image:width`, `og:image:height` and `og:image:alt`. - The full Twitter Card set: `twitter:card`, `twitter:site`, `twitter:title`, `twitter:description`, `twitter:image` and `twitter:image:alt`. -- A JSON-LD `@graph` carrying `Organization` and `WebSite`, plus `Article` on blog posts. +- A JSON-LD `@graph` carrying `Organization` and `WebSite`, plus `WebPage` with its `BreadcrumbList` on nodes and `Article` on blog posts. `twitter:card` is `summary_large_image` site-wide. Any other value makes X render a small square thumbnail, which is why the share image is produced at 1200x630. @@ -40,6 +40,7 @@ Configuration holds the values that genuinely differ between pages: | `node` | Node title, description and URL | | `node__blog` | `og:type: article`, the article timestamps and the `Article` structured data | | `node__civictheme_page`, `node__project` | The summary field the description is taken from | +| `node` | `WebPage` and its breadcrumb, alongside the node title, description and URL | The social **title and description are not configured**. `MetatagsAlterHook` derives them from the `title` and `description` tags, and the Twitter pair from the Open Graph pair. This keeps one source of truth for the wording, and it is also the only way those tags reach the front page: `metatag_get_default_tags()` treats the front page, 403 and 404 as special pages and stops after the global and special defaults, never reading the entity or bundle defaults. @@ -54,6 +55,16 @@ A thumbnail is passed over in favour of the fallback when no image toolkit can d The `Article` image in the structured data is filled from the same resolved value, so it carries the same fallbacks. It is set as an `ImageObject` rather than a bare URL because `SchemaImageObjectBase::output()` drops any value without a `url` key. +## Title and description length + +A search result shows roughly 60 characters of the title and 155 of the description, and cuts whatever is past that. Two things keep the tags inside those bounds. + +`MetatagsAlterHook::trimDescriptions()` cuts `description`, `og:description` and `twitter:description` to 155 characters on a word boundary. It runs on `hook_metatags_attachments_alter()` rather than `hook_metatags_alter()`, because tokens are still unreplaced when the tags themselves are altered: at that point a description is the literal `[node:field_c_n_summary:value]` and there is nothing to measure. All three tags get the same treatment so the wording stays identical wherever it appears. + +That is a floor, not a substitute for writing to length. Pages whose derived wording was too long, too short, or missing carry an explicit value in `field_n_metatags`, written once by `do_base_deploy_set_seo_metatags()`. The hook replaces a tag only when the value it finds falls outside those bounds, so wording an editor writes later is left alone and a repeat deployment is a no-op. + +The titles it writes carry qualifiers the visible heading does not need: a page headed `GovCMS` is titled `GovCMS Development and Migration`, because the heading has a whole page for context and a search result has one line. They use `[site:name]` rather than a literal brand, matching the `node` default they replace. + ## Image assets Both live in `web/modules/custom/do_base/assets/` and are generated from the theme's brand assets: diff --git a/docs/sitemap.md b/docs/sitemap.md index c88651d0..2760cefd 100644 --- a/docs/sitemap.md +++ b/docs/sitemap.md @@ -20,6 +20,12 @@ A bundle is included only when an `xmlsitemap.settings..` c Only `xmlsitemap` itself is enabled. The `xmlsitemap_custom` and `xmlsitemap_engines` submodules are deliberately left off - the front page is covered natively by `frontpage_priority` and `frontpage_changefreq`, and pinging search engines on every change is not wanted. +## The host the URLs carry + +Cron regenerates the sitemap, and cron has no request to take a host from, so `xmlsitemap` keeps its own base URL. Left unset it falls back to a state value seeded at install time from whichever host ran the installer, and state is not exported configuration, so that value never travels with the code and never shows up in a diff. + +`web/sites/default/includes/modules/settings.xmlsitemap.php` states it instead. It has to match the host in the canonical tags and in `robots.txt`, because anything else makes every URL in the sitemap a redirect to the host the site actually serves. + ## Front page de-duplication `system.site:page.front` points at a node that has no path alias, so that node would otherwise be listed twice: once as `/` and once under its internal path. `do_base_xmlsitemap_link_alter()` drops the second entry, because two sitemap URLs serving identical content read as duplicate content to search engines. diff --git a/tests/behat/features/metatags.feature b/tests/behat/features/metatags.feature index d32c09e4..affcd62f 100644 --- a/tests/behat/features/metatags.feature +++ b/tests/behat/features/metatags.feature @@ -62,6 +62,30 @@ Feature: Page content metatags And the response should contain "https://www.drevops.com/" + And the response should not contain "https://drevops.com/" + @api @blog Scenario: Sitemap lists published blog posts only Given the following "blog" content: diff --git a/tests/phpunit/Drupal/EnvironmentSettingsTest.php b/tests/phpunit/Drupal/EnvironmentSettingsTest.php index 2f6d9bf9..7b7b26c8 100644 --- a/tests/phpunit/Drupal/EnvironmentSettingsTest.php +++ b/tests/phpunit/Drupal/EnvironmentSettingsTest.php @@ -279,6 +279,7 @@ public function testEnvironmentNoOverrides(): void { $settings['trusted_host_patterns'] = [ '^localhost$', ]; + $settings['xmlsitemap_base_url'] = 'https://www.drevops.com'; $this->assertSettings($settings); } @@ -354,6 +355,7 @@ public function testEnvironmentOverrides(): void { '^localhost$', ]; + $settings['xmlsitemap_base_url'] = 'https://www.drevops.com'; $this->assertSettings($settings); } @@ -437,6 +439,7 @@ public function testEnvironmentLocal(): void { $settings['trusted_host_patterns'] = [ '^localhost$', ]; + $settings['xmlsitemap_base_url'] = 'https://www.drevops.com'; $this->assertSettings($settings); } @@ -492,6 +495,7 @@ public function testEnvironmentLocalContainer(): void { '^example-site\.docker\.amazee\.io$', '^nginx$', ]; + $settings['xmlsitemap_base_url'] = 'https://www.drevops.com'; $this->assertSettings($settings); } @@ -546,6 +550,7 @@ public function testEnvironmentGha(): void { $settings['trusted_host_patterns'] = [ '^localhost$', ]; + $settings['xmlsitemap_base_url'] = 'https://www.drevops.com'; $this->assertSettings($settings); } @@ -600,6 +605,7 @@ public function testEnvironmentLagoonPreview(): void { '^.+\.amazee\.io$', '^example1\.com|example2/com$', ]; + $settings['xmlsitemap_base_url'] = 'https://www.drevops.com'; $this->assertSettings($settings); } @@ -654,6 +660,7 @@ public function testEnvironmentLagoonDev(): void { '^.+\.amazee\.io$', '^example1\.com|example2/com$', ]; + $settings['xmlsitemap_base_url'] = 'https://www.drevops.com'; $this->assertSettings($settings); } @@ -708,6 +715,7 @@ public function testEnvironmentLagoonTest(): void { '^.+\.amazee\.io$', '^example1\.com|example2/com$', ]; + $settings['xmlsitemap_base_url'] = 'https://www.drevops.com'; $this->assertSettings($settings); } @@ -762,6 +770,7 @@ public function testEnvironmentLagoonProd(): void { '^.+\.amazee\.io$', '^example1\.com|example2/com$', ]; + $settings['xmlsitemap_base_url'] = 'https://www.drevops.com'; $this->assertSettings($settings); } diff --git a/web/modules/custom/do_base/do_base.deploy.php b/web/modules/custom/do_base/do_base.deploy.php index ea353b8a..87358f1c 100644 --- a/web/modules/custom/do_base/do_base.deploy.php +++ b/web/modules/custom/do_base/do_base.deploy.php @@ -10,11 +10,13 @@ declare(strict_types=1); use Drupal\civictheme\CivicthemeColorManager; +use Drupal\Component\Serialization\Json; use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Sql\DefaultTableMapping; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; use Drupal\Core\File\FileExists; use Drupal\Core\File\FileSystemInterface; +use Drupal\do_base\Hook\MetatagsAlterHook; use Drupal\drupal_helpers\Helper; use Drupal\drupal_helpers\Report\Reporter; use Drupal\entity_usage\RecreateTrackingDataForFieldQueuer; @@ -584,6 +586,89 @@ function do_base_deploy_seed_project_vocabularies(): string { return Helper::report(); } +/** + * Regenerates blog aliases that do not follow the pathauto pattern. + * + * @param array|null $sandbox + * Batch sandbox, matching the nullable reference the batch helper takes. + * + * @return string|null + * Summary once every alias is regenerated, or NULL while batching. + */ +function do_base_deploy_realias_blog_posts(?array &$sandbox = NULL): ?string { + $nids = \Drupal::entityQuery('node')->condition('type', 'blog')->accessCheck(FALSE)->execute(); + + if (empty($nids)) { + Helper::reporter()->skipped('There are no blog posts.'); + + return Helper::report(); + } + + // The query doubles as the idempotency guard: an alias regenerated onto the + // pattern no longer matches, so a repeat deployment finds nothing to do. + $query = \Drupal::entityQuery('path_alias') + ->condition('alias', '/blog/%', 'NOT LIKE') + ->condition('path', array_map(static fn(string $nid): string => '/node/' . $nid, $nids), 'IN'); + + return Helper::entity($sandbox)->batchQuery($query, static function (PathAliasInterface $alias): void { + _do_base_blog_realias($alias); + }, status: Reporter::UPDATED); +} + +/** + * Adds primary navigation links for pages nothing links to. + */ +function do_base_deploy_relink_orphan_pages(): string { + $menu_name = 'civictheme-primary-navigation'; + + $pages = [ + 'How we work' => '/how-we-work', + 'AI integration & automation' => '/ai-integration-automation', + ]; + + foreach ($pages as $title => $alias) { + _do_base_menu_link_alias($menu_name, $title, $alias); + } + + return Helper::report(); +} + +/** + * Sets the search result title and description on the pages that need one. + * + * @param array|null $sandbox + * Batch sandbox, matching the nullable reference the batch helper takes. + * + * @return string|null + * Summary once every page is set, or NULL while batching. + */ +function do_base_deploy_set_seo_metatags(?array &$sandbox = NULL): ?string { + $overrides = _do_base_seo_metatags(); + $alias_manager = \Drupal::service('path_alias.manager'); + + $nids = []; + foreach (array_keys($overrides) as $alias) { + // The front page is reached through the site setting rather than an alias. + $path = $alias === '/' ? (string) \Drupal::config('system.site')->get('page.front') : $alias_manager->getPathByAlias($alias); + + if (preg_match('#^/node/(\d+)$#', $path, $matches)) { + $nids[$matches[1]] = $alias; + } + } + + if (empty($nids)) { + Helper::reporter()->skipped('None of the pages carrying an override exist.'); + + return Helper::report(); + } + + $query = \Drupal::entityQuery('node')->condition('nid', array_keys($nids), 'IN'); + + return Helper::entity($sandbox, 10)->batchQuery($query, static function (NodeInterface $node) use ($nids, $overrides): void { + _do_base_set_seo_metatags($node, $overrides[$nids[$node->id()]] ?? []); + }); +} + /** * Assembles the Our Work page. */ @@ -765,6 +850,257 @@ function _do_base_menu_leading_weight(string $menu_name): int { return min($weights) - 1; } +/** + * Writes a title and description onto a node. + * + * @param \Drupal\node\NodeInterface $node + * The node to write to. + * @param array $tags + * Metatag values keyed by tag name. + */ +function _do_base_set_seo_metatags(NodeInterface $node, array $tags): void { + if (empty($tags) || !$node->hasField('field_n_metatags')) { + return; + } + + $current = Json::decode((string) $node->get('field_n_metatags')->value) ?: []; + $changed = FALSE; + + foreach ($tags as $tag => $value) { + // Wording already inside the length a result shows is left alone, whoever + // wrote it. That also makes a repeat deployment a no-op, since everything + // written here is inside those bounds. + if (isset($current[$tag]) && _do_base_seo_metatag_fits($tag, (string) $current[$tag])) { + continue; + } + + $current[$tag] = $value; + $changed = TRUE; + } + + if (!$changed) { + return; + } + + $node->set('field_n_metatags', Json::encode($current)); + $node->setNewRevision(FALSE); + $node->save(); + + Helper::reporter()->updated(sprintf('Set the search result wording on "%s".', $node->getTitle())); +} + +/** + * Reports whether a tag value fits what a search result shows. + * + * @param string $tag + * The metatag name. + * @param string $value + * The value, which may still carry tokens. + * + * @return bool + * TRUE when the value needs no replacing. + */ +function _do_base_seo_metatag_fits(string $tag, string $value): bool { + $length = mb_strlen(str_replace('[site:name]', (string) \Drupal::config('system.site')->get('name'), $value)); + + return match ($tag) { + 'title' => $length >= 30 && $length <= 60, + 'description' => $length >= 70 && $length <= MetatagsAlterHook::DESCRIPTION_MAX_LENGTH, + default => TRUE, + }; +} + +/** + * Returns the title and description to publish for each page, keyed by alias. + * + * The title is what a search result shows rather than what the page displays, + * so it carries the qualifiers a heading does not need. The description is + * written to sit inside the length a result will show. + * + * @return array> + * Metatag values keyed by tag name, keyed by path alias. + */ +function _do_base_seo_metatags(): array { + return [ + '/' => [ + 'description' => 'Australian Drupal and DevOps consultancy. We build and support Drupal platforms with senior engineering and automated testing from the first commit.', + ], + '/about-us' => [ + 'title' => 'About Us: Australian Drupal and DevOps Team | [site:name]', + 'description' => 'An Australian Drupal and DevOps consultancy since 2016, working with government, education and enterprise teams who need real engineering.', + ], + '/ai-assisted-delivery' => [ + 'description' => 'Already on Drupal? We cost the same senior, fully-tested work two ways, by hand and AI-assisted, so you see the difference before you change.', + ], + '/ai-integration-automation' => [ + 'description' => 'AI integration and automation for Drupal platforms, built with the same testing and review gates as everything else we ship.', + ], + '/blog' => [ + 'title' => 'Drupal and DevOps Blog | [site:name]', + 'description' => 'Real-world Drupal and DevOps practice from the DrevOps team: technical deep-dives, release notes, and what we have learned running open-source tools.', + ], + '/blog/ai-written-code-safe-what-we-put-around-it-it-ships' => [ + 'description' => 'Is AI-written code safe? AI speeds up the writing, never the checking. Every change is still reviewed, tested and gated before it ships.', + ], + '/blog/are-ai-restrictions-actually-growing-open-source' => [ + 'description' => 'AI policies meant to limit AI on private code have an unexpected effect: developers extract generic logic into public modules, and open source grows.', + ], + '/blog/becoming-maintainers-drupal-driver-and-drupal-extension-projects' => [ + 'description' => 'Alex Skrypnyk now co-maintains Drupal Driver and Drupal Extension. Three coordinated alphas of the Drupal Behat stack just shipped.', + ], + '/blog/how-we-upgrade-and-modernise-drupal-sites' => [ + 'description' => 'Off Drupal 7, or stuck on 9 or 10? How we upgrade: assess, modernise with Rector, migrate content, and prove it with automated tests.', + ], + '/blog/same-senior-drupal-work-about-third-less' => [ + 'description' => 'The same senior, tested Drupal work for about a third less on suitable work, because delivery got faster, not because corners were cut.', + ], + '/blog/vortex-134' => [ + 'description' => 'Vortex 1.34.0 (Flux) adds Composer security audits, Composer Patches v2, modernised dev dependencies, and moves end-to-end tests to PHPUnit.', + ], + '/blog/vortex-135-released' => [ + 'description' => 'Vortex 1.35 adds full Drupal 11.3 compatibility and updates container images, GitHub Actions and automation tooling for stability and security.', + ], + '/blog/vortex-136-released' => [ + 'description' => 'Vortex 1.36 makes the template AI-native and migration-ready, with structured agent support, CI-testable migrations and full-stack JS testing.', + ], + '/blog/vortex-137-released' => [ + 'description' => 'Vortex 1.37 extracts demo code into its own module, splits linting into a standalone CI job, and restructures the CircleCI config for maintenance.', + ], + '/blog/vortex-1390-photon-whats-release' => [ + 'description' => 'Vortex 1.39.0 adds opt-in visual regression testing, accessibility checks in the box, faster CI, and a reliability fix for Lagoon projects.', + ], + '/blog/vortex-1-40-0-spectrum' => [ + 'description' => 'Vortex 1.40.0 ships CI secret and workflow scanning, test results on your PRs, site-wide accessibility checks and SDC tooling out of the box.', + ], + '/blog/vortex-138-released' => [ + 'description' => 'Vortex 1.38 brings new testing, default modules, security and deployment improvements, plus a runtime bump. Here is what changed and why.', + ], + '/blog/vortex-2570-released' => [ + 'description' => 'Vortex 25.7.0 adds Drupal 11.2 support, faster CI, better Docker and Composer handling for local development, and a more robust installer.', + ], + '/blog/vortex-2580-released' => [ + 'description' => 'Vortex 25.8.0 adds Drupal CMS support, cuts CI build times by up to 5 minutes, improves Lagoon hosting, and significantly enhances the installer.', + ], + '/blog/what-ai-actually-doing-open-source' => [ + 'description' => 'From maintaining around 40 repos: AI speeds up consuming open source far faster than contributing back, and that gap is the real threat.', + ], + '/contact' => [ + 'title' => 'Contact Our Drupal Team | [site:name]', + 'description' => 'Talk to the engineers who would do the work. Tell us what you are running and what is not working, and we will tell you what we would do.', + ], + '/how-we-work' => [ + 'title' => 'How We Work: Process, Pricing, Delivery | [site:name]', + 'description' => 'What working with DrevOps looks like, from first conversation to go-live: what happens at each step and how we build a price with nothing hidden.', + ], + '/responsible-ai' => [ + 'title' => 'Responsible AI Policy | [site:name]', + 'description' => 'How DrevOps uses AI responsibly: safeguards around data security, governance and human oversight, so nothing you share trains a public model.', + ], + '/services' => [ + 'title' => 'Drupal and DevOps Services | [site:name]', + 'description' => 'Expert-led Drupal and DevOps services: builds, upgrades, migrations, automated testing, CI/CD and ongoing support for platforms that matter.', + ], + '/services/audit' => [ + 'title' => 'Drupal Site Audit and Health Check | [site:name]', + ], + '/services/automated-testing' => [ + 'title' => 'Automated Testing for Drupal | [site:name]', + ], + '/services/ci-cd-pipelines' => [ + 'description' => 'Automated CI/CD pipelines that test, build and deploy your Drupal application safely, using GitHub Actions, CircleCI, Azure Pipelines or GitLab CI.', + ], + '/services/civictheme' => [ + 'title' => 'CivicTheme Design System Development | [site:name]', + ], + '/services/containerisation' => [ + 'title' => 'Docker Containerisation for Drupal | [site:name]', + ], + '/services/drupal-upgrades' => [ + 'title' => 'Drupal Core and Contrib Upgrades | [site:name]', + ], + '/services/govcms' => [ + 'title' => 'GovCMS Development and Migration | [site:name]', + ], + '/services/migrations' => [ + 'title' => 'Drupal Migrations from Any CMS | [site:name]', + ], + '/services/support-plans' => [ + 'title' => 'SLA-backed Drupal Support Plans | [site:name]', + ], + '/work' => [ + 'description' => 'Drupal projects we have delivered and supported, from government platforms to community organisations, plus the open-source tools that came out of it.', + ], + ]; +} + +/** + * Returns a weight that sorts behind every top-level link in a menu. + */ +function _do_base_menu_trailing_weight(string $menu_name): int { + $links = \Drupal::entityTypeManager()->getStorage('menu_link_content')->loadByProperties(['menu_name' => $menu_name]); + + // Seeded so that a menu with no top-level links still yields a weight. + $weights = [0]; + + foreach ($links as $link) { + if ($link instanceof MenuLinkContentInterface && $link->getParentId() === '') { + $weights[] = $link->getWeight(); + } + } + + return max($weights) + 1; +} + +/** + * Adds a menu link to the page behind an alias. + */ +function _do_base_menu_link_alias(string $menu_name, string $title, string $alias): void { + if (Helper::menu()->findItem($menu_name, ['title' => $title]) instanceof MenuLinkContentInterface) { + Helper::reporter()->skipped(sprintf('The "%s" link already exists.', $title)); + + return; + } + + $path = \Drupal::service('path_alias.manager')->getPathByAlias($alias); + + if (!preg_match('#^/node/(\d+)$#', $path, $matches)) { + Helper::reporter()->skipped(sprintf('No node is aliased to "%s".', $alias)); + + return; + } + + // createTree() numbers links from their position in the tree it is handed, + // which describes this link alone and so says nothing about where it belongs + // among the links already in the menu. Reading the weight first keeps the + // link being created out of its own calculation. + $weight = _do_base_menu_trailing_weight($menu_name); + + Helper::menu()->createTree($menu_name, [$title => 'entity:node/' . $matches[1]]); + Helper::menu()->updateItem($menu_name, ['title' => $title], ['weight' => $weight]); + + Helper::reporter()->created(sprintf('Created the "%s" link.', $title)); +} + +/** + * Regenerates the alias of the blog post a path alias points at. + */ +function _do_base_blog_realias(PathAliasInterface $alias): void { + if (!preg_match('#^/node/(\d+)$#', $alias->getPath(), $matches)) { + return; + } + + $node = \Drupal::entityTypeManager()->getStorage('node')->load($matches[1]); + + if (!$node instanceof NodeInterface || $node->bundle() !== 'blog') { + return; + } + + // Regenerating rather than rewriting the alias string keeps the result + // defined by the pattern alone, and lets the redirect module record the + // superseded path so inbound links keep resolving. + \Drupal::service('pathauto.generator')->updateEntityAlias($node, 'update'); +} + /** * Regenerates the alias of the project a path alias points at. */ diff --git a/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php b/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php index f3bcf6f7..2ae265b3 100644 --- a/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php +++ b/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php @@ -4,6 +4,7 @@ namespace Drupal\do_base\Hook; +use Drupal\Component\Utility\Unicode; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -21,6 +22,16 @@ */ final class MetatagsAlterHook { + /** + * The point past which a search result stops showing the description. + */ + public const DESCRIPTION_MAX_LENGTH = 155; + + /** + * The tags carrying that description. + */ + protected const DESCRIPTION_TAGS = ['description', 'og_description', 'twitter_cards_description']; + public function __construct( protected EntityTypeManagerInterface $entityTypeManager, protected ConfigFactoryInterface $configFactory, @@ -38,6 +49,29 @@ public function alter(array &$metatags, array &$context): void { $this->setSocialImage($metatags, $entity instanceof ContentEntityInterface ? $entity : NULL); } + /** + * Implements hook_metatags_attachments_alter(). + */ + #[Hook('metatags_attachments_alter')] + public function trimDescriptions(array &$attachments): void { + // Tokens are replaced after hook_metatags_alter(), so a description is + // still a token when the tags themselves are altered and only reaches its + // full length here. + foreach ($attachments['#attached']['html_head'] ?? [] as $delta => $element) { + if (!in_array($element[1] ?? '', static::DESCRIPTION_TAGS, TRUE)) { + continue; + } + + $content = $element[0]['#attributes']['content'] ?? NULL; + + if (!is_string($content) || mb_strlen($content) <= static::DESCRIPTION_MAX_LENGTH) { + continue; + } + + $attachments['#attached']['html_head'][$delta][0]['#attributes']['content'] = Unicode::truncate($content, static::DESCRIPTION_MAX_LENGTH, TRUE, TRUE); + } + } + /** * Gives the social tags the page title and description when they have none. */ diff --git a/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php b/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php new file mode 100644 index 00000000..9547bf36 --- /dev/null +++ b/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php @@ -0,0 +1,200 @@ +installEntitySchema('user'); + $this->installEntitySchema('file'); + $this->installConfig(['system', 'image']); + + $this->extension = $this->container->get('do_base.twig.image_dimensions'); + + $directory = 'public://do_test'; + $this->container->get('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY); + $this->writeImage($directory . '/source.png'); + } + + /** + * Tests that an unprocessed image reports the dimensions of the file. + */ + public function testOriginalReportsItsOwnDimensions(): void { + // Act. + $dimensions = $this->extension->dimensions($this->publicUrl('do_test/source.png')); + + // Assert. + $this->assertSame(['width' => static::SOURCE_WIDTH, 'height' => static::SOURCE_HEIGHT], $dimensions); + } + + /** + * Tests that a derivative reports the dimensions the style produces. + */ + public function testDerivativeReportsTheStyleDimensions(): void { + // Prepare. + $this->createScaleStyle('do_test_scale', 400); + + // Act. + $dimensions = $this->extension->dimensions($this->publicUrl('styles/do_test_scale/public/do_test/source.png')); + + // Assert. + $this->assertSame(['width' => 400, 'height' => 200], $dimensions); + } + + /** + * Tests that a converted derivative is traced back to its source file. + * + * A convert effect appends its extension to the source file name, so the + * derivative path is not a path any file sits at. + */ + public function testConvertedDerivativeIsTracedToItsSource(): void { + // Prepare. + $this->createScaleStyle('do_test_convert', 200); + + // Act. + $dimensions = $this->extension->dimensions($this->publicUrl('styles/do_test_convert/public/do_test/source.png.webp')); + + // Assert. + $this->assertSame(['width' => 200, 'height' => 100], $dimensions); + } + + /** + * Tests that a URL carrying a query string is still resolved. + */ + public function testQueryStringIsIgnored(): void { + // Act. + $dimensions = $this->extension->dimensions($this->publicUrl('do_test/source.png') . '?itok=abc123'); + + // Assert. + $this->assertSame(['width' => static::SOURCE_WIDTH, 'height' => static::SOURCE_HEIGHT], $dimensions); + } + + /** + * Tests that a vector reports the ratio declared in its markup. + */ + public function testVectorReportsItsViewBox(): void { + // Prepare. + $path = 'do_test_vector.svg'; + file_put_contents($this->container->getParameter('app.root') . '/' . $path, ''); + + // Act. + $dimensions = $this->extension->dimensions('/' . $path); + + // Assert. + $this->assertSame(['width' => 120, 'height' => 60], $dimensions); + + unlink($this->container->getParameter('app.root') . '/' . $path); + } + + /** + * Tests that a URL nothing can be measured from yields no dimensions. + */ + #[DataProvider('dataProviderUnmeasurableUrlYieldsNothing')] + public function testUnmeasurableUrlYieldsNothing(?string $url): void { + // Act. + $dimensions = $this->extension->dimensions($url); + + // Assert. + $this->assertSame([], $dimensions); + } + + /** + * Data provider for testUnmeasurableUrlYieldsNothing. + */ + public static function dataProviderUnmeasurableUrlYieldsNothing(): \Iterator { + yield 'null' => [NULL]; + yield 'empty' => ['']; + yield 'no path' => ['https://example.com']; + yield 'missing vector' => ['/themes/custom/absent.svg']; + } + + /** + * Tests that a managed file that cannot be read yields no dimensions. + */ + #[DataProvider('dataProviderUnreadableManagedFileYieldsNothing')] + public function testUnreadableManagedFileYieldsNothing(string $relative): void { + // Act. + $dimensions = $this->extension->dimensions($this->publicUrl($relative)); + + // Assert. + $this->assertSame([], $dimensions); + } + + /** + * Data provider for testUnreadableManagedFileYieldsNothing. + */ + public static function dataProviderUnreadableManagedFileYieldsNothing(): \Iterator { + yield 'absent file' => ['do_test/absent.png']; + yield 'absent derivative source' => ['styles/do_test_scale/public/do_test/absent.png']; + } + + /** + * Returns the URL a file in the public directory is served at. + */ + protected function publicUrl(string $relative): string { + $directory = $this->container->get('stream_wrapper_manager')->getViaScheme('public')->getDirectoryPath(); + + return '/' . $directory . '/' . $relative; + } + + /** + * Writes a PNG of known dimensions. + */ + protected function writeImage(string $uri): void { + $resource = imagecreatetruecolor(static::SOURCE_WIDTH, static::SOURCE_HEIGHT); + imagepng($resource, $this->container->get('file_system')->realpath($uri)); + imagedestroy($resource); + } + + /** + * Creates an image style that scales to a given width. + */ + protected function createScaleStyle(string $name, int $width): void { + $style = ImageStyle::create(['name' => $name, 'label' => $name]); + $style->addImageEffect([ + 'id' => 'image_scale', + 'data' => ['width' => $width, 'height' => NULL, 'upscale' => FALSE], + ]); + $style->save(); + } + +} diff --git a/web/modules/custom/do_base/tests/src/Kernel/MetatagsAlterHookTest.php b/web/modules/custom/do_base/tests/src/Kernel/MetatagsAlterHookTest.php index e26bcb63..d702608d 100644 --- a/web/modules/custom/do_base/tests/src/Kernel/MetatagsAlterHookTest.php +++ b/web/modules/custom/do_base/tests/src/Kernel/MetatagsAlterHookTest.php @@ -295,6 +295,78 @@ public function testSocialTextIsNotInventedWhenThereIsNone(): void { $this->assertArrayNotHasKey('twitter_cards_description', $metatags); } + /** + * Tests that an over-long description is cut to what a result shows. + */ + #[DataProvider('dataProviderLongDescriptionIsTrimmed')] + public function testLongDescriptionIsTrimmed(string $tag): void { + // Prepare. + $description = '[TEST] ' . str_repeat('word ', 60); + $attachments = $this->headAttachments([$tag => $description]); + + // Act. + $this->hook->trimDescriptions($attachments); + + // Assert. + $trimmed = $attachments['#attached']['html_head'][0][0]['#attributes']['content']; + $this->assertLessThanOrEqual(MetatagsAlterHook::DESCRIPTION_MAX_LENGTH, mb_strlen($trimmed)); + $this->assertStringEndsWith('…', $trimmed); + $this->assertStringStartsWith('[TEST] word', $trimmed); + } + + /** + * Data provider for testLongDescriptionIsTrimmed. + */ + public static function dataProviderLongDescriptionIsTrimmed(): \Iterator { + yield 'search result' => ['description']; + yield 'open graph' => ['og_description']; + yield 'twitter' => ['twitter_cards_description']; + } + + /** + * Tests that a description already short enough is left alone. + */ + public function testShortDescriptionIsLeftAlone(): void { + // Prepare. + $description = '[TEST] Short enough to show in full.'; + $attachments = $this->headAttachments(['description' => $description]); + + // Act. + $this->hook->trimDescriptions($attachments); + + // Assert. + $this->assertSame($description, $attachments['#attached']['html_head'][0][0]['#attributes']['content']); + } + + /** + * Tests that tags other than the descriptions are left alone. + */ + public function testOtherTagsAreLeftAlone(): void { + // Prepare. + $title = '[TEST] ' . str_repeat('word ', 60); + $attachments = $this->headAttachments(['title' => $title]); + + // Act. + $this->hook->trimDescriptions($attachments); + + // Assert. + $this->assertSame($title, $attachments['#attached']['html_head'][0][0]['#attributes']['content']); + } + + /** + * Tests that attachments carrying no head elements are handled. + */ + public function testAttachmentsWithoutHeadElementsAreHandled(): void { + // Prepare. + $attachments = []; + + // Act. + $this->hook->trimDescriptions($attachments); + + // Assert. + $this->assertSame([], $attachments); + } + /** * Tests that an article's structured data carries the resolved image. * @@ -352,6 +424,28 @@ protected function alter(array &$metatags, ?NodeInterface $node = NULL): void { $this->hook->alter($metatags, $context); } + /** + * Builds page attachments carrying one rendered meta tag per given value. + * + * @param array $tags + * Tag content keyed by metatag name. + * + * @return array + * The attachments, shaped as metatag hands them over. + */ + protected function headAttachments(array $tags): array { + $attachments = []; + + foreach ($tags as $name => $content) { + $attachments['#attached']['html_head'][] = [ + ['#tag' => 'meta', '#attributes' => ['name' => $name, 'content' => $content]], + $name, + ]; + } + + return $attachments; + } + /** * Asserts the tags carry the site-wide image rather than one of their own. */ From e8ef7aa556716b336201a38523dc110aaeda156a Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 10 Aug 2026 15:26:05 +1000 Subject: [PATCH 3/8] Tightened types on the image dimension resolver and metatag hook. --- web/modules/custom/do_base/do_base.deploy.php | 5 +++-- .../do_base/src/Hook/MetatagsAlterHook.php | 10 +++++----- .../src/Twig/ImageDimensionsExtension.php | 6 ++++-- .../src/Kernel/ImageDimensionsExtensionTest.php | 16 +++++++++++----- .../drevops/components/00-base/fonts/fonts.scss | 12 ++++++------ .../drevops/components/variables.base.scss | 1 - .../drevops/components/variables.components.scss | 1 - 7 files changed, 29 insertions(+), 22 deletions(-) diff --git a/web/modules/custom/do_base/do_base.deploy.php b/web/modules/custom/do_base/do_base.deploy.php index 87358f1c..a7cc9bfb 100644 --- a/web/modules/custom/do_base/do_base.deploy.php +++ b/web/modules/custom/do_base/do_base.deploy.php @@ -652,7 +652,7 @@ function do_base_deploy_set_seo_metatags(?array &$sandbox = NULL): ?string { $path = $alias === '/' ? (string) \Drupal::config('system.site')->get('page.front') : $alias_manager->getPathByAlias($alias); if (preg_match('#^/node/(\d+)$#', $path, $matches)) { - $nids[$matches[1]] = $alias; + $nids[(int) $matches[1]] = $alias; } } @@ -665,7 +665,8 @@ function do_base_deploy_set_seo_metatags(?array &$sandbox = NULL): ?string { $query = \Drupal::entityQuery('node')->condition('nid', array_keys($nids), 'IN'); return Helper::entity($sandbox, 10)->batchQuery($query, static function (NodeInterface $node) use ($nids, $overrides): void { - _do_base_set_seo_metatags($node, $overrides[$nids[$node->id()]] ?? []); + $alias = $nids[(int) $node->id()] ?? ''; + _do_base_set_seo_metatags($node, $overrides[$alias] ?? []); }); } diff --git a/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php b/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php index 2ae265b3..65d64e2c 100644 --- a/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php +++ b/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php @@ -25,12 +25,12 @@ final class MetatagsAlterHook { /** * The point past which a search result stops showing the description. */ - public const DESCRIPTION_MAX_LENGTH = 155; + public const int DESCRIPTION_MAX_LENGTH = 155; /** * The tags carrying that description. */ - protected const DESCRIPTION_TAGS = ['description', 'og_description', 'twitter_cards_description']; + private const array DESCRIPTION_TAGS = ['description', 'og_description', 'twitter_cards_description']; public function __construct( protected EntityTypeManagerInterface $entityTypeManager, @@ -58,17 +58,17 @@ public function trimDescriptions(array &$attachments): void { // still a token when the tags themselves are altered and only reaches its // full length here. foreach ($attachments['#attached']['html_head'] ?? [] as $delta => $element) { - if (!in_array($element[1] ?? '', static::DESCRIPTION_TAGS, TRUE)) { + if (!in_array($element[1] ?? '', self::DESCRIPTION_TAGS, TRUE)) { continue; } $content = $element[0]['#attributes']['content'] ?? NULL; - if (!is_string($content) || mb_strlen($content) <= static::DESCRIPTION_MAX_LENGTH) { + if (!is_string($content) || mb_strlen($content) <= self::DESCRIPTION_MAX_LENGTH) { continue; } - $attachments['#attached']['html_head'][$delta][0]['#attributes']['content'] = Unicode::truncate($content, static::DESCRIPTION_MAX_LENGTH, TRUE, TRUE); + $attachments['#attached']['html_head'][$delta][0]['#attributes']['content'] = Unicode::truncate($content, self::DESCRIPTION_MAX_LENGTH, TRUE, TRUE); } } diff --git a/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php b/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php index 212f76df..4840d9de 100644 --- a/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php +++ b/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php @@ -6,6 +6,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Image\ImageFactory; +use Drupal\Core\StreamWrapper\PublicStream; use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface; use Drupal\image\ImageStyleInterface; use Twig\Extension\AbstractExtension; @@ -55,9 +56,10 @@ public function dimensions(?string $url): array { return []; } - $public_path = $this->streamWrapperManager->getViaScheme('public')?->getDirectoryPath(); + $wrapper = $this->streamWrapperManager->getViaScheme('public'); + $public_path = $wrapper instanceof PublicStream ? $wrapper->getDirectoryPath() : ''; - if (!empty($public_path) && str_starts_with($path, $public_path . '/')) { + if ($public_path !== '' && str_starts_with($path, $public_path . '/')) { return $this->managedFile(urldecode(substr($path, strlen($public_path) + 1))); } diff --git a/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php b/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php index 9547bf36..ea04e7f0 100644 --- a/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php +++ b/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php @@ -5,6 +5,7 @@ namespace Drupal\Tests\do_base\Kernel; use Drupal\Core\File\FileSystemInterface; +use Drupal\Core\StreamWrapper\PublicStream; use Drupal\do_base\Twig\ImageDimensionsExtension; use Drupal\image\Entity\ImageStyle; use PHPUnit\Framework\Attributes\DataProvider; @@ -114,7 +115,8 @@ public function testQueryStringIsIgnored(): void { public function testVectorReportsItsViewBox(): void { // Prepare. $path = 'do_test_vector.svg'; - file_put_contents($this->container->getParameter('app.root') . '/' . $path, ''); + $file = \Drupal::root() . '/' . $path; + file_put_contents($file, ''); // Act. $dimensions = $this->extension->dimensions('/' . $path); @@ -122,7 +124,7 @@ public function testVectorReportsItsViewBox(): void { // Assert. $this->assertSame(['width' => 120, 'height' => 60], $dimensions); - unlink($this->container->getParameter('app.root') . '/' . $path); + unlink($file); } /** @@ -171,17 +173,21 @@ public static function dataProviderUnreadableManagedFileYieldsNothing(): \Iterat * Returns the URL a file in the public directory is served at. */ protected function publicUrl(string $relative): string { - $directory = $this->container->get('stream_wrapper_manager')->getViaScheme('public')->getDirectoryPath(); + $wrapper = $this->container->get('stream_wrapper_manager')->getViaScheme('public'); + $this->assertInstanceOf(PublicStream::class, $wrapper); - return '/' . $directory . '/' . $relative; + return '/' . $wrapper->getDirectoryPath() . '/' . $relative; } /** * Writes a PNG of known dimensions. */ protected function writeImage(string $uri): void { + $path = $this->container->get('file_system')->realpath($uri); + $this->assertIsString($path); + $resource = imagecreatetruecolor(static::SOURCE_WIDTH, static::SOURCE_HEIGHT); - imagepng($resource, $this->container->get('file_system')->realpath($uri)); + imagepng($resource, $path); imagedestroy($resource); } diff --git a/web/themes/custom/drevops/components/00-base/fonts/fonts.scss b/web/themes/custom/drevops/components/00-base/fonts/fonts.scss index edeeb750..71d3d846 100644 --- a/web/themes/custom/drevops/components/00-base/fonts/fonts.scss +++ b/web/themes/custom/drevops/components/00-base/fonts/fonts.scss @@ -7,7 +7,7 @@ // @font-face { - font-family: 'Lexend'; + font-family: Lexend; font-style: normal; font-weight: 100 900; font-display: swap; @@ -16,7 +16,7 @@ } @font-face { - font-family: 'Lexend'; + font-family: Lexend; font-style: normal; font-weight: 100 900; font-display: swap; @@ -25,7 +25,7 @@ } @font-face { - font-family: 'Rubik'; + font-family: Rubik; font-style: normal; font-weight: 300 900; font-display: swap; @@ -34,7 +34,7 @@ } @font-face { - font-family: 'Rubik'; + font-family: Rubik; font-style: normal; font-weight: 300 900; font-display: swap; @@ -43,7 +43,7 @@ } @font-face { - font-family: 'Rubik'; + font-family: Rubik; font-style: italic; font-weight: 300 900; font-display: swap; @@ -52,7 +52,7 @@ } @font-face { - font-family: 'Rubik'; + font-family: Rubik; font-style: italic; font-weight: 300 900; font-display: swap; diff --git a/web/themes/custom/drevops/components/variables.base.scss b/web/themes/custom/drevops/components/variables.base.scss index 50744dc7..4e36cd0d 100644 --- a/web/themes/custom/drevops/components/variables.base.scss +++ b/web/themes/custom/drevops/components/variables.base.scss @@ -21,7 +21,6 @@ $ct-colors-brands: ( 'brand3': #00698f, ) ); - $ct-colors: ( 'light': ( 'success': green, diff --git a/web/themes/custom/drevops/components/variables.components.scss b/web/themes/custom/drevops/components/variables.components.scss index e3bcc6e9..5d2b3b77 100644 --- a/web/themes/custom/drevops/components/variables.components.scss +++ b/web/themes/custom/drevops/components/variables.components.scss @@ -65,7 +65,6 @@ $ct-icon-sizes: ( 'm': (ct-particle-px(3.5), ct-particle-px(3.5)), ), ); - $ct-back-to-top-light-background-color: ct-color-light('custom1'); // From 9d044dce3d238010113570ff7ae1bdb002396af6 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 10 Aug 2026 15:50:12 +1000 Subject: [PATCH 4/8] Removed runtime description trimming in favour of authored values. A length rule applied at render time cuts mid-sentence and produces a tag nobody wrote. Descriptions now come only from the values 'do_base_deploy_set_seo_metatags()' writes into 'field_n_metatags', which covers every page the audit found with a missing or over-long one. The CSP scenario asserted that 'fonts.gstatic.com' was still allowed, which self-hosting the faces deliberately changed. It now asserts the opposite, alongside a note that there is no 'font-src' directive to check because the module omits one matching 'default-src'. --- docs/seo.md | 8 +- tests/behat/features/csp.feature | 13 ++- tests/behat/features/metatags.feature | 14 --- web/modules/custom/do_base/do_base.deploy.php | 4 +- .../do_base/src/Hook/MetatagsAlterHook.php | 34 ------- .../src/Kernel/MetatagsAlterHookTest.php | 94 ------------------- 6 files changed, 19 insertions(+), 148 deletions(-) diff --git a/docs/seo.md b/docs/seo.md index bafbcd84..15126f8a 100644 --- a/docs/seo.md +++ b/docs/seo.md @@ -57,14 +57,16 @@ The `Article` image in the structured data is filled from the same resolved valu ## Title and description length -A search result shows roughly 60 characters of the title and 155 of the description, and cuts whatever is past that. Two things keep the tags inside those bounds. +A search result shows roughly 60 characters of the title and 155 of the description, and cuts whatever is past that. -`MetatagsAlterHook::trimDescriptions()` cuts `description`, `og:description` and `twitter:description` to 155 characters on a word boundary. It runs on `hook_metatags_attachments_alter()` rather than `hook_metatags_alter()`, because tokens are still unreplaced when the tags themselves are altered: at that point a description is the literal `[node:field_c_n_summary:value]` and there is nothing to measure. All three tags get the same treatment so the wording stays identical wherever it appears. +Nothing trims a tag at render time. A description cut by a rule rather than by an author breaks mid-sentence and reads worse than a description written to fit, and the tag it produces is nobody's wording. Pages that need a shorter or a different one carry it explicitly in `field_n_metatags`, written by `do_base_deploy_set_seo_metatags()` from the values in `_do_base_seo_metatags()`. -That is a floor, not a substitute for writing to length. Pages whose derived wording was too long, too short, or missing carry an explicit value in `field_n_metatags`, written once by `do_base_deploy_set_seo_metatags()`. The hook replaces a tag only when the value it finds falls outside those bounds, so wording an editor writes later is left alone and a repeat deployment is a no-op. +That hook replaces a tag only when the value it finds falls outside the lengths above, so wording an editor writes later is left alone and a repeat deployment is a no-op. Everything it writes is inside those lengths, which is what makes the second run do nothing. The titles it writes carry qualifiers the visible heading does not need: a page headed `GovCMS` is titled `GovCMS Development and Migration`, because the heading has a whole page for context and a search result has one line. They use `[site:name]` rather than a literal brand, matching the `node` default they replace. +A page not listed there falls back to `[node:field_c_n_summary:value]`, which is as long as the summary an editor wrote. Adding a page to `_do_base_seo_metatags()` is the way to fix that, and it is worth checking a new page's rendered description against 155 characters rather than assuming the summary happens to fit. + ## Image assets Both live in `web/modules/custom/do_base/assets/` and are generated from the theme's brand assets: diff --git a/tests/behat/features/csp.feature b/tests/behat/features/csp.feature index 09d046fd..58cb81f5 100644 --- a/tests/behat/features/csp.feature +++ b/tests/behat/features/csp.feature @@ -33,5 +33,16 @@ Feature: Content Security Policy And the response header "Content-Security-Policy" should contain the value "https://www.googletagmanager.com" And the response header "Content-Security-Policy" should contain the value "https://www.recaptcha.net" And the response header "Content-Security-Policy" should contain the value "https://www.youtube.com" - And the response header "Content-Security-Policy" should contain the value "https://fonts.gstatic.com" And the response header "Content-Security-Policy" should contain the value "https://www.google-analytics.com" + + @api + Scenario: CSP allows no external font source + Given I am an anonymous user + When I go to the homepage + Then the response status code should be 200 + # Both faces are served from this origin, so a policy that still reaches + # out to Google is one a stylesheet could quietly start using again. There + # is no "font-src" to assert: the module omits a directive that matches + # "default-src", so fonts fall through to the "'self'" asserted above. + And the response header "Content-Security-Policy" should not contain the value "https://fonts.gstatic.com" + And the response header "Content-Security-Policy" should not contain the value "https://fonts.googleapis.com" diff --git a/tests/behat/features/metatags.feature b/tests/behat/features/metatags.feature index affcd62f..df38df28 100644 --- a/tests/behat/features/metatags.feature +++ b/tests/behat/features/metatags.feature @@ -62,20 +62,6 @@ Feature: Page content metatags And the response should contain "get('name'), $value)); + // The lengths a search result shows before it cuts the value off. return match ($tag) { 'title' => $length >= 30 && $length <= 60, - 'description' => $length >= 70 && $length <= MetatagsAlterHook::DESCRIPTION_MAX_LENGTH, + 'description' => $length >= 70 && $length <= 155, default => TRUE, }; } diff --git a/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php b/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php index 65d64e2c..f3bcf6f7 100644 --- a/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php +++ b/web/modules/custom/do_base/src/Hook/MetatagsAlterHook.php @@ -4,7 +4,6 @@ namespace Drupal\do_base\Hook; -use Drupal\Component\Utility\Unicode; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -22,16 +21,6 @@ */ final class MetatagsAlterHook { - /** - * The point past which a search result stops showing the description. - */ - public const int DESCRIPTION_MAX_LENGTH = 155; - - /** - * The tags carrying that description. - */ - private const array DESCRIPTION_TAGS = ['description', 'og_description', 'twitter_cards_description']; - public function __construct( protected EntityTypeManagerInterface $entityTypeManager, protected ConfigFactoryInterface $configFactory, @@ -49,29 +38,6 @@ public function alter(array &$metatags, array &$context): void { $this->setSocialImage($metatags, $entity instanceof ContentEntityInterface ? $entity : NULL); } - /** - * Implements hook_metatags_attachments_alter(). - */ - #[Hook('metatags_attachments_alter')] - public function trimDescriptions(array &$attachments): void { - // Tokens are replaced after hook_metatags_alter(), so a description is - // still a token when the tags themselves are altered and only reaches its - // full length here. - foreach ($attachments['#attached']['html_head'] ?? [] as $delta => $element) { - if (!in_array($element[1] ?? '', self::DESCRIPTION_TAGS, TRUE)) { - continue; - } - - $content = $element[0]['#attributes']['content'] ?? NULL; - - if (!is_string($content) || mb_strlen($content) <= self::DESCRIPTION_MAX_LENGTH) { - continue; - } - - $attachments['#attached']['html_head'][$delta][0]['#attributes']['content'] = Unicode::truncate($content, self::DESCRIPTION_MAX_LENGTH, TRUE, TRUE); - } - } - /** * Gives the social tags the page title and description when they have none. */ diff --git a/web/modules/custom/do_base/tests/src/Kernel/MetatagsAlterHookTest.php b/web/modules/custom/do_base/tests/src/Kernel/MetatagsAlterHookTest.php index d702608d..e26bcb63 100644 --- a/web/modules/custom/do_base/tests/src/Kernel/MetatagsAlterHookTest.php +++ b/web/modules/custom/do_base/tests/src/Kernel/MetatagsAlterHookTest.php @@ -295,78 +295,6 @@ public function testSocialTextIsNotInventedWhenThereIsNone(): void { $this->assertArrayNotHasKey('twitter_cards_description', $metatags); } - /** - * Tests that an over-long description is cut to what a result shows. - */ - #[DataProvider('dataProviderLongDescriptionIsTrimmed')] - public function testLongDescriptionIsTrimmed(string $tag): void { - // Prepare. - $description = '[TEST] ' . str_repeat('word ', 60); - $attachments = $this->headAttachments([$tag => $description]); - - // Act. - $this->hook->trimDescriptions($attachments); - - // Assert. - $trimmed = $attachments['#attached']['html_head'][0][0]['#attributes']['content']; - $this->assertLessThanOrEqual(MetatagsAlterHook::DESCRIPTION_MAX_LENGTH, mb_strlen($trimmed)); - $this->assertStringEndsWith('…', $trimmed); - $this->assertStringStartsWith('[TEST] word', $trimmed); - } - - /** - * Data provider for testLongDescriptionIsTrimmed. - */ - public static function dataProviderLongDescriptionIsTrimmed(): \Iterator { - yield 'search result' => ['description']; - yield 'open graph' => ['og_description']; - yield 'twitter' => ['twitter_cards_description']; - } - - /** - * Tests that a description already short enough is left alone. - */ - public function testShortDescriptionIsLeftAlone(): void { - // Prepare. - $description = '[TEST] Short enough to show in full.'; - $attachments = $this->headAttachments(['description' => $description]); - - // Act. - $this->hook->trimDescriptions($attachments); - - // Assert. - $this->assertSame($description, $attachments['#attached']['html_head'][0][0]['#attributes']['content']); - } - - /** - * Tests that tags other than the descriptions are left alone. - */ - public function testOtherTagsAreLeftAlone(): void { - // Prepare. - $title = '[TEST] ' . str_repeat('word ', 60); - $attachments = $this->headAttachments(['title' => $title]); - - // Act. - $this->hook->trimDescriptions($attachments); - - // Assert. - $this->assertSame($title, $attachments['#attached']['html_head'][0][0]['#attributes']['content']); - } - - /** - * Tests that attachments carrying no head elements are handled. - */ - public function testAttachmentsWithoutHeadElementsAreHandled(): void { - // Prepare. - $attachments = []; - - // Act. - $this->hook->trimDescriptions($attachments); - - // Assert. - $this->assertSame([], $attachments); - } - /** * Tests that an article's structured data carries the resolved image. * @@ -424,28 +352,6 @@ protected function alter(array &$metatags, ?NodeInterface $node = NULL): void { $this->hook->alter($metatags, $context); } - /** - * Builds page attachments carrying one rendered meta tag per given value. - * - * @param array $tags - * Tag content keyed by metatag name. - * - * @return array - * The attachments, shaped as metatag hands them over. - */ - protected function headAttachments(array $tags): array { - $attachments = []; - - foreach ($tags as $name => $content) { - $attachments['#attached']['html_head'][] = [ - ['#tag' => 'meta', '#attributes' => ['name' => $name, 'content' => $content]], - $name, - ]; - } - - return $attachments; - } - /** * Asserts the tags carry the site-wide image rather than one of their own. */ From e49e3318459d9dc2301c2e5cd99b495117f85fc2 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 10 Aug 2026 16:12:24 +1000 Subject: [PATCH 5/8] Addressed code review: token-aware length check, cached and contained dimension lookup. The length check measured a stored value verbatim and resolved only 'site:name', so an override written as a token pattern could be replaced despite rendering to a valid length. It now resolves against the node. The dimension resolver reopened the same file for every repeat of an image on a page, and joined a URL path onto the application root without checking the result stayed beneath it. Both are fixed, and the converted-derivative test now configures the convert effect it claims to exercise rather than relying on the source-path fallback. --- web/modules/custom/do_base/do_base.deploy.php | 10 +++++-- .../src/Twig/ImageDimensionsExtension.php | 28 ++++++++++++++++--- .../Kernel/ImageDimensionsExtensionTest.php | 18 ++++++++++-- .../mobile-navigation-trigger.component.yml | 4 +++ .../03-organisms/promo/promo.component.yml | 4 +++ 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/web/modules/custom/do_base/do_base.deploy.php b/web/modules/custom/do_base/do_base.deploy.php index cb72d23e..93b88f93 100644 --- a/web/modules/custom/do_base/do_base.deploy.php +++ b/web/modules/custom/do_base/do_base.deploy.php @@ -870,7 +870,7 @@ function _do_base_set_seo_metatags(NodeInterface $node, array $tags): void { // Wording already inside the length a result shows is left alone, whoever // wrote it. That also makes a repeat deployment a no-op, since everything // written here is inside those bounds. - if (isset($current[$tag]) && _do_base_seo_metatag_fits($tag, (string) $current[$tag])) { + if (isset($current[$tag]) && _do_base_seo_metatag_fits($tag, (string) $current[$tag], $node)) { continue; } @@ -896,12 +896,16 @@ function _do_base_set_seo_metatags(NodeInterface $node, array $tags): void { * The metatag name. * @param string $value * The value, which may still carry tokens. + * @param \Drupal\node\NodeInterface $node + * The node the value belongs to, giving its tokens something to resolve + * against. A value is measured rendered, because that is the length a + * search result has to fit. * * @return bool * TRUE when the value needs no replacing. */ -function _do_base_seo_metatag_fits(string $tag, string $value): bool { - $length = mb_strlen(str_replace('[site:name]', (string) \Drupal::config('system.site')->get('name'), $value)); +function _do_base_seo_metatag_fits(string $tag, string $value, NodeInterface $node): bool { + $length = mb_strlen(\Drupal::token()->replace($value, ['node' => $node], ['clear' => TRUE])); // The lengths a search result shows before it cuts the value off. return match ($tag) { diff --git a/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php b/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php index 4840d9de..1b3b38bf 100644 --- a/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php +++ b/web/modules/custom/do_base/src/Twig/ImageDimensionsExtension.php @@ -20,6 +20,13 @@ */ final class ImageDimensionsExtension extends AbstractExtension { + /** + * Dimensions already resolved this request, keyed by path. + * + * @var array> + */ + protected array $resolved = []; + public function __construct( private readonly ImageFactory $imageFactory, private readonly StreamWrapperManagerInterface $streamWrapperManager, @@ -80,6 +87,13 @@ public function dimensions(?string $url): array { * Associative array of 'width' and 'height', or empty. */ protected function managedFile(string $relative): array { + // A listing renders the same image style over and over, and each miss here + // costs opening and parsing a file. + if (isset($this->resolved[$relative])) { + return $this->resolved[$relative]; + } + + $key = $relative; $style = NULL; if (preg_match('~^styles/([^/]+)/[^/]+/(.+)$~', $relative, $matches) === 1) { @@ -110,13 +124,13 @@ protected function managedFile(string $relative): array { } if (empty($dimensions['width']) || empty($dimensions['height'])) { - return []; + return $this->resolved[$key] = []; } - return $dimensions; + return $this->resolved[$key] = $dimensions; } - return []; + return $this->resolved[$key] = []; } /** @@ -137,7 +151,13 @@ protected function vector(string $path): array { return []; } - $file = $this->appRoot . '/' . $path; + // A path is only ever read once it is known to sit under the application + // root, so that a traversal in the URL cannot reach a file outside it. + $file = realpath($this->appRoot . '/' . $path); + if ($file === FALSE || !str_starts_with($file, $this->appRoot . '/')) { + return []; + } + if (!is_file($file) || !is_readable($file)) { return []; } diff --git a/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php b/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php index ea04e7f0..b4061ef7 100644 --- a/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php +++ b/web/modules/custom/do_base/tests/src/Kernel/ImageDimensionsExtensionTest.php @@ -89,7 +89,7 @@ public function testDerivativeReportsTheStyleDimensions(): void { */ public function testConvertedDerivativeIsTracedToItsSource(): void { // Prepare. - $this->createScaleStyle('do_test_convert', 200); + $this->createScaleStyle('do_test_convert', 200, 'webp'); // Act. $dimensions = $this->extension->dimensions($this->publicUrl('styles/do_test_convert/public/do_test/source.png.webp')); @@ -193,13 +193,25 @@ protected function writeImage(string $uri): void { /** * Creates an image style that scales to a given width. - */ - protected function createScaleStyle(string $name, int $width): void { + * + * @param string $name + * Machine name of the style. + * @param int $width + * Width to scale to. + * @param string|null $extension + * Extension to convert to, or NULL to leave the format alone. + */ + protected function createScaleStyle(string $name, int $width, ?string $extension = NULL): void { $style = ImageStyle::create(['name' => $name, 'label' => $name]); $style->addImageEffect([ 'id' => 'image_scale', 'data' => ['width' => $width, 'height' => NULL, 'upscale' => FALSE], ]); + + if ($extension !== NULL) { + $style->addImageEffect(['id' => 'image_convert', 'data' => ['extension' => $extension]]); + } + $style->save(); } diff --git a/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.component.yml b/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.component.yml index a96c5701..03b45d9b 100644 --- a/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.component.yml +++ b/web/themes/custom/drevops/components/03-organisms/mobile-navigation/mobile-navigation-trigger.component.yml @@ -26,3 +26,7 @@ props: type: string title: Modifier Class description: Additional CSS classes. + attributes: + type: Drupal\Core\Template\Attribute + title: Attributes + description: Additional HTML attributes. diff --git a/web/themes/custom/drevops/components/03-organisms/promo/promo.component.yml b/web/themes/custom/drevops/components/03-organisms/promo/promo.component.yml index 0bd92409..67c61e3a 100644 --- a/web/themes/custom/drevops/components/03-organisms/promo/promo.component.yml +++ b/web/themes/custom/drevops/components/03-organisms/promo/promo.component.yml @@ -34,6 +34,10 @@ props: type: string title: Modifier Class description: Additional CSS classes. + attributes: + type: Drupal\Core\Template\Attribute + title: Attributes + description: Additional HTML attributes. link: type: object title: Link From 2f85cbfc758e8f123c93396b2ef832aa77539199 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 10 Aug 2026 16:47:09 +1000 Subject: [PATCH 6/8] Restored the stylesheets the overridden components ship. A component library is built from the files in that component's own directory, so pointing 'replaces:' at an override carrying only a template left the promo and the pager with correct markup and no CSS at all. The promo band lost its background and rendered near-white text on white. Both overrides now carry the stylesheet alongside the template. 'image' and 'mobile-navigation-trigger' have none upstream and are unaffected. --- docs/performance.md | 4 + .../02-molecules/pagination/pagination.scss | 103 ++++++++++++++++++ .../components/03-organisms/promo/promo.scss | 65 +++++++++++ 3 files changed, 172 insertions(+) create mode 100644 web/themes/custom/drevops/components/02-molecules/pagination/pagination.scss create mode 100644 web/themes/custom/drevops/components/03-organisms/promo/promo.scss diff --git a/docs/performance.md b/docs/performance.md index d61e5b01..4d283892 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -38,6 +38,10 @@ replaces: civictheme:image Without it the theme's version is simply never used, and the rendered markup keeps saying `data-component-id="civictheme:image"`. +**Copy the component's stylesheet along with its template.** A component's library is built from the files sitting in its own directory, so once `replaces:` points rendering at the override, the original's `.scss` is no longer part of what loads. An override carrying only a `.twig` renders the right markup with none of the component's CSS, which reads as the component being unstyled rather than as a missing file. `promo` and `pagination` both have one; `image` and `mobile-navigation-trigger` do not. + +Checking the markup is not enough to catch this, because the markup is correct. Compare a computed style against the same element on production, or look at the page. + ## Fonts are served from this origin Lexend and Rubik ship in `assets/fonts/` and are declared in `components/00-base/fonts/fonts.scss`. Nothing is fetched from `fonts.googleapis.com`, which is why the CSP no longer allows it. diff --git a/web/themes/custom/drevops/components/02-molecules/pagination/pagination.scss b/web/themes/custom/drevops/components/02-molecules/pagination/pagination.scss new file mode 100644 index 00000000..70d6bceb --- /dev/null +++ b/web/themes/custom/drevops/components/02-molecules/pagination/pagination.scss @@ -0,0 +1,103 @@ +// +// CivicTheme Pagination component styles. +// + +.ct-pagination { + $root: &; + + @include ct-typography('label-regular'); + + & { + display: flex; + align-items: center; + flex-wrap: wrap; + justify-content: center; + width: auto; + border-top-width: ct-particle(0.125); + border-top-style: solid; + padding: ct-spacing(3); + box-sizing: border-box; + } + + @include ct-breakpoint(m) { + width: 100%; + border-bottom-width: ct-particle(0.125); + border-bottom-style: solid; + } + + #{$root}__items_per_page { + position: relative; + display: flex; + justify-content: center; + width: 100%; + margin-bottom: ct-spacing(4); + + @include ct-breakpoint(m) { + width: auto; + margin-bottom: 0; + } + } + + #{$root}__items_per_page__field { + align-self: center; + margin-bottom: 0; + white-space: nowrap; + } + + #{$root}__items_per_page__select { + min-width: ct-particle(10); + margin-left: ct-spacing(); + padding: 0 ct-spacing(2) 0 ct-spacing(2); + } + + #{$root}__items { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: center; + + @include ct-breakpoint(m) { + margin-left: auto; + } + } + + #{$root}__item--ellipsis { + padding: 0 ct-spacing(); + text-align: center; + } + + #{$root}__item--first, + #{$root}__item--previous { + padding: 0 ct-spacing(1) 0 0; + + @include ct-breakpoint(m) { + padding: 0 ct-spacing(2) 0 0; + } + } + + #{$root}__item--next, + #{$root}__item--last { + padding: 0 0 0 ct-spacing(1); + + @include ct-breakpoint(m) { + padding: 0 0 0 ct-spacing(2); + } + } + + #{$root}__item__link { + padding: 0 ct-spacing(); + white-space: nowrap; + } + + @include ct-component-theme($root) using($root, $theme) { + @include ct-component-property($root, $theme, color); + + & { + border-top-color: ct-component-var($root, $theme, border-color); + border-bottom-color: ct-component-var($root, $theme, border-color); + } + } +} diff --git a/web/themes/custom/drevops/components/03-organisms/promo/promo.scss b/web/themes/custom/drevops/components/03-organisms/promo/promo.scss new file mode 100644 index 00000000..e2f73c14 --- /dev/null +++ b/web/themes/custom/drevops/components/03-organisms/promo/promo.scss @@ -0,0 +1,65 @@ +// +// CivicTheme Promo component styles. +// + +.ct-promo { + $root: &; + + &#{$root}--with-background { + @include ct-breakpoint(m) { + padding-left: var(--ct-promo-space-horizontal); + padding-right: var(--ct-promo-space-horizontal); + } + } + + & { + border-top: solid ct-particle(0.125); + border-bottom: solid ct-particle(0.125); + } + + &__wrapper { + padding: ct-spacing(3) 0; + + @include ct-breakpoint(m) { + padding: ct-spacing(7) 0; + display: flex; + align-items: center; + } + } + + &__inner { + @include ct-breakpoint(m) { + flex-grow: 1; + padding-right: ct-spacing(5); + } + } + + &__links { + margin-top: ct-spacing(3); + + @include ct-breakpoint(m) { + margin-top: 0; + } + } + + &__title { + margin-bottom: ct-spacing(1); + } + + &__content { + margin-left: auto; + } + + &__button { + width: auto; + + @include ct-breakpoint(m) { + white-space: nowrap; + } + } + + @include ct-component-theme($root) using($root, $theme) { + @include ct-component-property($root, $theme, background-color); + @include ct-component-property($root, $theme, border-color); + } +} From 8ae9041f9e3a6890fc371b994ce6d2966dcd8f93 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 10 Aug 2026 16:54:28 +1000 Subject: [PATCH 7/8] Left the primary navigation untouched. Withdrew the deploy hook that added navigation links for the two pages nothing links to, along with the helpers only it used. Site chrome is outside what this change set covers, so the two pages stay reachable only from the sitemap. --- web/modules/custom/do_base/do_base.deploy.php | 66 ------------------- 1 file changed, 66 deletions(-) diff --git a/web/modules/custom/do_base/do_base.deploy.php b/web/modules/custom/do_base/do_base.deploy.php index 93b88f93..8bfc4390 100644 --- a/web/modules/custom/do_base/do_base.deploy.php +++ b/web/modules/custom/do_base/do_base.deploy.php @@ -614,24 +614,6 @@ function do_base_deploy_realias_blog_posts(?array &$sandbox = NULL): ?string { }, status: Reporter::UPDATED); } -/** - * Adds primary navigation links for pages nothing links to. - */ -function do_base_deploy_relink_orphan_pages(): string { - $menu_name = 'civictheme-primary-navigation'; - - $pages = [ - 'How we work' => '/how-we-work', - 'AI integration & automation' => '/ai-integration-automation', - ]; - - foreach ($pages as $title => $alias) { - _do_base_menu_link_alias($menu_name, $title, $alias); - } - - return Helper::report(); -} - /** * Sets the search result title and description on the pages that need one. * @@ -1038,54 +1020,6 @@ function _do_base_seo_metatags(): array { ]; } -/** - * Returns a weight that sorts behind every top-level link in a menu. - */ -function _do_base_menu_trailing_weight(string $menu_name): int { - $links = \Drupal::entityTypeManager()->getStorage('menu_link_content')->loadByProperties(['menu_name' => $menu_name]); - - // Seeded so that a menu with no top-level links still yields a weight. - $weights = [0]; - - foreach ($links as $link) { - if ($link instanceof MenuLinkContentInterface && $link->getParentId() === '') { - $weights[] = $link->getWeight(); - } - } - - return max($weights) + 1; -} - -/** - * Adds a menu link to the page behind an alias. - */ -function _do_base_menu_link_alias(string $menu_name, string $title, string $alias): void { - if (Helper::menu()->findItem($menu_name, ['title' => $title]) instanceof MenuLinkContentInterface) { - Helper::reporter()->skipped(sprintf('The "%s" link already exists.', $title)); - - return; - } - - $path = \Drupal::service('path_alias.manager')->getPathByAlias($alias); - - if (!preg_match('#^/node/(\d+)$#', $path, $matches)) { - Helper::reporter()->skipped(sprintf('No node is aliased to "%s".', $alias)); - - return; - } - - // createTree() numbers links from their position in the tree it is handed, - // which describes this link alone and so says nothing about where it belongs - // among the links already in the menu. Reading the weight first keeps the - // link being created out of its own calculation. - $weight = _do_base_menu_trailing_weight($menu_name); - - Helper::menu()->createTree($menu_name, [$title => 'entity:node/' . $matches[1]]); - Helper::menu()->updateItem($menu_name, ['title' => $title], ['weight' => $weight]); - - Helper::reporter()->created(sprintf('Created the "%s" link.', $title)); -} - /** * Regenerates the alias of the blog post a path alias points at. */ From 7de5d340902a68f818e2b2613b7ff776c6c943b3 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Mon, 10 Aug 2026 17:11:55 +1000 Subject: [PATCH 8/8] Addressed code review: measured metatag length as plain text. Token::replace() escapes its values for HTML, so a title carrying an ampersand measured five characters longer than it displays. 'CI/CD Pipelines & Automation' is a real title on this site, so the inflated length could push a perfectly good value outside the bounds and have it replaced. --- web/modules/custom/do_base/do_base.deploy.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/modules/custom/do_base/do_base.deploy.php b/web/modules/custom/do_base/do_base.deploy.php index 8bfc4390..07116021 100644 --- a/web/modules/custom/do_base/do_base.deploy.php +++ b/web/modules/custom/do_base/do_base.deploy.php @@ -887,7 +887,9 @@ function _do_base_set_seo_metatags(NodeInterface $node, array $tags): void { * TRUE when the value needs no replacing. */ function _do_base_seo_metatag_fits(string $tag, string $value, NodeInterface $node): bool { - $length = mb_strlen(\Drupal::token()->replace($value, ['node' => $node], ['clear' => TRUE])); + // Plain, because a search result shows characters rather than markup: an + // escaped ampersand would otherwise count as five. + $length = mb_strlen(\Drupal::token()->replacePlain($value, ['node' => $node], ['clear' => TRUE])); // The lengths a search result shows before it cuts the value off. return match ($tag) {