Skip to content

Commit

Permalink
Merge pull request #2757 from contentful/feat/AHOY-3140-add-avatar-in…
Browse files Browse the repository at this point in the history
…itials

feat: update Avatar and Navbar.Account to display initials if avatar is not available [AHOY-3140] [AHOY-3146]
  • Loading branch information
Annmary12 committed May 22, 2024
2 parents 488dba2 + 24d7729 commit e1091c3
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 21 deletions.
1 change: 1 addition & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@contentful/f36-image",
"@contentful/f36-header",
"@contentful/f36-layout",
"@contentful/f36-navbar",
"@contentful/f36-navlist",
"@contentful/f36-website"
],
Expand Down
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions packages/components/avatar/src/Avatar/Avatar.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ export const convertSizeToPixels = (size: AvatarProps['size']) =>
large: '48px',
}[size]);

const getInitialsFontSize = (sizePixels: string) =>
Math.round(Number(sizePixels.replace('px', '')) / 2);

export const getAvatarStyles = ({
isFallback,
size,
Expand All @@ -38,8 +41,14 @@ export const getAvatarStyles = ({
return {
fallback: css({
backgroundColor: tokens.gray200,
color: 'rgba(0,0,0,0.5)',
height: '100%',
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontStretch: 'semi-condensed',
fontSize: `${getInitialsFontSize(sizePixels)}px`,
}),
image: css({
borderRadius,
Expand Down
6 changes: 5 additions & 1 deletion packages/components/avatar/src/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface AvatarProps extends CommonProps {
alt?: ImageProps['alt'];
isLoading?: boolean;
size?: Size;
initials?: string;
src?: ImageProps['src'];
/**
* A tooltipProps attribute used to conditionally render the tooltip around root element
Expand All @@ -40,6 +41,7 @@ function _Avatar(
icon = null,
isLoading = false,
size = 'medium',
initials,
src,
testId = 'cf-ui-avatar',
tooltipProps,
Expand All @@ -65,7 +67,9 @@ function _Avatar(
{...otherProps}
>
{isFallback ? (
<div className={styles.fallback} data-test-id={`${testId}-fallback`} />
<div className={styles.fallback} data-test-id={`${testId}-fallback`}>
{initials?.substring(0, 2).toUpperCase()}
</div>
) : (
<Image
alt={alt}
Expand Down
18 changes: 18 additions & 0 deletions packages/components/avatar/stories/Avatar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default {
} as Meta;

export const Overview: Story<AvatarProps> = (args) => {
const { src, ...argsNoSrc } = args;
return (
<>
<SectionHeading as="h3" marginBottom="spacingS">
Expand All @@ -35,6 +36,22 @@ export const Overview: Story<AvatarProps> = (args) => {
<Avatar size="tiny" variant="app" />
</Flex>

<Flex
alignItems="center"
flexDirection="row"
gap="spacingS"
marginBottom="spacingM"
>
<Avatar {...argsNoSrc} size="tiny" variant="user" />
<Avatar {...argsNoSrc} size="small" variant="user" />
<Avatar {...argsNoSrc} size="medium" variant="user" />
<Avatar {...argsNoSrc} size="large" variant="app" />
<Avatar {...argsNoSrc} size="large" variant="user" />
<Avatar {...argsNoSrc} size="medium" variant="app" />
<Avatar {...argsNoSrc} size="small" variant="app" />
<Avatar {...argsNoSrc} size="tiny" variant="app" />
</Flex>

<Flex
alignItems="center"
flexDirection="row"
Expand Down Expand Up @@ -104,5 +121,6 @@ export const Overview: Story<AvatarProps> = (args) => {
};

Overview.args = {
initials: 'BB',
src: 'https://images.ctfassets.net/iq4lnigp6fgt/2EEEk92Kiz6KxREsjBLPAN/810d5a21650d91abad12e95da4cd3beb/2021-06_Everyone_is_Welcome_here_1_.png?fit=fill&f=top_left&w=100&h=100',
};
1 change: 1 addition & 0 deletions packages/components/navbar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"dependencies": {
"@contentful/f36-core": "^4.65.6",
"@contentful/f36-menu": "^4.65.6",
"@contentful/f36-avatar": "^4.0.0-alpha.11",
"@contentful/f36-tokens": "^4.0.1",
"@contentful/f36-utils": "^4.23.2",
"@contentful/f36-skeleton": "^4.65.6",
Expand Down
12 changes: 8 additions & 4 deletions packages/components/navbar/src/NavbarAccount/NavbarAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import {
type ExpandProps,
} from '@contentful/f36-core';
import { NavbarMenu } from '../NavbarMenu/NavbarMenu';
import { Avatar } from '@contentful/f36-avatar';

type NavbarAccountOwnProps = CommonProps & {
children: React.ReactNode;
username: string;
avatar: string;
avatar?: string;
initials?: string;
hasNotification?: boolean;
/**
* @default 'warning'
Expand All @@ -34,6 +36,7 @@ function _NavbarAccount(
className,
testId = 'cf-ui-navbar-account-trigger',
avatar,
initials,
username,
hasNotification,
notificationVariant = 'warning',
Expand All @@ -51,10 +54,11 @@ function _NavbarAccount(
className={cx(styles.root, className)}
testId={testId}
>
<img
<Avatar
src={avatar}
alt={`Avatar for user ${username}`}
className={styles.avatar}
initials={initials}
size="small"
variant="user"
/>
{hasNotification ? (
<span className={styles.notificationIcon(notificationVariant)} />
Expand Down
105 changes: 89 additions & 16 deletions packages/components/navbar/stories/Navbar.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import type { Meta, Story } from '@storybook/react/types-6-0';

import { Navbar, type NavbarProps } from '../src';
import { Navbar } from '../src';
import { AssetIcon, EntryIcon } from '@contentful/f36-icons';
import { SectionHeading } from '@contentful/f36-typography';
import { Flex } from '@contentful/f36-core';
Expand Down Expand Up @@ -32,12 +32,15 @@ const Switcher = ({
);

const Account = ({
avatar,
initials,
hasNotification,
notificationVariant,
}: Partial<NavbarAccountProps>) => (
<Navbar.Account
username="username"
avatar="https://images.ctfassets.net/iq4lnigp6fgt/2EEEk92Kiz6KxREsjBLPAN/810d5a21650d91abad12e95da4cd3beb/2021-06_Everyone_is_Welcome_here_1_.png?fit=fill&f=top_left&w=48&h=48"
avatar={avatar}
initials={initials}
hasNotification={hasNotification}
notificationVariant={notificationVariant}
>
Expand Down Expand Up @@ -69,22 +72,59 @@ const MainItems = () => (
</>
);

export const Basic: Story<NavbarProps> = () => {
export const Basic: Story<{ initials?: string; avatar?: string }> = (args) => {
return (
<div style={{ width: '900px' }}>
<Navbar switcher={<Switcher />} account={<Account />}>
<Navbar switcher={<Switcher />} account={<Account {...args} />}>
<MainItems />
</Navbar>
</div>
);
};

export const Complete: Story<NavbarProps> = () => {
Basic.args = {
initials: 'AB',
avatar:
'https://images.ctfassets.net/iq4lnigp6fgt/2EEEk92Kiz6KxREsjBLPAN/810d5a21650d91abad12e95da4cd3beb/2021-06_Everyone_is_Welcome_here_1_.png?fit=fill&f=top_left&w=100&h=100',
};

export const WithInitialsAvatar: Story<{
initials?: string;
avatar?: string;
}> = (args) => {
return (
<div style={{ width: '900px' }}>
<Navbar switcher={<Switcher />} account={<Account {...args} />}>
<MainItems />
</Navbar>
</div>
);
};

WithInitialsAvatar.args = {
initials: 'AB',
};

export const WithFallbackAvatar: Story<{}> = (args) => {
return (
<div style={{ width: '900px' }}>
<Navbar switcher={<Switcher />} account={<Account {...args} />}>
<MainItems />
</Navbar>
</div>
);
};

WithFallbackAvatar.args = {};

export const Complete: Story<{ initials?: string; avatar?: string }> = (
args,
) => {
return (
<div style={{ width: '900px' }}>
<Navbar
switcher={<Switcher />}
account={<Account />}
account={<Account {...args} />}
help={
<Navbar.Help>
<Navbar.MenuItem
Expand Down Expand Up @@ -142,15 +182,24 @@ export const Complete: Story<NavbarProps> = () => {
);
};

export const WithDifferentEnviromnments: Story<NavbarProps> = () => {
Complete.args = {
initials: 'AB',
avatar:
'https://images.ctfassets.net/iq4lnigp6fgt/2EEEk92Kiz6KxREsjBLPAN/810d5a21650d91abad12e95da4cd3beb/2021-06_Everyone_is_Welcome_here_1_.png?fit=fill&f=top_left&w=100&h=100',
};

export const WithDifferentEnvironments: Story<{
initials?: string;
avatar?: string;
}> = (args) => {
return (
<Flex flexDirection="column" gap="spacingL" style={{ width: '900px' }}>
<Flex flexDirection="column">
<SectionHeading as="h3" marginBottom="spacingS">
Master
</SectionHeading>

<Navbar switcher={<Switcher />} account={<Account />}>
<Navbar switcher={<Switcher />} account={<Account {...args} />}>
<MainItems />
</Navbar>
</Flex>
Expand All @@ -162,7 +211,7 @@ export const WithDifferentEnviromnments: Story<NavbarProps> = () => {

<Navbar
switcher={<Switcher envVariant="non-master">development</Switcher>}
account={<Account />}
account={<Account {...args} />}
>
<MainItems />
</Navbar>
Expand All @@ -175,7 +224,7 @@ export const WithDifferentEnviromnments: Story<NavbarProps> = () => {

<Navbar
switcher={<Switcher isAlias>staging</Switcher>}
account={<Account />}
account={<Account {...args} />}
>
<MainItems />
</Navbar>
Expand All @@ -192,7 +241,7 @@ export const WithDifferentEnviromnments: Story<NavbarProps> = () => {
dev
</Switcher>
}
account={<Account />}
account={<Account {...args} />}
>
<MainItems />
</Navbar>
Expand All @@ -201,15 +250,27 @@ export const WithDifferentEnviromnments: Story<NavbarProps> = () => {
);
};

export const WithAccountNotification: Story<NavbarProps> = () => {
WithDifferentEnvironments.args = {
initials: 'AB',
avatar:
'https://images.ctfassets.net/iq4lnigp6fgt/2EEEk92Kiz6KxREsjBLPAN/810d5a21650d91abad12e95da4cd3beb/2021-06_Everyone_is_Welcome_here_1_.png?fit=fill&f=top_left&w=100&h=100',
};

export const WithAccountNotification: Story<{
initials?: string;
avatar?: string;
}> = (args) => {
return (
<Flex flexDirection="column" gap="spacingL" style={{ width: '900px' }}>
<Flex flexDirection="column">
<SectionHeading as="h3" marginBottom="spacingS">
Warning
</SectionHeading>

<Navbar switcher={<Switcher />} account={<Account hasNotification />}>
<Navbar
switcher={<Switcher />}
account={<Account {...args} hasNotification />}
>
<MainItems />
</Navbar>
</Flex>
Expand All @@ -221,7 +282,9 @@ export const WithAccountNotification: Story<NavbarProps> = () => {

<Navbar
switcher={<Switcher />}
account={<Account hasNotification notificationVariant="negative" />}
account={
<Account {...args} hasNotification notificationVariant="negative" />
}
>
<MainItems />
</Navbar>
Expand All @@ -234,7 +297,9 @@ export const WithAccountNotification: Story<NavbarProps> = () => {

<Navbar
switcher={<Switcher />}
account={<Account hasNotification notificationVariant="info" />}
account={
<Account {...args} hasNotification notificationVariant="info" />
}
>
<MainItems />
</Navbar>
Expand All @@ -243,7 +308,13 @@ export const WithAccountNotification: Story<NavbarProps> = () => {
);
};

export const LoadingSkeleton: Story<NavbarProps> = () => {
WithAccountNotification.args = {
initials: 'AB',
avatar:
'https://images.ctfassets.net/iq4lnigp6fgt/2EEEk92Kiz6KxREsjBLPAN/810d5a21650d91abad12e95da4cd3beb/2021-06_Everyone_is_Welcome_here_1_.png?fit=fill&f=top_left&w=100&h=100',
};

export const LoadingSkeleton: Story<{}> = () => {
return (
<div style={{ width: '900px' }}>
<Navbar
Expand All @@ -263,3 +334,5 @@ export const LoadingSkeleton: Story<NavbarProps> = () => {
</div>
);
};

LoadingSkeleton.args = {};

0 comments on commit e1091c3

Please sign in to comment.