diff --git a/packages/documentation-v7/.storybook/helpers/register-web-components.ts b/packages/documentation-v7/.storybook/helpers/register-web-components.ts index a09a50def5..c5963a748c 100644 --- a/packages/documentation-v7/.storybook/helpers/register-web-components.ts +++ b/packages/documentation-v7/.storybook/helpers/register-web-components.ts @@ -1,14 +1,22 @@ -import { defineCustomElements, JSX as LocalJSX } from '@swisspost/design-system-components/loader'; -import { HTMLAttributes } from 'react'; +import { defineCustomElements as defineInternetHeader } from '@swisspost/internet-header/loader'; +import { defineCustomElements as definePostComponent } from '@swisspost/design-system-components/loader'; +import { setStencilDocJson } from '@pxtrn/storybook-addon-docs-stencil'; +import { StencilJsonDocs, StencilJsonDocsComponent } from '@pxtrn/storybook-addon-docs-stencil/dist/types'; +import postComponentsDocJson from '@swisspost/design-system-components/dist/docs.json'; +import internetHeaderDocJson from '@swisspost/internet-header/dist/docs.json'; -type StencilToReact = { - [P in keyof T]?: T[P] & Omit, 'className'> & { class?: string }; -}; +defineInternetHeader(window); +definePostComponent(window); -declare global { - export namespace JSX { - interface IntrinsicElements extends StencilToReact {} - } -} +if (postComponentsDocJson && internetHeaderDocJson) { + const jsonDocs: StencilJsonDocs = { + timestamp: postComponentsDocJson.timestamp, + compiler: postComponentsDocJson.compiler, + components: [ + ...postComponentsDocJson.components, + ...internetHeaderDocJson.components + ] as StencilJsonDocsComponent[], + }; -defineCustomElements(window); + setStencilDocJson(jsonDocs); +} diff --git a/packages/documentation-v7/.storybook/preview.ts b/packages/documentation-v7/.storybook/preview.ts index 9eb4868e07..8d05d53869 100644 --- a/packages/documentation-v7/.storybook/preview.ts +++ b/packages/documentation-v7/.storybook/preview.ts @@ -1,11 +1,6 @@ import type { Preview } from '@storybook/web-components'; -import { - extractArgTypes, - extractComponentDescription, - setStencilDocJson, -} from '@pxtrn/storybook-addon-docs-stencil'; -import { StencilJsonDocs } from '@pxtrn/storybook-addon-docs-stencil/dist/types'; +import { extractArgTypes, extractComponentDescription } from '@pxtrn/storybook-addon-docs-stencil'; import { format } from 'prettier'; import DocsLayout from './blocks/layout'; import { badgesConfig, prettierOptions, resetComponents } from './helpers'; @@ -18,10 +13,6 @@ import scss from 'react-syntax-highlighter/dist/esm/languages/prism/scss'; SyntaxHighlighter.registerLanguage('scss', scss); -import docJson from '@swisspost/design-system-components/dist/docs.json'; - -if (docJson) setStencilDocJson(docJson as StencilJsonDocs); - const preview: Preview = { parameters: { options: { @@ -34,7 +25,7 @@ const preview: Preview = { ['Typography', 'Color', 'Layout', 'Elevation', 'Accessibility'], 'Components', 'Internet Header', - ['Getting started', 'Migration Guide', 'Components', ['Header', 'Breadcrumbs', 'Footer']], + ['Getting started', 'Migration Guide', 'Header Component', 'Breadcrumbs Component', 'Footer Component'], 'Intranet Header', ['Getting started'], 'Icons', @@ -55,7 +46,6 @@ const preview: Preview = { }, components: resetComponents, extractArgTypes, - extractComponentDescription, }, actions: { argTypesRegex: '^on[A-Z].*' }, controls: { diff --git a/packages/documentation-v7/src/stories/internet-header/components/internet-header.docs.mdx b/packages/documentation-v7/src/stories/internet-header/components/internet-header.docs.mdx new file mode 100644 index 0000000000..4be69ee0f9 --- /dev/null +++ b/packages/documentation-v7/src/stories/internet-header/components/internet-header.docs.mdx @@ -0,0 +1,54 @@ +import { Canvas, ArgTypes, Meta } from '@storybook/blocks'; +import * as InternetHeaderStories from './internet-header.stories'; + + + +# Header + +
+ Customizable navigation header tailored for Swiss Post customer-facing applications, + ensuring complete accessibility and responsiveness. +
+ +The `` element needs +to be nested directly inside the `` for the sticky scrolling to work. + +If you want to render the header element with Angular, +have a look at [portals](https://medium.com/angular-in-depth/how-do-cdk-portals-work-7c097c14a494). + + + Open Header in New Tab + + + + +
+ +
+ +## Examples + +### Custom Navigation Item + + + +### Custom Online Service Flyout + + + +### Full Width + +By default, on viewports with a width greater than 1440px, header content is padded right and left. +To make the header span the full width of the viewport, set the `full-width` property to `true`. + + + See Fullwidth Header + diff --git a/packages/documentation-v7/src/stories/internet-header/components/internet-header.stories.tsx b/packages/documentation-v7/src/stories/internet-header/components/internet-header.stories.tsx new file mode 100644 index 0000000000..d2b80ec41b --- /dev/null +++ b/packages/documentation-v7/src/stories/internet-header/components/internet-header.stories.tsx @@ -0,0 +1,241 @@ +import { Args, Meta, StoryObj } from '@storybook/web-components'; +import { html } from 'lit'; +import { spread } from '@open-wc/lit-helpers'; +import { BADGE } from '../../../../.storybook/constants'; +import './internet-header.styles.scss'; + +const meta: Meta = { + title: 'Internet Header/Header Component', + component: 'swisspost-internet-header', + render: renderInternetHeader, + parameters: { + layout: 'fullscreen', + actions: { + handles: ['headerLoaded', 'languageChanged'], + }, + badges: [BADGE.STABLE], + controls: { + exclude: ['config-proxy'] + }, + }, + args: { + 'project': 'test' + }, + argTypes: { + activeRoute: { + name: 'active-route', + control: 'text', + }, + customConfig: { + name: 'custom-config', + control: 'object', + }, + language: { + control: 'select', + options: ['de', 'fr', 'it', 'en'], + }, + languageCookieKey: { + name: 'language-cookie-key', + control: 'text', + }, + languageLocalStorageKey: { + name: 'language-local-storage-key', + control: 'text', + }, + languageSwitchOverrides: { + name: 'language-switch-overrides', + control: 'object', + }, + osFlyoutOverrides: { + name: 'os-flyout-overrides', + control: 'object', + }, + stickyness: { + control: 'select', + }, + }, +}; + +export default meta; + +// DECORATORS +function mockPage(story: any) { + return html` +
+ ${story()} +
+ +

Swiss Post Internet Header

+

+

+
+ +
+ `; +} + +// RENDERER +function renderInternetHeader(args: HTMLSwisspostInternetHeaderElement) { + const attributes = getAttributes(args, arg => arg !== null && arg !== undefined); + return html` + + `; +} + +// STORIES +type Story = StoryObj; + +export const Default: Story = { + decorators: [ mockPage ], + parameters: { + docs: { + story: { + inline: false, + height: '40em', + }, + }, + }, +}; + +export const FullWidth: Story = { + decorators: [ mockPage ], + args: { + fullWidth: true, + }, +}; + +export const CustomNavigation: Story = { + args: { + customConfig: { + de: { + header: { + navMain: [ + { + title: 'Meine Links (custom config)', + text: 'Meine Links', + url: '#', + flyout: [ + { + title: 'Google', + linkList: [ + { url: 'https://maps.google.com', title: 'Google Maps', target: '_blank' }, + { url: 'https://translate.google.com', title: 'Google Translate' }, + ], + }, + ], + }, + ], + }, + }, + fr: { + header: { + navMain: [ + { + title: 'Meine Links (custom config)', + text: 'Meine Links', + url: '#', + flyout: [ + { + title: 'Google', + linkList: [ + { url: 'https://maps.google.com', title: 'Google Maps', target: '_blank' }, + { url: 'https://translate.google.com', title: 'Google Translate' }, + ], + }, + ], + }, + ], + }, + }, + it: { + header: { + navMain: [ + { + title: 'Meine Links (custom config)', + text: 'Meine Links', + url: '#', + flyout: [ + { + title: 'Google', + linkList: [ + { url: 'https://maps.google.com', title: 'Google Maps', target: '_blank' }, + { url: 'https://translate.google.com', title: 'Google Translate' }, + ], + }, + ], + }, + ], + }, + }, + en: { + header: { + navMain: [ + { + title: 'Meine Links (custom config)', + text: 'Meine Links', + url: '#', + flyout: [ + { + title: 'Google', + linkList: [ + { url: 'https://maps.google.com', title: 'Google Maps', target: '_blank' }, + { url: 'https://translate.google.com', title: 'Google Translate' }, + ], + }, + ], + }, + ], + }, + }, + }, + }, +}; + +export const CustomOnlineServiceFlyout: Story = { + args: { + osFlyoutOverrides: { + title: 'Custom OS Flyout', + text: 'Custom OS Flyout', + url: '#', + flyout: [ + { + title: 'A title', + linkList: [ + { + url: '#bla', + title: 'Another link', + }, + ], + }, + { + title: 'Another column', + linkList: [ + { + url: '#foo', + title: 'Foo', + }, + ], + }, + ], + }, + }, +}; + +// TODO: move to utils +const getAttributes = (args: Args, condition?: (arg: any) => boolean): Args => { + const attrs: { [key: string]: any } = {}; + + for (const key in args) { + if (args.hasOwnProperty(key) && condition && condition(args[key])) { + const attrKey = key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); + + // Cast boolean false to string so it's displayed in the docs code block. False values are otherwise omitted + attrs[attrKey] = args[key] === false ? 'false' : args[key]; + if (typeof args[key] === 'object') { + attrs[attrKey] = JSON.stringify(args[key]); + } + } + } + + return attrs; +}; diff --git a/packages/documentation-v7/src/stories/internet-header/components/internet-header.styles.scss b/packages/documentation-v7/src/stories/internet-header/components/internet-header.styles.scss new file mode 100644 index 0000000000..9b64d999be --- /dev/null +++ b/packages/documentation-v7/src/stories/internet-header/components/internet-header.styles.scss @@ -0,0 +1,32 @@ +.docs-story { + > div:first-child { + overflow: hidden; + } + + > div:nth-child(2) { + z-index: 1000; + } +} + +// Used for internet header stories +.fake-content { + position: relative; + min-height: calc(1.6rem * 8); + background: repeating-linear-gradient( + rgb(230, 230, 230), + rgb(230, 230, 230) 1rem, + transparent 1rem, + transparent 1.6rem + ); + + &::after { + content: ''; + background: white; + width: 33%; + height: 1.7rem; + display: block; + position: absolute; + bottom: 0; + right: 0; + } +} diff --git a/packages/documentation-v7/src/stories/internet-header/getting-started.docs.mdx b/packages/documentation-v7/src/stories/internet-header/getting-started.docs.mdx new file mode 100644 index 0000000000..5da7c225be --- /dev/null +++ b/packages/documentation-v7/src/stories/internet-header/getting-started.docs.mdx @@ -0,0 +1,113 @@ +import { Meta } from '@storybook/blocks'; +import { BADGE } from '../../../.storybook/constants'; + + + +# @swisspost/internet-header + +[![npm version](https://badge.fury.io/js/@swisspost%2Finternet-header.svg)](https://badge.fury.io/js/@swisspost%2Finternet-header) + +The header for client-facing applications. + +- [Installation](#installation) +- [Configuration](#configuration) +- [Help](#help) + +## Installation + +### Angular, Vue JS, React (or any other bundler setup) + +All the popular frameworks come with some form of bundler. +This makes it easy to use npm packages like the Internet Header as you can import, +bundle and deliver the header with your own code. + +When working with Angular or any other framework, the easiest installation method is via npm. + +```shell +npm install @swisspost/internet-header +``` + +```typescript +// main.ts / index.js / ... +import { defineCustomElements } from '@swisspost/internet-header'; + +defineCustomElements(); +``` + +```html + + + + ... + +``` + +### Include from a CDN + +If you are not using any loader or don't want to install from npm, +you can load the `internet-header` from your favourite +[CDN](https://en.wikipedia.org/wiki/Content_delivery_network).
+There are two options available. +Make sure to replace `{version}` with the version you want to use. + +- [jsDelivr](https://www.jsdelivr.com/) +- [unpkg](https://unpkg.com/) + +#### jsDelivr + +```html + + + + + + + +``` + +```javascript +// main.js | main.ts +import { defineCustomElements } from 'https://cdn.jsdelivr.net/npm/@swisspost/internet-header@{version}/loader/index.min.js'; + +defineCustomElements(); +``` + +#### unpkg + +```javascript +// main.js | main.ts +import { defineCustomElements } from 'https://unpkg.com/@swisspost/internet-header@{version}/loader/index.min.js'; + +defineCustomElements(); +``` + +## Configuration + +The Internet Header is built to support the already existing Portal Configuration used for the old Internet Header. + +If you're working on a new project, you probably need a new configuration. Please click the button below. + +Contact Post Portal Team + +Not every Online Service has configurations for all environments. +For example, "TOPOS" only has `int02` configured and cannot use `int01` as value for environment. +If you are not sure what's configured for your project, please reach out to the post-portal team as well. + +For settings on the header itself, see the examples provided in the left menu bar. + +## Help + +If you noticed a bug or need assistance with migrating to the new Internet Header, +please post your enquiry at the [Design System GitHub Discussions](https://github.com/swisspost/design-system/discussions/categories/q-a). diff --git a/packages/documentation-v7/src/stories/internet-header/migration-guide.docs.mdx b/packages/documentation-v7/src/stories/internet-header/migration-guide.docs.mdx new file mode 100644 index 0000000000..59819e4702 --- /dev/null +++ b/packages/documentation-v7/src/stories/internet-header/migration-guide.docs.mdx @@ -0,0 +1,195 @@ +import { Meta } from '@storybook/blocks'; +import { BADGE } from '../../../.storybook/constants'; + + + +# Migration from the old header + +This guide aims to give a broad overview of how a migration can be performed. +Different projects have different levels of integration with the header, +and therefore require more steps to migrate. + +## Architecture + +The "new" +Internet Header Web Component aims +to encapsulate as much as possible whereas the old header had a big influence on the page — +limiting design decisions and flexibility of the markup structure. +The Web Component Header consists of one script and three standard Web Components that can be freely placed on the page. +It's even possible to render those elements with Angular +(or any other framework) to easier pass settings into the component. + +The new header is built +to work with the existing Sitecore configuration +already existing for your project to make the migration as smooth as possible. + +## Support + +If you need support during your migration, +don't hesitate +to contact the [Design System Team](https://github.com/swisspost/design-system/discussions/categories/general) on GitHub. + +## 1. Remove the old header + +In your index.html, you should find three scripts associated with the old header. +One to load static assets, one to configure it and one to load it. + +- You can remove the configuration and the loader scripts, but remember your `serviceid`. +- Try to remove the `staticassets` script to check if you still need it + +```html + + + + + + + + + + + + +
+ +
+ + + + + + + + +``` + +## 2. Fix your app styles + +The old header was responsible for wrapping your main code (here `#os_content`) with custom `
`s. +The new header does not provide those wrappers. +Instead, every page has control over the main markup structure. +A possible replacement of the above code could be: + +```html + + + + + + + + + +
+ +
+ + +``` + +- Likely you'll need the class `container` around your main content to align it properly in the center. +- For bonus points on semantic markup, use the [`
` tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main) around the main page content +- Check if you need the `staticasset` stylesheets linked in the header + +If you need to do any other changes, +please make a post to the [Design System Teams Channel](https://teams.microsoft.com/l/channel/19%3ae7fa68fb13eb40b4bf4604edea5f4b3e%40thread.tacv2/%25F0%259F%259A%2591%2520Support?groupId=123c7c9e-052a-40e6-98d3-6cc6d46bad0a&tenantId=3ae7c479-0cf1-47f4-8f84-929f364eff67) +in order to inform the devs to update this guide and provide useful information for other developers. + +## 3. jQuery + +The new Header does not ship jQuery anymore. +While jQuery v3.6 is an internal dependency for the Login Widget, +every project is now responsible for loading and updating jQuery individually. +If you are depending on an older (<3.5) version of jQuery, please update. +There is a long list of [known jQuery vulnerabilities](https://security.snyk.io/package/npm/jquery). + +## 4. Install the new header + +Please refer to the [Internet Header installation instructions](/story/getting-started--page) for an installation guide. + +After installation, you're ready to add the new tags to your markup: + +```html + + + + + + + + + + + + + + +
+ +
+ + + + +``` + +Place the new elements as described (and needed) as shown above. +The breadcrumbs need a `container` wrapper to align themselves with the content of your page, +the header and the footer already provide a container. +If you don't have breadcrumbs, you can just delete the `