diff --git a/.changeset/stupid-pianos-rush.md b/.changeset/stupid-pianos-rush.md
new file mode 100644
index 0000000000..b0ed6e883e
--- /dev/null
+++ b/.changeset/stupid-pianos-rush.md
@@ -0,0 +1,5 @@
+---
+'@swisspost/internet-header': minor
+---
+
+Updated the logo size, the post logo now spans the meta-navigation and scales down on scroll.
diff --git a/packages/documentation/src/stories/internet-header/components/header/post-internet-header.stories.tsx b/packages/documentation/src/stories/internet-header/components/header/post-internet-header.stories.tsx
index b997cf4eed..85633f1c6b 100644
--- a/packages/documentation/src/stories/internet-header/components/header/post-internet-header.stories.tsx
+++ b/packages/documentation/src/stories/internet-header/components/header/post-internet-header.stories.tsx
@@ -288,7 +288,7 @@ const Template = (args: Args) => {
- CWF Internet Header
+ Design System Internet Header
diff --git a/packages/internet-header/cypress/e2e/header.cy.ts b/packages/internet-header/cypress/e2e/header.cy.ts
index 3d46c7f2e3..adeb87f697 100644
--- a/packages/internet-header/cypress/e2e/header.cy.ts
+++ b/packages/internet-header/cypress/e2e/header.cy.ts
@@ -10,8 +10,8 @@ describe('header', () => {
cy.get('swisspost-internet-header').should('have.class', 'hydrated');
});
- it(`has title 'CWF Internet Header'`, () => {
- cy.get('h1').should('contain.text', 'CWF Internet Header');
+ it(`has title 'Design System Internet Header'`, () => {
+ cy.get('h1').should('contain.text', 'Design System Internet Header');
});
it(`has nav item 'Briefe versenden' selected`, () => {
diff --git a/packages/internet-header/src/components/post-internet-header/logo-animation/logo-animation.scss b/packages/internet-header/src/components/post-internet-header/logo-animation/logo-animation.scss
new file mode 100644
index 0000000000..c70f6d327b
--- /dev/null
+++ b/packages/internet-header/src/components/post-internet-header/logo-animation/logo-animation.scss
@@ -0,0 +1,24 @@
+@use '../../../utils/mixins.scss';
+
+/**
+ * Default position: scrolled
+ * Logo is being scaled up for the initial view (scrollY = 0). This enables media queries to override
+ * mobile behaviour without re-calculation
+*/
+:host {
+ --logo-scale: 1;
+
+ @include mixins.max(lg) {
+ --logo-scale: 1 !important;
+ }
+}
+
+post-logo {
+ height: var(--header-height);
+ transform-origin: bottom left;
+ transform: scale(var(--logo-scale));
+}
+
+post-main-navigation {
+ margin-left: calc((var(--header-height) * var(--logo-scale)) - var(--header-height));
+}
diff --git a/packages/internet-header/src/components/post-internet-header/logo-animation/logo-animation.ts b/packages/internet-header/src/components/post-internet-header/logo-animation/logo-animation.ts
new file mode 100644
index 0000000000..ce95ceadcd
--- /dev/null
+++ b/packages/internet-header/src/components/post-internet-header/logo-animation/logo-animation.ts
@@ -0,0 +1,59 @@
+import { debounce } from 'throttle-debounce';
+import { state } from '../../../data/store';
+
+export const registerLogoAnimationObserver = (
+ target: HTMLElement,
+ headerRef: HTMLSwisspostInternetHeaderElement,
+) => {
+ /**
+ * Set intersection ratio as CSS custom property
+ */
+ const handleScroll = () => {
+ const fullStickyness = state.stickyness === 'full';
+ let scale = 1;
+ // Minus 1px border at the bottom that the logo is not covering
+ const adjustedHeaderHeight = headerRef.clientHeight - 1;
+ const scrollY = fullStickyness ? 0 : window.scrollY;
+
+ // If meta navigation is not visible (mobile, not configured), scale should just be 1
+ if (target.clientHeight > 0) {
+ scale = Math.max(
+ (adjustedHeaderHeight - Math.max(scrollY, 0)) /
+ (adjustedHeaderHeight - target.clientHeight),
+ 1,
+ );
+ }
+ headerRef.style.setProperty('--logo-scale', scale.toString());
+ };
+
+ const debounced = debounce(150, handleScroll);
+
+ /**
+ * Observe the meta navigation in order to not track scroll events throughout the whole page.
+ * This ensures that the scroll listener is only active while the meta navigation is visible.
+ */
+ const observer = new IntersectionObserver(
+ entries => {
+ entries.forEach(entry => {
+ if (entry.isIntersecting && entry.intersectionRatio > 0) {
+ window.addEventListener('scroll', handleScroll, { passive: true });
+ window.addEventListener('resize', debounced);
+
+ // Ensure callback is called at least once in case main thread is too busy while scrolling up
+ window.requestAnimationFrame(handleScroll);
+ } else {
+ window.removeEventListener('scroll', handleScroll);
+ window.removeEventListener('resize', debounced);
+ window.requestAnimationFrame(handleScroll);
+ }
+ });
+ },
+ {
+ // Fires when element leaves viewport (0) and when it just about enters it (0.001)
+ threshold: [0, 0.001],
+ },
+ );
+ observer.observe(target);
+
+ return handleScroll;
+};
diff --git a/packages/internet-header/src/components/post-internet-header/post-internet-header.scss b/packages/internet-header/src/components/post-internet-header/post-internet-header.scss
index a3e3bee625..399bc0a865 100644
--- a/packages/internet-header/src/components/post-internet-header/post-internet-header.scss
+++ b/packages/internet-header/src/components/post-internet-header/post-internet-header.scss
@@ -1,6 +1,7 @@
@use '@swisspost/design-system-styles/variables/color';
@use '../../utils/utils.scss';
@use '../../utils/mixins.scss';
+@use './logo-animation/logo-animation.scss';
:host {
display: block;
diff --git a/packages/internet-header/src/components/post-internet-header/post-internet-header.tsx b/packages/internet-header/src/components/post-internet-header/post-internet-header.tsx
index 6d6a02aba6..20e8bf286b 100644
--- a/packages/internet-header/src/components/post-internet-header/post-internet-header.tsx
+++ b/packages/internet-header/src/components/post-internet-header/post-internet-header.tsx
@@ -27,6 +27,7 @@ import { IAvailableLanguage } from '../../models/language.model';
import { translate } from '../../services/language.service';
import { If } from '../../utils/if.component';
import packageJson from '../../../package.json';
+import { registerLogoAnimationObserver } from './logo-animation/logo-animation';
@Component({
tag: 'swisspost-internet-header',
@@ -123,7 +124,7 @@ export class PostInternetHeader {
@State() activeFlyout: string | null = null;
@State() activeDropdownElement: DropdownElement | null = null;
- @Element() host: HTMLElement;
+ @Element() host: HTMLSwisspostInternetHeaderElement;
/**
* Get the currently set language as a two letter string ("de", "fr" "it" or "en")
@@ -135,10 +136,12 @@ export class PostInternetHeader {
}
private mainNav?: HTMLPostMainNavigationElement;
+ private metaNav?: HTMLPostMetaNavigationElement;
private lastScrollTop = window.scrollY || document.documentElement.scrollTop;
private throttledScroll: throttle<() => void>;
private debouncedResize: debounce<() => void>;
private lastWindowWidth: number = window.innerWidth;
+ private updateLogoAnimation: () => void;
constructor() {
if (this.project === undefined || this.project === '' || !isValidProjectId(this.project)) {
@@ -167,6 +170,7 @@ export class PostInternetHeader {
// Wait for the config to arrive, then render the header
try {
state.projectId = this.project;
+ state.stickyness = this.stickyness;
state.environment = this.environment.toLocaleLowerCase() as Environment;
if (this.language !== undefined) state.currentLanguage = this.language;
state.languageSwitchOverrides =
@@ -205,6 +209,9 @@ export class PostInternetHeader {
this.handleResize();
this.headerLoaded.emit();
this.host.classList.add('header-loaded');
+ if (this.meta && this.metaNav) {
+ this.updateLogoAnimation = registerLogoAnimationObserver(this.metaNav, this.host);
+ }
});
if (this.stickyness === 'full')
@@ -299,6 +306,12 @@ export class PostInternetHeader {
this.handleLanguageChange(event.detail);
}
+ @Watch('stickyness')
+ handleStickynessChange(newValue: StickynessOptions) {
+ state.stickyness = newValue;
+ this.updateLogoAnimation();
+ }
+
private handleClickOutsideBound = this.handleClickOutside.bind(this);
private handleClickOutside(event: Event) {
@@ -439,6 +452,7 @@ export class PostInternetHeader {
orientation="horizontal"
class="hidden-lg"
full-width={this.fullWidth}
+ ref={el => (this.metaNav = el)}
>
void>;
- private resizeObserver: ResizeObserver;
-
- constructor() {
- // Register window resize event listener and a resize observer on the mainnav controls (they change size while controls are being loaded) to display an accurately sized logo
- this.throttledResize = throttle(300, () => this.handleResize());
- window.addEventListener('resize', this.throttledResize, { passive: true });
- this.resizeObserver = new ResizeObserver(this.handleResize.bind(this));
-
- // Initially call the resize handler
- this.handleResize();
- }
-
- componentDidLoad() {
- const mainNavControls = this.host.parentElement?.querySelector('.main-navigation-controls');
- if (mainNavControls) {
- this.resizeObserver.observe(mainNavControls);
- }
- }
-
- disconnectedCallback() {
- window.removeEventListener('resize', this.throttledResize);
- this.resizeObserver.disconnect();
- }
-
- handleResize() {
- const mainNavControls = this.host.parentElement?.querySelector('.main-navigation-controls');
- const menuButton = this.host.parentElement?.querySelector('.menu-button');
- if (mainNavControls && menuButton)
- this.showFaviconLogo =
- window.innerWidth - (150 + mainNavControls.clientWidth + menuButton.clientWidth) <= 0;
- }
render() {
if (state.localizedConfig?.header.logo === undefined) return;
diff --git a/packages/internet-header/src/components/post-meta-navigation/post-meta-navigation.scss b/packages/internet-header/src/components/post-meta-navigation/post-meta-navigation.scss
index 401a8438c8..495f4a5b15 100644
--- a/packages/internet-header/src/components/post-meta-navigation/post-meta-navigation.scss
+++ b/packages/internet-header/src/components/post-meta-navigation/post-meta-navigation.scss
@@ -1,11 +1,10 @@
-@use "@swisspost/design-system-styles/variables/color";
-@use "@swisspost/design-system-styles/functions";
-@use "../../utils/utils.scss";
-@use "../../utils/mixins.scss";
+@use '@swisspost/design-system-styles/variables/color';
+@use '@swisspost/design-system-styles/functions';
+@use '../../utils/utils.scss';
+@use '../../utils/mixins.scss';
:host {
display: block;
- background: color.$gray-background-light;
font-size: functions.px-to-rem(14px);
}
@@ -15,6 +14,8 @@
align-items: center;
min-height: functions.px-to-rem(48px);
+ background: color.$gray-background-light;
+
@media (min-width: 1441px) {
&:not(.full-width) {
margin: 0 auto;
@@ -40,11 +41,23 @@
--separator-display: block;
--separator-height: #{functions.px-to-rem(34px)};
}
+
+ &::before {
+ display: block;
+ content: '';
+ position: absolute;
+ top: 0px;
+ height: var(--meta-header-height);
+ background-color: color.$gray-background-light;
+ left: 50%;
+ width: 50%;
+ }
}
}
.meta-navigation {
.horizontal & {
+ position: relative;
padding-right: 1rem;
}
}
diff --git a/packages/internet-header/src/data/store.ts b/packages/internet-header/src/data/store.ts
index c85d1fe84b..0c99a42261 100644
--- a/packages/internet-header/src/data/store.ts
+++ b/packages/internet-header/src/data/store.ts
@@ -2,6 +2,7 @@ import { createStore } from '@stencil/store';
import { Environment, ILocalizedConfig, ILocalizedCustomConfig } from '../models/general.model';
import { NavMainEntity } from '../models/header.model';
import { IAvailableLanguage } from '../models/language.model';
+import { StickynessOptions } from '../components';
export interface HeaderState {
localizedConfig: ILocalizedConfig | null;
@@ -14,6 +15,7 @@ export interface HeaderState {
languageSwitchOverrides?: IAvailableLanguage[];
localizedCustomConfig?: ILocalizedCustomConfig;
osFlyoutOverrides?: NavMainEntity;
+ stickyness: StickynessOptions;
}
export const { state, reset, dispose } = createStore({
@@ -24,4 +26,5 @@ export const { state, reset, dispose } = createStore({
search: true,
login: true,
meta: true,
+ stickyness: 'minimal',
});