From 6e79b59f2bdaa8bac21865c9702eac6edc7b1091 Mon Sep 17 00:00:00 2001 From: Bhushan Palsapure Date: Fri, 17 Jul 2026 13:03:53 +0100 Subject: [PATCH 1/2] chore: Update vf-hero component for optimised responsive image delivery and performance --- components/vf-hero/CHANGELOG.md | 8 +++ components/vf-hero/README.md | 37 ++++++++++++-- .../vf-hero/vf-hero.angular.component.ts | 27 ++++++++++ .../lib/vf-hero.angular.component.d.ts | 12 ++++- .../lib/vf-hero.angular.component.spec.ts | 18 +++++++ components/vf-hero/vf-hero.config.yml | 36 +++++++++++++- components/vf-hero/vf-hero.njk | 28 ++++++++++- components/vf-hero/vf-hero.react.js | 49 +++++++++++++++++-- components/vf-hero/vf-hero.react.test.js | 22 +++++++++ components/vf-hero/vf-hero.scss | 20 ++++++++ 10 files changed, 247 insertions(+), 10 deletions(-) diff --git a/components/vf-hero/CHANGELOG.md b/components/vf-hero/CHANGELOG.md index dd20f50c73..9eb9d90328 100755 --- a/components/vf-hero/CHANGELOG.md +++ b/components/vf-hero/CHANGELOG.md @@ -1,3 +1,11 @@ +### 4.0.8 + +* Changed: Update vf-hero component for optimised responsive image delivery and performance [Tracking issue](https://github.com/visual-framework/vf-core/issues/2405) + +### 4.0.7 + +* Changed: Documentation updated [Tracking issue](https://github.com/visual-framework/vf-core/issues/2392) + ### 4.0.6 * Changed: Test cases added for React [Tracking issue](https://github.com/visual-framework/vf-core/issues/2174) diff --git a/components/vf-hero/README.md b/components/vf-hero/README.md index cec2dacc41..6026e38e5e 100755 --- a/components/vf-hero/README.md +++ b/components/vf-hero/README.md @@ -14,7 +14,8 @@ By default the `vf-hero` makes use of the roundels background image. To keep the You can bring your own image to use with the vf-hero. -- Size: recommended image size for a typical hero is 3000 by 1000 pixels. +- Size: Image size should be below 500KB +- Format: WebP or AVIF provide better image quality at smaller file sizes - Positioning: people and other important imagery should be placed on the right side. The image will, by default, vertically centre and align to the right side. - Imagery: most of the image should be abstract as to not visually compete with the text in the hero box. - Text: do not use raster text as part of the image. @@ -43,6 +44,15 @@ You can bring your own image to use with the vf-hero. | Text | `vf_hero_text` | `vf-hero__text` | | Link Text | `vf_hero_link_text` | `vf-hero__link` | | Link HREF | `vf_hero_link_href` | n/a | +| Image Mobile | `vf_hero_image_mobile_src` | `vf-hero__image` | +| Image Desktop | `vf_hero_image_src` | `vf-hero__image` | +| Image Large | `vf_hero_image_large_src` | `vf-hero__image` | +| Image Width | `vf_hero_image_width` | `vf-hero__image` | +| Image Height | `vf_hero_image_height` | `vf-hero__image` | +| Image Priority | `vf_hero_image_fetchpriority` | `vf-hero__image` | +| Image Loading | `vf_hero_image_loading` | `vf-hero__image` | +| Image Sizes | `vf_hero_image_sizes` | `vf-hero__image` | +| Image Alt | `vf_hero_image_alt` | `vf-hero__image` | ### CSS Custom Properties @@ -82,7 +92,14 @@ This package was generated with Angular version 15.2.0 and has been tested on ap [vf_hero_text]="['The Hentze group combines biochemical and systems–level approaches to investigate the connections between gene expression and cell metabolism, and their roles in human disease.']" [vf_hero_link_text]="'Learn more'" [vf_hero_link_href]="'JavaScript:Void(0);'" - [vf_hero_image_size]="'auto 28.5rem'"> + [vf_hero_image_size]="'auto 28.5rem'" + [vf_hero_image_mobile_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg'" + [vf_hero_image_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg'" + [vf_hero_image_large_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg'" + [vf_hero_image_width]="'1920'" + [vf_hero_image_height]="'1080'" + [vf_hero_image_fetchpriority]="'high'" + [vf_hero_image_loading]="'eager'"> ``` 4. add to your styles.scss @@ -106,7 +123,14 @@ Usage: [vf_hero_text]="['The Hentze group combines biochemical and systems–level approaches to investigate the connections between gene expression and cell metabolism, and their roles in human disease.']" [vf_hero_link_text]="'Learn more'" [vf_hero_link_href]="'JavaScript:Void(0);'" - [vf_hero_image_size]="'auto 28.5rem'"> + [vf_hero_image_size]="'auto 28.5rem'" + [vf_hero_image_mobile_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg'" + [vf_hero_image_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg'" + [vf_hero_image_large_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg'" + [vf_hero_image_width]="'1920'" + [vf_hero_image_height]="'1080'" + [vf_hero_image_fetchpriority]="'high'" + [vf_hero_image_loading]="'eager'"> ``` @@ -133,6 +157,13 @@ As of version 4.0.0-alpha.2 vf-hero has experimental React support which has bee vf_hero_link_text="Learn more" vf_hero_link_href="'JavaScript:Void(0);'" vf_hero_image_size="auto 28.5rem" + vf_hero_image_mobile_src="https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg" + vf_hero_image_src="https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg" + vf_hero_image_large_src="https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg" + vf_hero_image_width="1920" + vf_hero_image_height="1080" + vf_hero_image_fetchpriority="high" + vf_hero_image_loading="eager" /> ``` 4. Styling changes diff --git a/components/vf-hero/vf-hero.angular.component.ts b/components/vf-hero/vf-hero.angular.component.ts index cce9e58cdf..c6273f43f3 100644 --- a/components/vf-hero/vf-hero.angular.component.ts +++ b/components/vf-hero/vf-hero.angular.component.ts @@ -5,6 +5,20 @@ import { Component, Input, OnInit } from "@angular/core"; selector: "vf-hero", template: `
+ + + + +

