Skip to content

Commit

Permalink
60 Avatar size and shape (#64)
Browse files Browse the repository at this point in the history
* Avatar size and shape properties

* avatar styles

* tests

* upgrade deps
  • Loading branch information
mwarman authored Aug 26, 2024
1 parent 067c74f commit 3cb2ed3
Show file tree
Hide file tree
Showing 14 changed files with 629 additions and 572 deletions.
987 changes: 482 additions & 505 deletions package-lock.json

Large diffs are not rendered by default.

40 changes: 20 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
"@capacitor/app": "6.0.0",
"@capacitor/app": "6.0.1",
"@capacitor/core": "6.1.2",
"@capacitor/haptics": "6.0.0",
"@capacitor/keyboard": "6.0.1",
"@capacitor/status-bar": "6.0.0",
"@capacitor/haptics": "6.0.1",
"@capacitor/keyboard": "6.0.2",
"@capacitor/status-bar": "6.0.1",
"@fortawesome/fontawesome-svg-core": "6.6.0",
"@fortawesome/free-solid-svg-icons": "6.6.0",
"@fortawesome/react-fontawesome": "0.2.2",
"@ionic/react": "8.2.6",
"@ionic/react-router": "8.2.6",
"@tanstack/react-query": "5.51.23",
"@tanstack/react-query-devtools": "5.51.23",
"@ionic/react": "8.2.7",
"@ionic/react-router": "8.2.7",
"@tanstack/react-query": "5.52.1",
"@tanstack/react-query-devtools": "5.52.1",
"@types/react-router": "5.1.20",
"@types/react-router-dom": "5.3.3",
"axios": "1.7.3",
"axios": "1.7.5",
"classnames": "2.5.1",
"dayjs": "1.11.12",
"dayjs": "1.11.13",
"formik": "2.4.6",
"lodash": "4.17.21",
"react": "18.3.1",
Expand All @@ -48,29 +48,29 @@
"devDependencies": {
"@capacitor/cli": "6.1.2",
"@testing-library/dom": "10.4.0",
"@testing-library/jest-dom": "6.4.8",
"@testing-library/jest-dom": "6.5.0",
"@testing-library/react": "16.0.0",
"@testing-library/user-event": "14.5.2",
"@types/lodash": "4.17.7",
"@types/react": "18.3.3",
"@types/react": "18.3.4",
"@types/react-dom": "18.3.0",
"@types/uuid": "10.0.0",
"@typescript-eslint/eslint-plugin": "8.0.1",
"@typescript-eslint/parser": "8.0.1",
"@vitejs/plugin-legacy": "5.4.1",
"@typescript-eslint/eslint-plugin": "8.2.0",
"@typescript-eslint/parser": "8.2.0",
"@vitejs/plugin-legacy": "5.4.2",
"@vitejs/plugin-react": "4.3.1",
"@vitest/coverage-v8": "2.0.5",
"cypress": "13.13.2",
"cypress": "13.13.3",
"eslint": "8.57.0",
"eslint-plugin-react": "7.35.0",
"eslint-plugin-react-hooks": "4.6.2",
"eslint-plugin-react-refresh": "0.4.9",
"jsdom": "24.1.1",
"eslint-plugin-react-refresh": "0.4.11",
"jsdom": "25.0.0",
"msw": "2.3.5",
"sass": "1.77.8",
"terser": "5.31.5",
"terser": "5.31.6",
"typescript": "5.5.4",
"vite": "5.4.0",
"vite": "5.4.2",
"vitest": "2.0.5"
}
}
34 changes: 32 additions & 2 deletions src/common/components/Icon/Avatar.scss
Original file line number Diff line number Diff line change
@@ -1,15 +1,45 @@
.avatar {
height: 1.5rem;
width: 1.5rem;

font-size: 1rem;
font-weight: 500;
line-height: 0;

overflow: hidden;

--border-radius: 0.25rem;

&.avatar-round {
--border-radius: 50%;
}

&.avatar-square {
--border-radius: 0;
}

&.avatar-small {
height: 1.25rem;
width: 1.25rem;

font-size: 0.875rem;
}

&.avatar-large {
height: 2rem;
width: 2rem;

font-size: 1.5rem;
font-weight: 700;
}

.initial {
display: flex;
align-items: center;
justify-content: center;

height: 100%;
width: 100%;

font-weight: 700;
}

.primary {
Expand Down
32 changes: 30 additions & 2 deletions src/common/components/Icon/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,28 @@ import classNames from 'classnames';
import './Avatar.scss';
import { BaseComponentProps } from '../types';

/**
* The Avatar shape values.
*/
type AvatarShape = 'round' | 'rounded' | 'square';

/**
* The Avatar size values.
*/
type AvatarSize = 'small' | 'default' | 'large';

/**
* Properties for the `Avatar` component.
* @param {AvatarShape} [shape] - Optional. The avatar shape. Default: `rounded`.
* @param {AvatarSize} [size] - Optional. The avatar size. Default: `default`.
* @param {string} [src] - Optional. An image source.
* @param {string} value - Generated Avatar value.
* @see {@link BaseComponentProps}
* @see {@link IonAvatar}
*/
interface AvatarProps extends BaseComponentProps {
shape?: AvatarShape;
size?: AvatarSize;
src?: string;
value: string;
}
Expand All @@ -32,15 +46,29 @@ const COLORS = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'dange
* @param {AvatarProps} props - Component properties.
* @returns JSX
*/
const Avatar = ({ className, src, testid = 'avatar', value }: AvatarProps): JSX.Element => {
const Avatar = ({
className,
shape = 'rounded',
size = 'default',
src,
testid = 'avatar',
value,
}: AvatarProps): JSX.Element => {
const trimmedValue = value.trim();
const initial = trimmedValue ? trimmedValue.charAt(0) : '?';

const colorClass = COLORS[trimmedValue.length % COLORS.length];

return (
<IonAvatar
className={classNames('avatar', className)}
className={classNames(
'avatar',
{ 'avatar-round': shape === 'round' },
{ 'avatar-square': shape === 'square' },
{ 'avatar-small': size === 'small' },
{ 'avatar-large': size === 'large' },
className,
)}
data-testid={testid}
title={trimmedValue}
>
Expand Down
60 changes: 60 additions & 0 deletions src/common/components/Icon/__tests__/Avatar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,64 @@ describe('Avatar', () => {
// ASSERT
expect(screen.getByTestId('avatar-image')).toBeDefined();
});

it('should render small size', async () => {
// ARRANGE
render(<Avatar value={valueFixture} size="small" />);
await screen.findByTestId('avatar');

// ASSERT
expect(screen.getByTestId('avatar')).toHaveClass('avatar-small');
expect(screen.getByTestId('avatar')).not.toHaveClass('avatar-large');
});

it('should render large size', async () => {
// ARRANGE
render(<Avatar value={valueFixture} size="large" />);
await screen.findByTestId('avatar');

// ASSERT
expect(screen.getByTestId('avatar')).not.toHaveClass('avatar-small');
expect(screen.getByTestId('avatar')).toHaveClass('avatar-large');
});

it('should render default size', async () => {
// ARRANGE
render(<Avatar value={valueFixture} />);
await screen.findByTestId('avatar');

// ASSERT
expect(screen.getByTestId('avatar')).not.toHaveClass('avatar-small');
expect(screen.getByTestId('avatar')).not.toHaveClass('avatar-large');
});

it('should render round shape', async () => {
// ARRANGE
render(<Avatar value={valueFixture} shape="round" />);
await screen.findByTestId('avatar');

// ASSERT
expect(screen.getByTestId('avatar')).toHaveClass('avatar-round');
expect(screen.getByTestId('avatar')).not.toHaveClass('avatar-square');
});

it('should render square shape', async () => {
// ARRANGE
render(<Avatar value={valueFixture} shape="square" />);
await screen.findByTestId('avatar');

// ASSERT
expect(screen.getByTestId('avatar')).not.toHaveClass('avatar-round');
expect(screen.getByTestId('avatar')).toHaveClass('avatar-square');
});

it('should render default shape', async () => {
// ARRANGE
render(<Avatar value={valueFixture} />);
await screen.findByTestId('avatar');

// ASSERT
expect(screen.getByTestId('avatar')).not.toHaveClass('avatar-round');
expect(screen.getByTestId('avatar')).not.toHaveClass('avatar-square');
});
});
7 changes: 0 additions & 7 deletions src/common/components/Menu/AppMenu.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@

.avatar {
flex-shrink: 0;

height: 1.75rem;
width: 1.75rem;

font-size: 1.25rem;

border-radius: 0.25rem;
}
}
}
Expand Down
12 changes: 0 additions & 12 deletions src/pages/Users/components/UserDetail/UserDetailPage.scss

This file was deleted.

3 changes: 1 addition & 2 deletions src/pages/Users/components/UserDetail/UserDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { IonButton, IonButtons, IonContent, IonPage, IonText, useIonRouter } fro
import { useState } from 'react';
import { useParams } from 'react-router';

import './UserDetailPage.scss';
import { PropsWithTestId } from 'common/components/types';
import { useGetUser } from 'pages/Users/api/useGetUser';
import { useToasts } from 'common/hooks/useToasts';
Expand Down Expand Up @@ -83,7 +82,7 @@ export const UserDetailPage = ({
<Container fixed>
{user ? (
<PageHeader className="ion-hide-md-down" inset border>
<Avatar value={user.name} />
<Avatar value={user.name} size="large" />
<IonText data-testid={`${testid}-page-header-title`}>{user.name}</IonText>
<IonButtons>
<IonButton
Expand Down
12 changes: 0 additions & 12 deletions src/pages/Users/components/UserEdit/UserEditPage.scss

This file was deleted.

3 changes: 1 addition & 2 deletions src/pages/Users/components/UserEdit/UserEditPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { IonContent, IonPage, IonText } from '@ionic/react';
import { useParams } from 'react-router';

import './UserEditPage.scss';
import { useGetUser } from 'pages/Users/api/useGetUser';
import Header from 'common/components/Header/Header';
import Container from 'common/components/Content/Container';
Expand Down Expand Up @@ -39,7 +38,7 @@ export const UserEditPage = (): JSX.Element => {
{user ? (
<>
<PageHeader border inset className="ion-hide-md-down">
<Avatar value={user.name} />
<Avatar value={user.name} size="large" />
<IonText data-testid={`${testid}-title`}>{user.name}</IonText>
</PageHeader>

Expand Down
3 changes: 1 addition & 2 deletions src/pages/Users/components/UserList/UserCard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
.avatar {
height: 3rem;
width: 3rem;
font-size: 2.5rem;

border-radius: 0.25rem;
font-size: 2.5rem;
}

.header {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Users/components/UserList/UserCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const UserCard = ({ className, testid = 'card-user', user }: UserCardProps): JSX
data-testid={testid}
>
<div className="layout">
<Avatar value={user.name} />
<Avatar value={user.name} size="large" />
<div>
<div className="header">{user.name}</div>
<div className="content-row">
Expand Down
4 changes: 0 additions & 4 deletions src/pages/Users/components/UserList/UserListItem.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
--inner-padding-top: 0.5rem;

.avatar {
border-radius: 0.25rem;

font-size: 1.5rem;

margin-right: 1rem;
}

Expand Down
2 changes: 1 addition & 1 deletion src/pages/Users/components/UserList/UserListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const UserListItem = ({ className, lines, testid, user }: UserListItemProps): JS
data-testid={testIdentifier}
>
<IonItem routerLink={`/tabs/users/${user.id}`} lines={lines} detail>
<Avatar value={user.name} />
<Avatar value={user.name} size="large" />
<IonLabel>
<div className="content-row primary">
<div className="name" data-testid={`${testIdentifier}-name`}>
Expand Down

0 comments on commit 3cb2ed3

Please sign in to comment.