<header class="supt-hero-text-media supt-parallax-full-image -small" data-from-bottom="true">
    <div class="supt-hero-text-media__media" style="height: 100%;">
        <img src="/sites/gv/files/flmngr/hero-text-media.webp" alt="Hero Text Media" loading="eager" class="supt-parallax-full-image__image" />
    </div>

    <div class="supt-hero-text-media__content container">
        <div class="supt-hero-text-media__content-inner row">
            <div class="supt-hero-text-media__headline col-md-6 supt-slide-up-title">
                <h1 class="supt-hero-text-media__title">Our press releases</h1>
                <p class="supt-hero-text-media__description">Follow our latest corporate communications. For any questions or enquiries, please contact us</p>
            </div>
        </div>
    </div>

    <div class="supt-scroll-item">
        <p class="supt-scroll-item__text">Scroll down</p>
        <span class="supt-scroll-item__inner">
            <span class="supt-scroll-item__icon"></span>
        </span>
        <svg xmlns="http://www.w3.org/2000/svg" width="2" height="63" viewbox="0 0 2 63" fill="none" class="supt-scroll-item__line">
            <path d="M1 1L1 63" stroke="url(#paint0_linear_10281_8341)" stroke-linecap="round" stroke-dasharray="1 4" />
            <defs>
                <linearGradient id="paint0_linear_10281_8341" x1="1.5" y1="1" x2="1.5" y2="63" gradientunits="userSpaceOnUse">
                    <stop offset="0.4" stop-color="#ED002F" />
                    <stop offset="1" stop-color="#ED002F" stop-opacity="0" />
                </linearGradient>
            </defs>
        </svg>
    </div>
</header>

No notes defined.

<header class="supt-hero-text-media supt-parallax-full-image {{ modifiers|modifiersAttr }}" data-from-bottom="true" {% if not modifiers|contains('small') %} style="height: 100svh;" {% endif %}>
	<div class="supt-hero-text-media__media" style="height: 100%;">
		{% if image %}
			<img src="{{ path(image.src) }}" alt="{{ image.alt }}" loading="eager" class="supt-parallax-full-image__image"/>
		{% elseif video %}
			{% if video.sources %}
				<video muted loop playsinline class="supt-parallax-full-image__image" width="100%" height="100%" style="object-fit: cover;">
					{% for source in video.sources %}
						<source src="{{ path(source.src) }}" type="{{ source.type }}">
					{% endfor %}
				</video>
			{% else %}
				<video muted loop playsinline class="supt-parallax-full-image__image" width="100%" height="100%" style="object-fit: cover;" src="{{ path(video.src) }}" poster="{{ path(video.poster) }}"/>
			{% endif %}
		{% endif %}
	</div>

	<div class="supt-hero-text-media__content container">
		<div class="supt-hero-text-media__content-inner row">
			<div class="supt-hero-text-media__headline col-md-6 supt-slide-up-title">
				{% if date %}
					{% include "atoms/post-metas/post-metas.twig" with {
							"tag": {label: "News"},
							"date": date
						} only %}
				{% endif %}
				{% if title %}
					<h1 class="supt-hero-text-media__title">{{ title }}</h1>
				{% endif %}
				{% if description %}
					<p class="supt-hero-text-media__description">{{ description }}</p>
				{% endif %}
			</div>
		</div>
	</div>

	{% include "atoms/scroll-item/scroll-item.twig" %}
