Skip to content

Commit

Permalink
Merge branch 'main' into 3434-component-spacing-utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
alizedebray committed Sep 27, 2024
2 parents 0206600 + d6033c5 commit b358340
Show file tree
Hide file tree
Showing 15 changed files with 252 additions and 63 deletions.
5 changes: 5 additions & 0 deletions .changeset/six-spiders-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-documentation': minor
---

Added documentation for design principles.
2 changes: 1 addition & 1 deletion .github/actions/setup-netlify-cli/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ runs:
steps:
- name: Install netlify-cli
shell: bash
run: pnpm i -g netlify-cli@17
run: pnpm i -g netlify-cli@17.36.1
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export class PostAccordion {

@Listen('postToggle')
collapseToggleHandler(event: CustomEvent<boolean>) {
event.stopPropagation();

const toggledItem = event.target as HTMLElement;
const closestParentAccordion = toggledItem.closest('post-accordion');

Expand Down
2 changes: 1 addition & 1 deletion packages/documentation/.storybook/addons/addons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
top: -5px;
right: 0;
padding: post.$size-mini;
background-color: var(--post-light);
background-color: post.$white;
border: post.$border-width solid post.$border-color;
border-radius: post.$border-radius;
font-size: post.$font-size-sm;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,101 +1,146 @@
import React, { useEffect, useState } from 'react';
import { IconButton, WithTooltip } from '@storybook/components';

const STYLESHEET_ID = 'preview-stylesheet';
const THEMES = ['Post'] as const;
const CHANNELS = ['External', 'Internal'] as const;
const MODES = ['Light', 'Dark'] as const;

/*
* Stylesheets
*/
const getStylesheetUrl = (theme: string, channel: string) => {
return `/styles/${theme.toLowerCase()}-${channel.toLowerCase()}.css`;
};
const possibleStylesheets = THEMES.flatMap(theme => {
return CHANNELS.map(channel => getStylesheetUrl(theme, channel));
});

/*
* Backgrounds
*/
const backgroundClasses: { [key in (typeof MODES)[number]]: string } = {
Light: 'bg-white',
Dark: 'bg-dark',
};
const getBackgroundClass = (mode: string) => {
return mode in backgroundClasses ? backgroundClasses[mode] : '';
};
const possibleBackgrounds = MODES.map(mode => getBackgroundClass(mode));

/*
* Local storage access
*/
const STORAGE_KEY_PREFIX = 'swisspost-documentation';
const THEMES = ['Post'];
const CHANNELS = ['External', 'Internal'];
const MODES = ['Light', 'Dark'];
const store = (key: string, value: string) => {
return localStorage.setItem(`${STORAGE_KEY_PREFIX}-${key}`, value);
};
const stored = (key: string): string => {
return localStorage.getItem(`${STORAGE_KEY_PREFIX}-${key}`);
};

/*
* Helpers
*/
const debounce = <T extends unknown[]>(callback: (...args: T) => void, timeout: number) => {
let timer;
return (...args: T) => {
clearTimeout(timer);
timer = setTimeout(() => {
callback(...args);
}, timeout);
};
};

function StylesSwitcher() {
const [currentTheme, setCurrentTheme] = useState<string>(
localStorage.getItem(`${STORAGE_KEY_PREFIX}-theme`) || THEMES[0],
);
const [currentChannel, setCurrentChannel] = useState<string>(
localStorage.getItem(`${STORAGE_KEY_PREFIX}-channel`) || CHANNELS[0],
);
const [currentMode, setCurrentMode] = useState<string>(
localStorage.getItem(`${STORAGE_KEY_PREFIX}-mode`) || MODES[0],
);
let observer: MutationObserver;

/**
* Sets the 'data-color-mode' attribute and preview stylesheet when the addon initializes
*/
useEffect(() => {
setPreviewStylesheet();
setDataColorModeAttribute();
});
const [currentTheme, setCurrentTheme] = useState<string>(stored('theme') || THEMES[0]);
const [currentChannel, setCurrentChannel] = useState<string>(stored('channel') || CHANNELS[0]);
const [currentMode, setCurrentMode] = useState<string>(stored('mode') || MODES[0]);

const [preview, setPreview] = useState<Document>();
const [stories, setStories] = useState<NodeListOf<Element>>();

/**
* Sets the stylesheet matching the selected theme and channel in the preview document head
* Retrieves the preview document after the first rendering
*/
const setPreviewStylesheet = () => {
const preview = getPreviewDocument();
const previewHead = preview && preview.querySelector('head');
useEffect(() => {
const previewIFrame = document.querySelector('iframe#storybook-preview-iframe');

if (!previewHead) return;
if (!previewIFrame) return;

let stylesheetLink = previewHead.querySelector(`#${STYLESHEET_ID}`);
previewIFrame.addEventListener('load', () => {
setPreview((previewIFrame as HTMLIFrameElement).contentWindow.document);
});
}, []);

if (!stylesheetLink) {
stylesheetLink = document.createElement('link');
stylesheetLink.setAttribute('rel', 'stylesheet');
stylesheetLink.setAttribute('id', STYLESHEET_ID);
previewHead.appendChild(stylesheetLink);
}
/**
* Retrieves all the stories when the preview content changes
*/
useEffect(() => {
if (!preview || observer) return;

stylesheetLink.setAttribute(
'href',
`/styles/${currentTheme.toLowerCase()}-${currentChannel.toLowerCase()}.css`,
observer = new MutationObserver(
debounce(() => {
setStories(preview.querySelectorAll('.sbdocs-preview, .sb-main-padded'));
}, 200),
);
};

observer.observe(preview.body, { childList: true, subtree: true });
}, [preview]);

/**
* Sets the 'data-color-mode' attribute of the preview body to match the selected mode
* Sets the expected stylesheet in the preview head when the theme or channel changes
*/
const setDataColorModeAttribute = () => {
const preview = getPreviewDocument();
useEffect(() => {
if (!preview) return;

const mode = currentMode.toLowerCase();
const storyContainers = preview.querySelectorAll('.sbdocs-preview, .sb-main-padded');
storyContainers.forEach(storyContainer => {
storyContainer.classList.remove('bg-light', 'bg-dark');
storyContainer.classList.add(`bg-${mode}`);
storyContainer.setAttribute('data-color-mode', mode);
possibleStylesheets.forEach(stylesheet => {
const stylesheetLink = preview.head.querySelector(`link[href="${stylesheet}"]`);
if (stylesheetLink) stylesheetLink.remove();
});
};

preview.head.insertAdjacentHTML(
'beforeend',
`<link rel="stylesheet" href="${getStylesheetUrl(currentTheme, currentChannel)}" />`,
);
}, [preview, currentTheme, currentChannel]);

/**
* Returns the Document contained in the preview iframe
* Sets the expected 'data-color-mode' attribute on all story containers when the mode changes
*/
const getPreviewDocument = (): Document | undefined => {
const preview = document.querySelector('#storybook-preview-iframe');
return preview && (preview as HTMLIFrameElement).contentWindow.document;
};
useEffect(() => {
if (!stories) return;

stories.forEach(story => {
story.classList.remove(...possibleBackgrounds);
story.classList.add(getBackgroundClass(currentMode));
story.setAttribute('data-color-mode', currentMode.toLowerCase());
});
}, [stories, currentMode]);

/**
* Applies selected theme and registers it to the local storage
*/
const applyTheme = (theme: string) => {
store('theme', theme);
setCurrentTheme(theme);
localStorage.setItem(`${STORAGE_KEY_PREFIX}-theme`, theme);
};

/**
* Applies selected channel and registers it to the local storage
*/
const applyChannel = (channel: string) => {
store('channel', channel);
setCurrentChannel(channel);
localStorage.setItem(`${STORAGE_KEY_PREFIX}-channel`, channel);
};

/**
* Applies selected mode and registers it to the local storage
*/
const applyMode = (mode: string) => {
store('mode', mode);
setCurrentMode(mode);
localStorage.setItem(`${STORAGE_KEY_PREFIX}-mode`, mode);
};

return (
Expand Down
1 change: 1 addition & 0 deletions packages/documentation/.storybook/preview-head.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="manifest" href="/site.webmanifest" />
<link rel="stylesheet" href="/styles/post-external.css" />

<meta name="design-system-settings" data-post-icon-base="/post-icons" />
<meta http-equiv="Content-Security-Policy" content="connect-src 'self' *.coveo.com *.post.ch" />
Expand Down
1 change: 1 addition & 0 deletions packages/documentation/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const preview: Preview = {
'Getting Started',
[
'Introduction',
'Design Principles',
'Mission',
'Angular',
'Compatibility',
Expand Down
4 changes: 4 additions & 0 deletions packages/documentation/.storybook/styles/preview.scss
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@
overflow-x: hidden;
}

.sbdocs-preview:not([data-color-mode]) {
display: none;
}

.fake-content {
position: relative;
min-height: calc(1.6rem * 8);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
interface Principles {
icon: string;
title: string;
description: string;
}

export const principles: Principles[] = [
{
icon: '2525',
title: 'Easy to use',
description:
'Create easy-to-use design patterns that consider the five elements of usability: Effectiveness, Efficiency, Engagement, Error Tolerance, and Ease of learning. This helps us to promote industry standards amongst our community and lowers the barrier of entry for new employees.',
},
{
icon: '2526',
title: 'Trustworthy',
description:
'We establish mutual trust with our stakeholders by creating robust and consistent patterns, maintaining comprehensive documentation, communicating transparently, and actively engaging with our community. Through these efforts, we ensure that our stakeholders can rely on our work. As a result, we can scale adoption across the organization, unlocking our full efficiency potential.',
},
{
icon: '2527',
title: 'Cordial',
description:
'We approach our customers on equal footing. By aligning our communication patterns with the Posts’ guidelines, we ensure that our interactions mirror how Post employees engage with clients: cordially, courteously, anticipatively, and empathically. Our goal is to foster the same strong bond between customers and the Post that exists beyond digital channels.',
},
{
icon: '2524',
title: 'Inclusive',
description:
'We promote inclusivity. We’re designing for diverse abilities, access to technology, literacy, economic circumstances, educational backgrounds, geographic locations, ages, and languages. With this approach, we ensure that everyone can use the public services we provide.',
},
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Meta } from '@storybook/blocks';
import * as DesignPrinciplesStories from './design-principles.stories';
import './design-principles.styles.scss';
import { principles } from './design-principles.data';

<Meta of={DesignPrinciplesStories} />

# Design Principles

Our aim is to make things simple, trustworthy, and inclusive. We create easy-to-use designs, build trust with clear communication, and ensure everyone feels included.

## Core Principles

<div className="row principle-container">
{principles.map((principle, index) => (
<div className="col-lg-3 principle-container--item" key={index}>
<div className="principle">
<post-icon name={principle.icon} style={{ fontSize: '3rem' }}></post-icon>
<h3 className="principle--title mt-20">{principle.title}</h3>
<p className="principle--description">{principle.description}</p>
</div>
</div>
))}
</div>

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { MetaExtended } from '@root/types';
import { StoryObj } from '@storybook/web-components';

const meta: MetaExtended = {
id: '43f5818c-98a0-48ba-84f1-bf4d8fe1e70d',
title: 'Getting Started/Design Principles',
parameters: {
badges: [],
},
};

export default meta;

type Story = StoryObj;

export const Default: Story = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@use '@swisspost/design-system-styles/core.scss' as post;

.principle-container {
padding: 0;

&-container--item {
display: flex;
align-items: stretch;
}
}

.principle {
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
padding: 2rem;
height: 100%;

&--title {
font-size: post.$font-size-regular;
}

&--description {
font-size: post.$font-size-sm;
margin-top: 1rem;
}
}
1 change: 1 addition & 0 deletions packages/styles/src/components/card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
// Outline with card-group margin trick prevents double/jumping (on hover) borders
outline: 1px solid card.$card-border-color;
box-shadow: commons.$box-shadow-lg;
color: card.$card-color;

&.product-card,
&.card-button {
Expand Down
1 change: 1 addition & 0 deletions packages/styles/src/variables/components/_card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ $card-inner-border-radius: calc(
) !default; // Design System
$card-cap-bg: color.$light !default;
$card-bg: color.$white !default;
$card-color: color.$black !default;

$card-img-overlay-padding: $card-spacer-x !default;

Expand Down
Loading

0 comments on commit b358340

Please sign in to comment.