@@ -33,6 +47,15 @@ export class VfHeroAngularComponent implements OnInit { /* Initialize values based on input values */ @Input() vf_hero_image = ''; @Input() vf_hero_image_size = ''; + @Input() vf_hero_image_src = ''; + @Input() vf_hero_image_mobile_src = ''; + @Input() vf_hero_image_large_src = ''; + @Input() vf_hero_image_alt = ''; + @Input() vf_hero_image_width = ''; + @Input() vf_hero_image_height = ''; + @Input() vf_hero_image_fetchpriority = ''; + @Input() vf_hero_image_loading = ''; + @Input() vf_hero_image_sizes = ''; @Input() vf_hero_kicker = ''; @Input() vf_hero_heading = ''; @Input() vf_hero_heading_href = ''; @@ -47,6 +70,7 @@ export class VfHeroAngularComponent implements OnInit { class = ''; style = ''; + hasResponsiveMedia = false; vf_hero_link_innerhtml = ''; ngOnInit(): void { @@ -62,6 +86,7 @@ export class VfHeroAngularComponent implements OnInit { /* Initialize/Reset the values for class and style */ this.class = 'vf-hero '; this.style = ''; + this.hasResponsiveMedia = false; if (this.vf_hero_heading_additional !== '') { this.vf_hero_kicker = this.vf_hero_heading_additional; @@ -69,6 +94,8 @@ export class VfHeroAngularComponent implements OnInit { /* Set values ass per the input */ this.class += this.spacing !== undefined ? 'vf-hero--' + this.spacing + ' ' : ''; + this.hasResponsiveMedia = this.vf_hero_image_src !== '' || this.vf_hero_image_mobile_src !== '' || this.vf_hero_image_large_src !== ''; + this.class += this.hasResponsiveMedia ? 'vf-hero--has-media ' : ''; this.class += '| vf-u-fullbleed'; this.class += this.modifier_class !== '' ? ' ' + this.modifier_class : ''; this.style += this.vf_hero_image !== '' ? '--vf-hero--bg-image: ' + this.vf_hero_image : ''; diff --git a/components/vf-hero/vf-hero.angular/lib/vf-hero.angular.component.d.ts b/components/vf-hero/vf-hero.angular/lib/vf-hero.angular.component.d.ts index ebe48a7cc4..9547eb3954 100644 --- a/components/vf-hero/vf-hero.angular/lib/vf-hero.angular.component.d.ts +++ b/components/vf-hero/vf-hero.angular/lib/vf-hero.angular.component.d.ts @@ -3,6 +3,15 @@ import * as i0 from "@angular/core"; export declare class VfHeroAngularComponent implements OnInit { vf_hero_image: string; vf_hero_image_size: string; + vf_hero_image_src: string; + vf_hero_image_mobile_src: string; + vf_hero_image_large_src: string; + vf_hero_image_alt: string; + vf_hero_image_width: string; + vf_hero_image_height: string; + vf_hero_image_fetchpriority: string; + vf_hero_image_loading: string; + vf_hero_image_sizes: string; vf_hero_kicker: string; vf_hero_heading: string; vf_hero_heading_href: string; @@ -16,10 +25,11 @@ export declare class VfHeroAngularComponent implements OnInit { vf_hero_heading_additional: string; class: string; style: string; + hasResponsiveMedia: boolean; vf_hero_link_innerhtml: string; ngOnInit(): void; ngOnChanges(): void; setValues(): void; static ɵfac: i0.ɵɵFactoryDeclaration; - static ɵcmp: i0.ɵɵComponentDeclaration; + static ɵcmp: i0.ɵɵComponentDeclaration; } diff --git a/components/vf-hero/vf-hero.angular/lib/vf-hero.angular.component.spec.ts b/components/vf-hero/vf-hero.angular/lib/vf-hero.angular.component.spec.ts index e5b7746981..faa35c4542 100644 --- a/components/vf-hero/vf-hero.angular/lib/vf-hero.angular.component.spec.ts +++ b/components/vf-hero/vf-hero.angular/lib/vf-hero.angular.component.spec.ts @@ -75,4 +75,22 @@ describe('VfHeroAngularComponent', () => { expect(linkElement.nativeElement.innerHTML).toContain('Link Text'); expect(linkElement.nativeElement.getAttribute('href')).toBe('http://example.com'); }); + + it('should render responsive media with high priority defaults', () => { + component.vf_hero_image_mobile_src = '/hero-mobile-360x200.jpg'; + component.vf_hero_image_src = '/hero-desktop-1920x1080.jpg'; + component.vf_hero_image_large_src = '/hero-large-2560x1440.jpg'; + component.vf_hero_image_sizes = '(max-width: 767px) 100vw, 1920px'; + fixture.detectChanges(); + + expect(component.class).toContain('vf-hero--has-media'); + + const imageElement = fixture.debugElement.query(By.css('.vf-hero__image')); + expect(imageElement.nativeElement.getAttribute('src')).toBe('/hero-desktop-1920x1080.jpg'); + expect(imageElement.nativeElement.getAttribute('fetchpriority')).toBe('high'); + expect(imageElement.nativeElement.getAttribute('loading')).toBe('eager'); + expect(imageElement.nativeElement.getAttribute('width')).toBe('1920'); + expect(imageElement.nativeElement.getAttribute('height')).toBe('1080'); + expect(imageElement.nativeElement.getAttribute('sizes')).toBe('(max-width: 767px) 100vw, 1920px'); + }); }); diff --git a/components/vf-hero/vf-hero.config.yml b/components/vf-hero/vf-hero.config.yml index 86f588c1ca..2c56c03604 100755 --- a/components/vf-hero/vf-hero.config.yml +++ b/components/vf-hero/vf-hero.config.yml @@ -12,6 +12,18 @@ preview: "@preview--nogrid" # hidden: true context: component-type: container + # Recommended responsive image settings: + # - mobile: 360x200 + # - desktop: 1920x1080 + # - large/high-res: 2560x1440 + # vf_hero_image_mobile_src: "https://example.org/hero-mobile-360x200.jpg" + # vf_hero_image_src: "https://example.org/hero-desktop-1920x1080.jpg" + # vf_hero_image_large_src: "https://example.org/hero-large-2560x1440.jpg" + # vf_hero_image_width: 1920 + # vf_hero_image_height: 1080 + # vf_hero_image_sizes: "(max-width: 767px) 100vw, 1920px" + # vf_hero_image_fetchpriority: high + # vf_hero_image_loading: eager @@ -60,6 +72,14 @@ variants: vf_hero_link_text: Learn more vf_hero_link_href: JavaScript:Void(0); vf_hero_image: url('https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png'); + vf_hero_image_mobile_src: https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg + vf_hero_image_src: https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg + vf_hero_image_large_src: https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg + vf_hero_image_width: 1920 + vf_hero_image_height: 1080 + vf_hero_image_sizes: '(max-width: 767px) 100vw, 1920px' + vf_hero_image_fetchpriority: high + vf_hero_image_loading: eager angular: + [vf_hero_image]="'url(https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png)'" + [vf_hero_image_mobile_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg'" + [vf_hero_image_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg'" + [vf_hero_image_large_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg'" + [vf_hero_image_width]="'1920'" + [vf_hero_image_height]="'1080'" + [vf_hero_image_fetchpriority]="'high'" + [vf_hero_image_loading]="'eager'"> react: - name: spacing (400) diff --git a/components/vf-hero/vf-hero.njk b/components/vf-hero/vf-hero.njk index c692338fe9..d9d431a70a 100755 --- a/components/vf-hero/vf-hero.njk +++ b/components/vf-hero/vf-hero.njk @@ -1,6 +1,16 @@ {% spaceless %} {%- if context %} {% set vf_hero_image = context.vf_hero_image %} + {% set vf_hero_image_size = context.vf_hero_image_size %} + {% set vf_hero_image_src = context.vf_hero_image_src %} + {% set vf_hero_image_mobile_src = context.vf_hero_image_mobile_src %} + {% set vf_hero_image_large_src = context.vf_hero_image_large_src %} + {% set vf_hero_image_alt = context.vf_hero_image_alt %} + {% set vf_hero_image_width = context.vf_hero_image_width %} + {% set vf_hero_image_height = context.vf_hero_image_height %} + {% set vf_hero_image_fetchpriority = context.vf_hero_image_fetchpriority %} + {% set vf_hero_image_loading = context.vf_hero_image_loading %} + {% set vf_hero_image_sizes = context.vf_hero_image_sizes %} {% set vf_hero_kicker = context.vf_hero_kicker %} {% set vf_hero_heading = context.vf_hero_heading %} @@ -26,10 +36,26 @@ {%- endif -%} {% endspaceless %}
+ {%- if vf_hero_image_src or vf_hero_image_mobile_src or vf_hero_image_large_src -%} + + {%- if vf_hero_image_large_src %}{% endif -%} + {%- if vf_hero_image_mobile_src %}{% endif -%} + {{ vf_hero_image_alt | default('', true) }} + + {%- endif -%}
{%- if vf_hero_kicker -%}

{{- vf_hero_kicker | safe -}}

diff --git a/components/vf-hero/vf-hero.react.js b/components/vf-hero/vf-hero.react.js index 3199ab0102..82a17f8513 100644 --- a/components/vf-hero/vf-hero.react.js +++ b/components/vf-hero/vf-hero.react.js @@ -14,14 +14,29 @@ function VfHero({ vf_hero_link_href, vf_hero_image, vf_hero_image_size, + vf_hero_image_src, + vf_hero_image_mobile_src, + vf_hero_image_large_src, + vf_hero_image_alt, + vf_hero_image_width = "1920", + vf_hero_image_height = "1080", + vf_hero_image_fetchpriority = "high", + vf_hero_image_loading = "eager", + vf_hero_image_sizes, vf_hero_kicker, vf_hero_heading_additional, modifier_class }) { - const classNames = `vf-hero vf-u-fullbleed ${modifier_class || ""}`; + const hasResponsiveMedia = + !!vf_hero_image_src || + !!vf_hero_image_mobile_src || + !!vf_hero_image_large_src; + const classNames = `vf-hero${ + hasResponsiveMedia ? " vf-hero--has-media" : "" + } vf-u-fullbleed ${modifier_class || ""}`; const styles = { - "--vf-hero--bg-image": vf_hero_image, - "--vf-hero--bg-image-size": vf_hero_image_size + ...(vf_hero_image && { "--vf-hero--bg-image": vf_hero_image }), + ...(vf_hero_image_size && { "--vf-hero--bg-image-size": vf_hero_image_size }) }; const attributes = { ...(id && { id }) @@ -34,6 +49,30 @@ function VfHero({ className={classNames} style={styles} > + {hasResponsiveMedia ? ( + + {vf_hero_image_large_src ? ( + + ) : null} + {vf_hero_image_mobile_src ? ( + + ) : null} + {vf_hero_image_alt + + ) : null}
{vf_hero_kicker ? (

{vf_hero_kicker}

@@ -41,7 +80,9 @@ function VfHero({ {vf_hero_heading ? (

{vf_hero_heading_href ? ( - {vf_hero_heading} + + {vf_hero_heading} + ) : ( vf_hero_heading )} diff --git a/components/vf-hero/vf-hero.react.test.js b/components/vf-hero/vf-hero.react.test.js index ba5459a065..05b48cb8bc 100644 --- a/components/vf-hero/vf-hero.react.test.js +++ b/components/vf-hero/vf-hero.react.test.js @@ -27,6 +27,28 @@ describe("VfHero", () => { }); }); + test("renders responsive hero media with high-priority image attrs", () => { + render( + + ); + + const banner = screen.getByRole("banner"); + expect(banner).toHaveClass("vf-hero--has-media"); + + const img = screen.getByRole("img"); + expect(img).toHaveAttribute("src", "/hero-desktop-1920x1080.jpg"); + expect(img).toHaveAttribute("fetchpriority", "high"); + expect(img).toHaveAttribute("loading", "eager"); + expect(img).toHaveAttribute("width", "1920"); + expect(img).toHaveAttribute("height", "1080"); + expect(img).toHaveAttribute("sizes", "(max-width: 767px) 100vw, 1920px"); + }); + test("renders with heading and link", () => { render( Date: Sat, 8 Aug 2026 22:03:51 +0100 Subject: [PATCH 2/2] chore: Update vf-hero component for optimised responsive image delivery and performance --- components/vf-hero/README.md | 77 +++++++++++-------- .../vf-hero/vf-hero.angular.component.ts | 2 +- .../lib/vf-hero.angular.component.spec.ts | 10 ++- components/vf-hero/vf-hero.config.yml | 67 ++++++++++++---- components/vf-hero/vf-hero.njk | 2 +- components/vf-hero/vf-hero.react.js | 4 +- components/vf-hero/vf-hero.react.test.js | 15 +++- components/vf-hero/vf-hero.scss | 4 +- 8 files changed, 125 insertions(+), 56 deletions(-) diff --git a/components/vf-hero/README.md b/components/vf-hero/README.md index 6026e38e5e..ddf34bd539 100755 --- a/components/vf-hero/README.md +++ b/components/vf-hero/README.md @@ -14,6 +14,10 @@ By default the `vf-hero` makes use of the roundels background image. To keep the You can bring your own image to use with the vf-hero. +- Dimensions - recommended dimensions for the hero image are: + - Desktop: 1920 × 1080 px + - Mobile: 360 × 200 px + - Large / high-res displays: 2560 × 1440 px - Size: Image size should be below 500KB - Format: WebP or AVIF provide better image quality at smaller file sizes - Positioning: people and other important imagery should be placed on the right side. The image will, by default, vertically centre and align to the right side. @@ -25,15 +29,16 @@ You can bring your own image to use with the vf-hero. | Content name | Usage | `.yml` key | | ------------ | ------------------------------------------------------------------------------ | -------------------- | -| Heading | To be used for the heading of the page. | `vf_hero_heading` | -| Heading HREF | To be used as a 'return to home' link for the micro site. | `vf_hero_heading_href` | -| Subheading | Optional content to be used along with the Heading for a terse explainer. | `vf_hero_subheading` | +| Heading | To be used for the heading of the page. | `vf_hero_heading` | +| Heading HREF | To be used as a 'return to home' link for the micro site. | `vf_hero_heading_href` | +| Subheading | Optional content to be used along with the Heading for a terse explainer. | `vf_hero_subheading` | | Kicker | Optional content that helps define the context of overall content of the page. | `vf_hero_kicker` | -| Text | Optional content that can help explain the page content in a brief paragraph. | `vf_hero_text` | -| Link Text | The text for the hero 'call to action' link. Only works if there is associated Link HREF. | `vf_hero_link_text` | -| Link HREF | The url that the Link Text would be pointing to and opens in the same browser tab. This only works if there is associated Link Text | `vf_hero_link_href` | -| Spacing | If added spacing can be any of these values only : 200, 400, 500, 600, 800, 1200, 1600 | 'spacing' +| Text | Optional content that can help explain the page content in a brief paragraph. | `vf_hero_text` | +| Link Text | The text for the hero 'call to action' link. Only works if there is associated Link HREF. | `vf_hero_link_text` | +| Link HREF | The url that the Link Text would be pointing to and opens in the same browser tab. This only works if there is associated Link Text | `vf_hero_link_href` | +| Spacing | If added spacing can be any of these values only : 200, 400, 500, 600, 800, 1200, 1600 | 'spacing' | +
| Content name | `.yml` key | CSS classname | | ------------ | -------------------- | --------------------- | @@ -54,6 +59,16 @@ You can bring your own image to use with the vf-hero. | Image Sizes | `vf_hero_image_sizes` | `vf-hero__image` | | Image Alt | `vf_hero_image_alt` | `vf-hero__image` | +
+ +For responsive hero delivery, use Cloudimage transformation URLs on the image sources. The recommended pattern is: + +- Mobile image: `width=360&height=200&func=crop` +- Desktop image: `width=1920&height=1080&func=crop` +- Large/high-res image: `width=2560&height=1440&func=crop` + +The initial HTML renders the hero image with `fetchpriority="high"`, `loading="eager"`, and explicit `width` and `height` defaults to help LCP and layout stability. + ### CSS Custom Properties `--vf-hero--bg-image` — this is for the url for the background image. It can either be added, inline if you're writing the HTML, using the `.yml` data source of `vf_hero_image`, or by other needs (a input or upload in WordPress, for example). @@ -66,7 +81,7 @@ IE 11 will get the background colour and the "roundels" image. Under the approac ### EMBL usage -For EMBL sites, the `vf-hero` can take an image (provided by Design) which should be uploaded to [the files site](https://www.embl.org/files) and applied using the custom property available (`--vf-hero--bg-image`). +For EMBL sites, the `vf-hero` can take an image (provided by Design) which should be uploaded to [the files site](https://www.embl.org/files) and applied using the custom property available (`--vf-hero--bg-image`). When you want the hero to be responsive in the initial HTML, prefer the Cloudimage transformation URLs shown above and pass them through the responsive image props instead of relying on the CSS background alone. ### Angular @@ -92,14 +107,14 @@ This package was generated with Angular version 15.2.0 and has been tested on ap [vf_hero_text]="['The Hentze group combines biochemical and systems–level approaches to investigate the connections between gene expression and cell metabolism, and their roles in human disease.']" [vf_hero_link_text]="'Learn more'" [vf_hero_link_href]="'JavaScript:Void(0);'" - [vf_hero_image_size]="'auto 28.5rem'" - [vf_hero_image_mobile_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg'" - [vf_hero_image_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg'" - [vf_hero_image_large_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg'" - [vf_hero_image_width]="'1920'" - [vf_hero_image_height]="'1080'" - [vf_hero_image_fetchpriority]="'high'" - [vf_hero_image_loading]="'eager'"> + [vf_hero_image_size]="'auto 28.5rem'" + [vf_hero_image_mobile_src]="'https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png?width=360&height=200&func=crop'" + [vf_hero_image_src]="'https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png?width=1920&height=1080&func=crop'" + [vf_hero_image_large_src]="'https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png?width=2560&height=1440&func=crop'" + [vf_hero_image_width]="'1920'" + [vf_hero_image_height]="'1080'" + [vf_hero_image_fetchpriority]="'high'" + [vf_hero_image_loading]="'eager'"> ``` 4. add to your styles.scss @@ -123,14 +138,14 @@ Usage: [vf_hero_text]="['The Hentze group combines biochemical and systems–level approaches to investigate the connections between gene expression and cell metabolism, and their roles in human disease.']" [vf_hero_link_text]="'Learn more'" [vf_hero_link_href]="'JavaScript:Void(0);'" - [vf_hero_image_size]="'auto 28.5rem'" - [vf_hero_image_mobile_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg'" - [vf_hero_image_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg'" - [vf_hero_image_large_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg'" - [vf_hero_image_width]="'1920'" - [vf_hero_image_height]="'1080'" - [vf_hero_image_fetchpriority]="'high'" - [vf_hero_image_loading]="'eager'"> + [vf_hero_image_size]="'auto 28.5rem'" + [vf_hero_image_mobile_src]="'https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png?width=360&height=200&func=crop'" + [vf_hero_image_src]="'https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png?width=1920&height=1080&func=crop'" + [vf_hero_image_large_src]="'https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png?width=2560&height=1440&func=crop'" + [vf_hero_image_width]="'1920'" + [vf_hero_image_height]="'1080'" + [vf_hero_image_fetchpriority]="'high'" + [vf_hero_image_loading]="'eager'"> ``` @@ -157,13 +172,13 @@ As of version 4.0.0-alpha.2 vf-hero has experimental React support which has bee vf_hero_link_text="Learn more" vf_hero_link_href="'JavaScript:Void(0);'" vf_hero_image_size="auto 28.5rem" - vf_hero_image_mobile_src="https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg" - vf_hero_image_src="https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg" - vf_hero_image_large_src="https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg" - vf_hero_image_width="1920" - vf_hero_image_height="1080" - vf_hero_image_fetchpriority="high" - vf_hero_image_loading="eager" + vf_hero_image_mobile_src="https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png?width=360&height=200&func=crop" + vf_hero_image_src="https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png?width=1920&height=1080&func=crop" + vf_hero_image_large_src="https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png?width=2560&height=1440&func=crop" + vf_hero_image_width="1920" + vf_hero_image_height="1080" + vf_hero_image_fetchpriority="high" + vf_hero_image_loading="eager" /> ``` 4. Styling changes diff --git a/components/vf-hero/vf-hero.angular.component.ts b/components/vf-hero/vf-hero.angular.component.ts index c6273f43f3..fd94a1e754 100644 --- a/components/vf-hero/vf-hero.angular.component.ts +++ b/components/vf-hero/vf-hero.angular.component.ts @@ -11,7 +11,7 @@ import { Component, Input, OnInit } from "@angular/core"; { component.vf_hero_image_mobile_src = '/hero-mobile-360x200.jpg'; component.vf_hero_image_src = '/hero-desktop-1920x1080.jpg'; component.vf_hero_image_large_src = '/hero-large-2560x1440.jpg'; - component.vf_hero_image_sizes = '(max-width: 767px) 100vw, 1920px'; fixture.detectChanges(); expect(component.class).toContain('vf-hero--has-media'); @@ -93,4 +92,13 @@ describe('VfHeroAngularComponent', () => { expect(imageElement.nativeElement.getAttribute('height')).toBe('1080'); expect(imageElement.nativeElement.getAttribute('sizes')).toBe('(max-width: 767px) 100vw, 1920px'); }); + + it('should use the default sizes hint when one is not provided', () => { + component.vf_hero_image_mobile_src = '/hero-mobile-360x200.jpg'; + component.vf_hero_image_src = '/hero-desktop-1920x1080.jpg'; + fixture.detectChanges(); + + const imageElement = fixture.debugElement.query(By.css('.vf-hero__image')); + expect(imageElement.nativeElement.getAttribute('sizes')).toBe('(max-width: 767px) 100vw, 1920px'); + }); }); diff --git a/components/vf-hero/vf-hero.config.yml b/components/vf-hero/vf-hero.config.yml index 2c56c03604..2630893818 100755 --- a/components/vf-hero/vf-hero.config.yml +++ b/components/vf-hero/vf-hero.config.yml @@ -16,9 +16,10 @@ context: # - mobile: 360x200 # - desktop: 1920x1080 # - large/high-res: 2560x1440 - # vf_hero_image_mobile_src: "https://example.org/hero-mobile-360x200.jpg" - # vf_hero_image_src: "https://example.org/hero-desktop-1920x1080.jpg" - # vf_hero_image_large_src: "https://example.org/hero-large-2560x1440.jpg" + # Example Cloudimage URLs: + # vf_hero_image_mobile_src: "https://acxngcvroo.cloudimg.io/v7/https://example.org/hero.jpg?width=360&height=200&func=crop" + # vf_hero_image_src: "https://acxngcvroo.cloudimg.io/v7/https://example.org/hero.jpg?width=1920&height=1080&func=crop" + # vf_hero_image_large_src: "https://acxngcvroo.cloudimg.io/v7/https://example.org/hero.jpg?width=2560&height=1440&func=crop" # vf_hero_image_width: 1920 # vf_hero_image_height: 1080 # vf_hero_image_sizes: "(max-width: 767px) 100vw, 1920px" @@ -62,7 +63,7 @@ variants: vf_hero_link_href="'JavaScript:Void(0);'" vf_hero_image_size="auto 28.5rem" /> - - name: default with image + - name: default with image (responsive) context: vf_hero_kicker: VF Hamburg | Structural Biology vf_hero_heading: About the Hentze group! @@ -71,10 +72,11 @@ variants: - The Hentze group combines biochemical and systems–level approaches to investigate the connections between gene expression and cell metabolism, and their roles in human disease. vf_hero_link_text: Learn more vf_hero_link_href: JavaScript:Void(0); - vf_hero_image: url('https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png'); - vf_hero_image_mobile_src: https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg - vf_hero_image_src: https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg - vf_hero_image_large_src: https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg + vf_hero_image: url('https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif') + vf_hero_image_size: null + vf_hero_image_mobile_src: https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif?width=360&height=200&func=crop + vf_hero_image_src: https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif?width=1920&height=1080&func=crop + vf_hero_image_large_src: https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif?width=2560&height=1440&func=crop vf_hero_image_width: 1920 vf_hero_image_height: 1080 vf_hero_image_sizes: '(max-width: 767px) 100vw, 1920px' @@ -88,10 +90,10 @@ variants: [vf_hero_text]="['The Hentze group combines biochemical and systems–level approaches to investigate the connections between gene expression and cell metabolism, and their roles in human disease.']" [vf_hero_link_text]="'Learn more'" [vf_hero_link_href]="'JavaScript:Void(0);'" - [vf_hero_image]="'url(https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png)'" - [vf_hero_image_mobile_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg'" - [vf_hero_image_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg'" - [vf_hero_image_large_src]="'https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg'" + [vf_hero_image]="'url(https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif)'" + [vf_hero_image_mobile_src]="'https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif?width=360&height=200&func=crop'" + [vf_hero_image_src]="'https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif?width=1920&height=1080&func=crop'" + [vf_hero_image_large_src]="'https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif?width=2560&height=1440&func=crop'" [vf_hero_image_width]="'1920'" [vf_hero_image_height]="'1080'" [vf_hero_image_fetchpriority]="'high'" @@ -106,16 +108,47 @@ variants: vf_hero_text={["The Hentze group combines biochemical and systems–level approaches to investigate the connections between gene expression and cell metabolism, and their roles in human disease."]} vf_hero_link_text="Learn more" vf_hero_link_href="'JavaScript:Void(0);'" - vf_hero_image="url(https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png)" - vf_hero_image_mobile_src="https://www.embl.org/files/wp-content/uploads/vf-hero-mobile-360x200.jpg" - vf_hero_image_src="https://www.embl.org/files/wp-content/uploads/vf-hero-intense-1920x1080.jpg" - vf_hero_image_large_src="https://www.embl.org/files/wp-content/uploads/vf-hero-intense-2560x1440.jpg" + vf_hero_image="url(https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif)" + vf_hero_image_mobile_src="https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif?width=360&height=200&func=crop" + vf_hero_image_src="https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif?width=1920&height=1080&func=crop" + vf_hero_image_large_src="https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.avif?width=2560&height=1440&func=crop" vf_hero_image_width="1920" vf_hero_image_height="1080" vf_hero_image_fetchpriority="high" vf_hero_image_loading="eager" /> - + - name: default with image + context: + vf_hero_kicker: VF Hamburg | Structural Biology + vf_hero_heading: About the Hentze group! + vf_hero_subheading: an example of some ancillary text + vf_hero_text: + - The Hentze group combines biochemical and systems–level approaches to investigate the connections between gene expression and cell metabolism, and their roles in human disease. + vf_hero_link_text: Learn more + vf_hero_link_href: JavaScript:Void(0); + vf_hero_image_size: null + vf_hero_image: url('https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png') + angular: + + + react: + systems–level approaches to investigate the connections between gene expression and cell metabolism, and their roles in human disease."]} + vf_hero_link_text="Learn more" + vf_hero_link_href="'JavaScript:Void(0);'" + vf_hero_image="url(https://acxngcvroo.cloudimg.io/v7/https://www.embl.org/files/wp-content/uploads/vf-hero-intense.png)" + /> - name: spacing (400) context: spacing: 400 diff --git a/components/vf-hero/vf-hero.njk b/components/vf-hero/vf-hero.njk index d9d431a70a..ae05fc7e7d 100755 --- a/components/vf-hero/vf-hero.njk +++ b/components/vf-hero/vf-hero.njk @@ -47,7 +47,7 @@ {{ vf_hero_image_alt | default('', true) }} { vf_hero_image_mobile_src="/hero-mobile-360x200.jpg" vf_hero_image_src="/hero-desktop-1920x1080.jpg" vf_hero_image_large_src="/hero-large-2560x1440.jpg" - vf_hero_image_sizes="(max-width: 767px) 100vw, 1920px" /> ); @@ -49,6 +48,20 @@ describe("VfHero", () => { expect(img).toHaveAttribute("sizes", "(max-width: 767px) 100vw, 1920px"); }); + test("uses the default sizes hint when none is provided", () => { + render( + + ); + + expect(screen.getByRole("img")).toHaveAttribute( + "sizes", + "(max-width: 767px) 100vw, 1920px" + ); + }); + test("renders with heading and link", () => { render(