</header>
{
  "modifiers": [
    "small"
  ],
  "title": "Our press releases",
  "description": "Follow our latest corporate communications. For any questions or enquiries, please contact us",
  "image": {
    "src": "/sites/gv/files/flmngr/hero-text-media.webp",
    "alt": "Hero Text Media"
  }
}
  • Content:
    .supt-hero-text-media {
    	display: flex;
    	position: relative;
    	min-height: 100svh;
    	height: 100svh;
    
    	@media (min-width: $breakpoint-xxl) {
    		min-height: 75svh;
    		height: 75svh;
    	}
    
    	&__media {
    		position: absolute;
    		top: 0;
    		left: 0;
    		display: flex;
    		flex-direction: column;
    		justify-content: center;
    		align-items: center;
    		width: 100%;
    		height: 100%;
    		object-fit: cover;
    		overflow: hidden;
    
    		&::after {
    			content: '';
    			position: absolute;
    			top: 0;
    			left: 0;
    			width: 100%;
    			height: 100%;
    			z-index: 1;
    			background: linear-gradient(
    				180deg,
    				rgb(0 0 0 / 70%) 0%,
    				rgb(0 0 0 / 10%) 50%,
    				rgb(0 0 0 / 70%) 100%
    			);
    		}
    
    		img,
    		video {
    			width: 100%;
    			height: 100%;
    			object-fit: cover;
    		}
    	}
    
    	&__content {
    		position: relative;
    		z-index: 2;
    		color: $color-white;
    		padding-top: $spacing-14;
    		padding-bottom: $spacing-40;
    		align-self: flex-end;
    
    		@media (min-width: $breakpoint-md) {
    			padding-top: $spacing-20;
    		}
    	}
    
    	&__headline {
    		@mixin clamp gap, $spacing-4, $spacing-6, $breakpoint-xs, $breakpoint-xl;
    		display: flex;
    		flex-direction: column;
    
    		.supt-post-metas,
    		.supt-tag__label {
    			color: $color-white;
    		}
    	}
    
    	&__title {
    		@extend %t-h1;
    		margin-bottom: 0;
    	}
    
    	&__description {
    		@extend %t-body-m;
    
    		a {
    			@extend %link-underline;
    			font-weight: 500;
    			outline: none;
    		}
    
    		/* No title, so make it bigger */
    		&:first-child {
    			@extend %t-h2;
    		}
    	}
    
    	&.-small {
    		height: auto;
    		min-height: auto;
    
    		/* This top spacing if to leave room for the nav & breadcrumb. */
    		padding-top: calc(69px + 18px + $spacing-4 * 2);
    		@media (min-width: $breakpoint-md) {
    			padding-top: calc(81px + 20px + $spacing-6 * 2);
    		}
    
    		.supt-hero-text-media__media {
    			img {
    				transform-origin: 50% 80%;
    			}
    			&::after {
    				background: linear-gradient(0deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.6) 100%);
    			}
    		}
    
    		.supt-hero-text-media__content {
    			padding-block: $spacing-10 $spacing-16;
    
    			@media (min-width: $breakpoint-md) {
    				padding-block: $spacing-16 $spacing-33;
    			}
    		}
    	}
    
    	&.-image-right {
    		.supt-hero-text-media__media {
    			img {
    				object-position: right;
    			}
    		}
    	}
    
    	& + .supt-section-team,
    	& + .supt-section-contact,
    	& + .supt-section-cards {
    		@mixin clamp padding-top, $spacing-16, $spacing-32, $breakpoint-xs, $breakpoint-xl, true;
    	}
    
    	& + .supt-listing-cards {
    		@mixin clamp padding-top, $spacing-8, $spacing-16, $breakpoint-xs, $breakpoint-xl, true;
    	}
    
    	& + .supt-single {
    		@mixin clamp padding-top, $spacing-8, $spacing-16, $breakpoint-xs, $breakpoint-xl, true;
    	}
    }
    
  • URL: /components/raw/hero-text-media/hero-text-media.css
  • Filesystem Path: src/components/organisms/hero-text-media/hero-text-media.css
  • Size: 2.6 KB
  • Content:
    import { animate, onScroll } from 'animejs';
    
    export class HeroTextMedia {
    	private $element: HTMLElement;
    	private $scrollItem: HTMLElement;
    	private $video: HTMLVideoElement;
    
    	constructor($element: HTMLElement) {
    		this.$element = $element;
    
    		this.$scrollItem = $element.querySelector('.supt-scroll-item') as HTMLElement;
    
    		this.$video = $element.querySelector('video') as HTMLVideoElement;
    
    		void this.setupVideo();
    		this.setupScrollAnimation();
    	}
    
    	private setupScrollAnimation() {
    		animate(this.$scrollItem, {
    			opacity: [1, 0],
    			autoplay: onScroll({
    				container: document.body,
    				target: this.$element,
    				enter: 'bottom bottom',
    				leave: 'center bottom',
    				sync: true,
    			}),
    		});
    	}
    
    	private async setupVideo() {
    		if (!this.$video) {
    			return;
    		}
    
    		const isHls = this.$video.src?.endsWith('.m3u8') ?? false;
    
    		if (isHls && !this.$video.canPlayType('application/vnd.apple.mpegurl')) {
    			// @ts-expect-error
    			const { Hls } = await import('https://cdn.jsdelivr.net/npm/hls.js@latest/+esm');
    
    			if (Hls.isSupported()) {
    				const hls = new Hls();
    
    				hls.loadSource(this.$video.src as string);
    				hls.attachMedia(this.$video);
    
    				// Smart initial quality selection
    				hls.on(Hls.Events.MANIFEST_PARSED, (_event: any, data: any) => {
    					const viewportWidth = window.innerWidth;
    					const estimatedBandwidth = hls.bandwidthEstimate || 5000000; // fallback 5Mbps
    
    					// console.log(`Viewport width: ${viewportWidth}px`);
    					// console.log(`Estimated bandwidth: ${estimatedBandwidth / 1000} kbps`);
    
    					let initialLevel = 0; // fallback to lowest
    
    					// Iterate levels to find best fit
    					data.levels.forEach((level: any, index: number) => {
    						const fitsViewport = level.width <= viewportWidth * 1.5; // 1.5x to allow for pixel density
    						const fitsBandwidth = level.bitrate <= estimatedBandwidth * 0.8; // 80% safety margin
    						if (fitsViewport && fitsBandwidth) {
    							initialLevel = index; // pick highest level that fits
    						}
    					});
    
    					// console.log(
    					// 	`Starting at level ${initialLevel} (${data.levels[initialLevel].width}x${data.levels[initialLevel].height}, ${data.levels[initialLevel].bitrate / 1000} kbps)`
    					// );
    
    					hls.startLevel = initialLevel;
    					this.$video.play();
    				});
    			} else {
    				console.error('Your browser does not support HLS');
    			}
    		} else {
    			// Safari native HLS
    			this.$video.addEventListener('loadedmetadata', () => {
    				this.$video.play();
    			});
    		}
    	}
    }
    
  • URL: /components/raw/hero-text-media/index.ts
  • Filesystem Path: src/components/organisms/hero-text-media/index.ts
  • Size: 2.5 KB