Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(components, components-angular, documentation): add new post-avatar component #3352

Merged
merged 54 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
3ed0e19
feat(components, components-angular): add component `post-avatar-pict…
oliverschuerch Jul 25, 2024
a0caedb
feat(documentation): add docs for post-avatar-picture
oliverschuerch Jul 25, 2024
4e08608
test(documentation): add snapshot test for avatar-picture component
oliverschuerch Jul 26, 2024
3564425
chore(components): remove hover styling for avatar-picture component
oliverschuerch Jul 26, 2024
aae95b6
feat(components): update styles for avatar-picture component
oliverschuerch Jul 26, 2024
9209f4c
test(documentation): add snapshot test for avatar-picture component
oliverschuerch Jul 26, 2024
e7aae5b
chore: update changeset
oliverschuerch Jul 26, 2024
c683fe1
test(components): add e2e tests for avatar-picture component
oliverschuerch Jul 26, 2024
d374a0b
chore(components-angular): implement post-avatar-picture component in…
oliverschuerch Aug 12, 2024
abff81a
Merge branch 'main' into feat/3210-component-profile-picture
oliverschuerch Aug 12, 2024
6a6cdb5
feat(components): implement change requests for post-avatar-picture c…
oliverschuerch Aug 12, 2024
7980326
test(documentation): update avatar-picture snapshot tests
oliverschuerch Aug 12, 2024
e8d52d1
refactor(components): replace crypto-js dependency with native crypto…
oliverschuerch Aug 12, 2024
5a37d6d
refactor(components): move static gravatar-sizes witin post-avatar-pi…
oliverschuerch Aug 12, 2024
13e52fe
fix(documentation): implement change requests
oliverschuerch Aug 12, 2024
0944c64
feat(documentation): update avatar-picture docs
oliverschuerch Aug 12, 2024
0e50fef
Merge branch 'main' into feat/3210-component-profile-picture
oliverschuerch Aug 12, 2024
e46f10f
fix(components): update watched prop for property checker of post-ava…
oliverschuerch Aug 13, 2024
2cb0a3c
refactor(components): implement cange-requests for post-avatar-pictur…
oliverschuerch Aug 13, 2024
c6cf91d
Merge branch 'main' into feat/3210-component-profile-picture
oliverschuerch Aug 13, 2024
0ff7010
refactor(documentation): add size large as default value for post-ava…
oliverschuerch Aug 13, 2024
0778728
fix(styles): gulpfile copy token-files error
oliverschuerch Aug 13, 2024
dc2aefc
chore: update lock file
oliverschuerch Aug 13, 2024
1b39dfb
test(components): fix avatar-picture e2e tests
oliverschuerch Aug 13, 2024
14ad494
rename post-avatar-picture to post-avatar
alizedebray Aug 20, 2024
a29c72a
Merge branch 'main' into feat/3210-component-profile-picture
alizedebray Aug 20, 2024
84acf91
fix e2e
alizedebray Aug 20, 2024
1201320
Merge branch 'feat/3210-component-profile-picture' of https://github.…
alizedebray Aug 20, 2024
0f5fcc9
Merge branch 'main' into feat/3210-component-profile-picture
oliverschuerch Sep 11, 2024
ee4773c
Update packages/components/src/components/post-avatar/post-avatar.scss
oliverschuerch Sep 11, 2024
972b46e
feat(components): implement sessionStorage for gravatar image
oliverschuerch Sep 11, 2024
0c95295
Merge branch 'feat/3210-component-profile-picture' of https://github.…
oliverschuerch Sep 11, 2024
b1c0c98
feat(components): add slot for custom image and userid to fetch inter…
oliverschuerch Sep 12, 2024
742a9b5
Update packages/documentation/src/stories/components/avatar/avatar.do…
oliverschuerch Oct 10, 2024
351c06f
feat(compnents, documentation): update post-avatar component
oliverschuerch Oct 10, 2024
c6e609e
Merge branch 'feat/3210-component-profile-picture' of https://github.…
oliverschuerch Oct 10, 2024
5852933
feat(components, documentation): add bg and fg color variables
oliverschuerch Oct 10, 2024
b7ad9c6
Merge branch 'main' into feat/3210-component-profile-picture
oliverschuerch Oct 10, 2024
4c803b7
fix(components): fix sonar reported code smell in post-avatar component
oliverschuerch Oct 11, 2024
151efe6
feat(components): update post-avatar to match v2 styles (tokens not y…
oliverschuerch Oct 11, 2024
a3fb59c
Merge branch 'main' into feat/3210-component-profile-picture
oliverschuerch Oct 11, 2024
b21a32b
chore(components): update post-avatar styles to the new tokens.get wo…
oliverschuerch Oct 11, 2024
4ace470
chore(components): add anchor and button wrapper stories
oliverschuerch Oct 15, 2024
aa03c99
feat(styles): add post-avatar specific styles when nested in anchor o…
oliverschuerch Oct 15, 2024
469b45c
Merge branch 'main' into feat/3210-component-profile-picture
oliverschuerch Oct 15, 2024
8777268
chore: implement tokens
oliverschuerch Oct 15, 2024
7d3a474
chore(components): remove unnecessary import in post-avatar component
oliverschuerch Oct 16, 2024
5e71027
test: update e2e tests and snapshot stories
oliverschuerch Oct 16, 2024
c758a9c
chore(components): implement open change requests
oliverschuerch Oct 18, 2024
2c98d4e
chore(components): do not set the alt attribute on a slotted image in…
oliverschuerch Oct 18, 2024
de69a32
Merge branch 'main' into feat/3210-component-profile-picture
oliverschuerch Oct 18, 2024
81a99e5
chore(styles): remove post-avatar specific focus tokens
oliverschuerch Oct 18, 2024
4b0ab7f
refactor(styles): create a standalone SCSS file for the post-avatar c…
oliverschuerch Oct 18, 2024
c39d13e
Merge branch 'main' into feat/3210-component-profile-picture
oliverschuerch Oct 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/giant-games-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@swisspost/design-system-components': minor
'@swisspost/design-system-components-angular': minor
'@swisspost/design-system-documentation': minor
---

Added component `post-avatar` to show an avatar, based on different possible input data (gravatar by email, initials by first- and/or lastname, fallback).
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ <h2>Post Alert</h2>
<post-alert><p>Contentus momentus vero siteos et accusam iretea et justo.</p></post-alert>
</div>

<div class="my-4">
<h2>Post Avatar</h2>
<post-avatar></post-avatar>
</div>

<div class="my-4">
<h2>Post Card-Control</h2>
<post-card-control type="checkbox" label="label"></post-card-control>
Expand Down
83 changes: 83 additions & 0 deletions packages/components/cypress/e2e/avatar.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const PAGE_ID = '09aac03d-220e-4885-8fb8-1cfa01add188';

describe('Avatar', () => {
describe('Structure & Props', () => {
beforeEach(() => {
cy.getComponent('post-avatar', PAGE_ID);
cy.window().then(win => {
cy.wrap(cy.spy(win.console, 'error')).as('consoleError');
});
});

it('should have no console errors', () => {
cy.get('@consoleError').should('not.be.called');
});

it('should have only attribute firstname and class "large" by default', () => {
cy.get('@avatar').should('exist');
cy.get('@avatar').should('not.have.attr', 'size');
cy.get('@avatar').should('not.have.attr', 'email');
cy.get('@avatar').should('have.attr', 'firstname');
cy.get('@avatar').should('not.have.attr', 'lastname');
cy.get('@avatar').should('have.class', 'large');
cy.get('@avatar').should('not.have.class', 'small');
});

it('should have class "small", when size attribute is set to "small"', () => {
cy.get('@avatar').invoke('attr', 'size', 'small');
cy.get('@avatar').should('have.class', 'small');
cy.get('@avatar').should('not.have.class', 'large');
});

it('should have a console error, when attribute "firstname" is not defined', () => {
cy.get('@avatar').invoke('removeAttr', 'firstname');
cy.get('@consoleError').should('have.been.calledOnce');
});

it('should show initials when, firstname and lastname is defined', () => {
cy.get('@avatar').invoke('attr', 'firstname', 'Open');
cy.get('@avatar').invoke('attr', 'lastname', 'Source');
cy.get('@avatar').find('img').should('not.exist');
cy.get('@avatar').find('div').should('exist').and('have.text', 'OS');
cy.get('@consoleError').should('not.have.been.called');

cy.get('@avatar').invoke('removeAttr', 'lastname');
cy.get('@avatar').find('img').should('not.exist');
cy.get('@avatar').find('div').should('exist').and('have.text', 'O');
cy.get('@consoleError').should('not.have.been.called');

cy.get('@avatar').invoke('removeAttr', 'firstname');
cy.get('@avatar').find('img').should('not.exist');
cy.get('@consoleError').should('have.been.calledOnce');
});

it('should show image when, email with gravatar account is defined', () => {
cy.get('@avatar').invoke('attr', 'email', '[email protected]');
cy.get('@avatar').should('have.attr', 'email');
cy.get('@avatar').should('have.attr', 'firstname');
cy.get('@avatar').find('img').should('exist');
cy.get('@avatar').find('div').should('not.exist');

cy.get('@avatar').invoke('removeAttr', 'email');
cy.get('@avatar').find('img').should('not.exist');
cy.get('@avatar').find('div').should('exist');
cy.get('@consoleError').should('not.have.been.called');
});

it('should show initials when, email with no gravatar account is defined', () => {
cy.get('@avatar').invoke('attr', 'email', '[email protected]');
cy.get('@avatar').should('have.attr', 'email');
cy.get('@avatar').should('have.attr', 'firstname');
cy.get('@avatar').find('img').should('not.exist');
cy.get('@avatar').find('div').should('exist');
cy.get('@consoleError').should('not.have.been.called');
});
});

describe('Accessibility', () => {
it('Has no detectable a11y violations on load for all variants', () => {
cy.getSnapshots('avatar');
cy.checkA11y('#root-inner');
});
});
});
45 changes: 45 additions & 0 deletions packages/components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,24 @@ export namespace Components {
*/
"type": AlertType;
}
interface PostAvatar {
/**
* Defines the users email address.
*/
"email"?: string;
/**
* Defines the users firstname.
*/
"firstname": string;
/**
* Defines the users lastname.
*/
"lastname"?: string;
/**
* Defines the size of the avatar.
*/
"size"?: 'large' | 'small';
}
/**
* @class PostCardControl - representing a stencil component
*/
Expand Down Expand Up @@ -375,6 +393,12 @@ declare global {
prototype: HTMLPostAlertElement;
new (): HTMLPostAlertElement;
};
interface HTMLPostAvatarElement extends Components.PostAvatar, HTMLStencilElement {
}
var HTMLPostAvatarElement: {
prototype: HTMLPostAvatarElement;
new (): HTMLPostAvatarElement;
};
interface HTMLPostCardControlElementEventMap {
"postInput": { state: boolean; value: string };
"postChange": { state: boolean; value: string };
Expand Down Expand Up @@ -520,6 +544,7 @@ declare global {
"post-accordion": HTMLPostAccordionElement;
"post-accordion-item": HTMLPostAccordionItemElement;
"post-alert": HTMLPostAlertElement;
"post-avatar": HTMLPostAvatarElement;
"post-card-control": HTMLPostCardControlElement;
"post-collapsible": HTMLPostCollapsibleElement;
"post-collapsible-trigger": HTMLPostCollapsibleTriggerElement;
Expand Down Expand Up @@ -583,6 +608,24 @@ declare namespace LocalJSX {
*/
"type"?: AlertType;
}
interface PostAvatar {
/**
* Defines the users email address.
*/
"email"?: string;
/**
* Defines the users firstname.
*/
"firstname": string;
/**
* Defines the users lastname.
*/
"lastname"?: string;
/**
* Defines the size of the avatar.
*/
"size"?: 'large' | 'small';
}
/**
* @class PostCardControl - representing a stencil component
*/
Expand Down Expand Up @@ -795,6 +838,7 @@ declare namespace LocalJSX {
"post-accordion": PostAccordion;
"post-accordion-item": PostAccordionItem;
"post-alert": PostAlert;
"post-avatar": PostAvatar;
"post-card-control": PostCardControl;
"post-collapsible": PostCollapsible;
"post-collapsible-trigger": PostCollapsibleTrigger;
Expand All @@ -817,6 +861,7 @@ declare module "@stencil/core" {
"post-accordion": LocalJSX.PostAccordion & JSXBase.HTMLAttributes<HTMLPostAccordionElement>;
"post-accordion-item": LocalJSX.PostAccordionItem & JSXBase.HTMLAttributes<HTMLPostAccordionItemElement>;
"post-alert": LocalJSX.PostAlert & JSXBase.HTMLAttributes<HTMLPostAlertElement>;
"post-avatar": LocalJSX.PostAvatar & JSXBase.HTMLAttributes<HTMLPostAvatarElement>;
/**
* @class PostCardControl - representing a stencil component
*/
Expand Down
78 changes: 78 additions & 0 deletions packages/components/src/components/post-avatar/aiconizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const ACTIVATOR = 'avatar';
const ICONIZER = {
gallileo: '2136',
home: '3136',
love: '2586',
postman: '1007',
potter: '2493',
ra: '2199',
rocket: '2383',
sido: '2397',
smart: '2165',
stamp: '1022',
ux: '2198',
workout: '2555',
};
let input1 = '';
let input2 = '';

function aiconizer(e) {
if (['INPUT', 'SELECT', 'TEXTAREA'].includes(e.target.tagName)) return;

if (input1 !== ACTIVATOR) {
input1 = (input1 + e.key).substring(Math.max(0, (input1 + e.key).length - ACTIVATOR.length));
} else {
input2 = (input2 + e.key).substring(Math.max(0, (input2 + e.key).length - 10));
const match = Object.entries(ICONIZER).find(([k]) => input2.includes(k));

if (input2.includes('help')) {
const keys = Object.keys(ICONIZER)
.map(k => `"${k}"`)
.join(', ');

console.log(
`%cCongrats, you have found an easter egg!%c\nClick in an empty area of the page and type:\n%c"${ACTIVATOR}"%c\nAnd then one of the following phrases:\n%c${keys}%c\nThis will let the post-avatar component display different icons.\nHave fun!`,
'font-size: 20px; font-weight: bold;',
'font-size: unset; font-weight: normal;',
'font-weight: bold; color: red;',
'font-weight: normal; color: unset;',
'font-weight: bold; color: red;',
'font-weight: normal; color: unset;',
);

input1 = '';
input2 = '';
}

if (match) {
Array.from(document.querySelectorAll('post-avatar')).forEach(el => {
const postIcon = document.createElement('post-icon');
postIcon.setAttribute('name', match[1]);

el.shadowRoot.querySelector('img')?.remove();
el.shadowRoot.querySelector('div')?.remove();
el.shadowRoot.querySelector('post-icon')?.remove();
el.shadowRoot.append(postIcon);

setTimeout(() => {
input1 = '';
input2 = '';
});
});
}
}
}

function register() {
window.removeEventListener('keydown', aiconizer);
window.addEventListener('keydown', aiconizer);
}

function destroy() {
window.removeEventListener('keydown', aiconizer);
}

export default {
register,
destroy,
};
37 changes: 37 additions & 0 deletions packages/components/src/components/post-avatar/post-avatar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@use '@swisspost/design-system-styles/core' as post;

:host {
display: inline-block;
width: 40px;
height: 40px;
}

:host(.small) {
width: 32px;
height: 32px;
oliverschuerch marked this conversation as resolved.
Show resolved Hide resolved
font-size: post.$font-size-12;
}

img {
display: block;
width: 100%;
border-radius: 50%;
}

div,
post-icon {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background-color: #004976;
oliverschuerch marked this conversation as resolved.
Show resolved Hide resolved
border-radius: 50%;
color: post.get-best-contrast-text(#004976);
text-transform: uppercase;
box-sizing: border-box;
}

post-icon {
padding: post.$size-micro;
}
Loading
Loading