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(avatarGroup): introduce #5916

Merged
merged 33 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b715483
feat(avatarGroup): introduce
AugustinMauroy Sep 29, 2023
49c6a31
update
AugustinMauroy Sep 29, 2023
19b888c
feat(avatarGroup): update base on feedback
AugustinMauroy Sep 30, 2023
7673f18
update
AugustinMauroy Oct 1, 2023
37f7a5e
Merge remote-tracking branch 'upstream/main' into feat(authors)
AugustinMauroy Oct 2, 2023
2d581af
re-add package
AugustinMauroy Oct 2, 2023
55457f8
update
AugustinMauroy Oct 3, 2023
0f3e306
update
AugustinMauroy Oct 4, 2023
b3bf1ed
update
AugustinMauroy Oct 8, 2023
de3ee52
feat(avatarGroupe): update with feedBack
AugustinMauroy Oct 11, 2023
340147c
fix: indentation
AugustinMauroy Oct 11, 2023
c61cbf9
remove `'use client';`
AugustinMauroy Oct 11, 2023
0e2e396
feat(utils): separate "avatar"
AugustinMauroy Oct 11, 2023
c764b26
feat(avatarGroup): introduce
AugustinMauroy Sep 29, 2023
4200176
update
AugustinMauroy Sep 29, 2023
b91d26a
feat(avatarGroup): update base on feedback
AugustinMauroy Sep 30, 2023
081cf42
update
AugustinMauroy Oct 1, 2023
fd75eee
re-add package
AugustinMauroy Oct 2, 2023
bf33b6b
update
AugustinMauroy Oct 3, 2023
477c0c3
update
AugustinMauroy Oct 4, 2023
423b208
update
AugustinMauroy Oct 8, 2023
86578f1
feat(avatarGroupe): update with feedBack
AugustinMauroy Oct 11, 2023
ceac69a
fix: indentation
AugustinMauroy Oct 11, 2023
4918f85
remove `'use client';`
AugustinMauroy Oct 11, 2023
af292d1
feat(utils): separate "avatar"
AugustinMauroy Oct 11, 2023
279ba4b
review: expedited code-review changes
ovflowd Oct 11, 2023
38144d0
test(avatarGroup): add
AugustinMauroy Oct 14, 2023
e8295b7
Merge branch 'feat(authors)' of https://github.com/AugustinMauroy/nod…
AugustinMauroy Oct 14, 2023
d71f145
review: expedited code-review changes
ovflowd Oct 11, 2023
4c98b35
remove: removed files with wrong casing
ovflowd Oct 14, 2023
db86f0e
chore: renamed utils
ovflowd Oct 14, 2023
a2edfec
chore: fix linting order
ovflowd Oct 14, 2023
d8233d9
chore: fix tests
ovflowd Oct 14, 2023
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
22 changes: 22 additions & 0 deletions components/Common/AvatarGroup/Avatar/index.module.css
AugustinMauroy marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.avatar {
@apply flex
ovflowd marked this conversation as resolved.
Show resolved Hide resolved
h-8
w-8
items-center
justify-center
rounded-full
border-2
border-white
bg-neutral-100
object-cover
text-xs
text-neutral-800
dark:border-neutral-950
dark:bg-neutral-900
dark:text-neutral-300;
}

.avatarRoot {
@apply -ml-2
first:ml-0;
}
31 changes: 31 additions & 0 deletions components/Common/AvatarGroup/Avatar/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { Meta as MetaObj, StoryObj } from '@storybook/react';

import { githubProfileAvatarUrl } from '@/util/github';

import Avatar from './';

type Story = StoryObj<typeof Avatar>;
type Meta = MetaObj<typeof Avatar>;

export const Default: Story = {
args: {
src: githubProfileAvatarUrl('ovflowd'),
alt: 'ovflowd',
},
};

export const NoSquare: Story = {
args: {
src: '/static/images/logos/stacked-dark.svg',
alt: 'SD',
},
};

export const FallBack: Story = {
args: {
src: 'https://avatars.githubusercontent.com/u/',
alt: 'UA',
},
};

export default { component: Avatar } as Meta;
20 changes: 20 additions & 0 deletions components/Common/AvatarGroup/Avatar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as RadixAvatar from '@radix-ui/react-avatar';
import type { FC } from 'react';

import styles from './index.module.css';

type AvatarProps = {
src: string;
alt: string;
};

const Avatar: FC<AvatarProps> = ({ src, alt }) => (
<RadixAvatar.Root className={styles.avatarRoot}>
<RadixAvatar.Image src={src} alt={alt} className={styles.avatar} />
<RadixAvatar.Fallback delayMs={500} className={styles.avatar}>
{alt}
</RadixAvatar.Fallback>
</RadixAvatar.Root>
);

export default Avatar;
4 changes: 4 additions & 0 deletions components/Common/AvatarGroup/index.module.css
AugustinMauroy marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.avatarGroup {
@apply flex
items-center;
}
61 changes: 61 additions & 0 deletions components/Common/AvatarGroup/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
AugustinMauroy marked this conversation as resolved.
Show resolved Hide resolved

import { githubProfileAvatarUrl } from '@/util/github';

import AvatarGroup from './';

type Story = StoryObj<typeof AvatarGroup>;
type Meta = MetaObj<typeof AvatarGroup>;

const names = [
'ovflowd',
'bmuenzenmeyer',
'AugustinMauroy',
'HinataKah0',
'Harkunwar',
'rodion-arr',
'mikeesto',
'bnb',
'benhalverson',
'aymen94',
'shanpriyan',
'Wai-Dung',
'manishprivet',
'araujogui',
];

const unknownAvatar = {
src: 'https://avatars.githubusercontent.com/u/',
alt: 'unknown-avatar',
};

const defaultProps = {
avatars: [
unknownAvatar,
...names.map(name => ({ src: githubProfileAvatarUrl(name), alt: name })),
],
};

export const Default: Story = {
args: { ...defaultProps },
};

export const WithCustomLimit: Story = {
args: {
...defaultProps,
limit: 5,
},
};

export const InSmallContainer: Story = {
decorators: [
Story => (
<div className="w-[150px]">
<Story />
</div>
),
],
args: { ...defaultProps, limit: 5 },
};

export default { component: AvatarGroup } as Meta;
48 changes: 48 additions & 0 deletions components/Common/AvatarGroup/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import classNames from 'classnames';
import type { ComponentProps, FC } from 'react';
import { useState, useMemo } from 'react';

import { getAcronymFromString } from '@/util/stringutils';

import Avatar from './Avatar';
import avatarstyles from './Avatar/index.module.css';
import styles from './index.module.css';

type AvatarGroupProps = {
avatars: ComponentProps<typeof Avatar>[];
limit?: number;
};

const AvatarGroup: FC<AvatarGroupProps> = ({ avatars, limit = 10 }) => {
const [showMore, setShowMore] = useState(false);

const renderAvatars = useMemo(
() => avatars.slice(0, showMore ? avatars.length : limit),
[showMore, avatars, limit]
);

return (
<div className={styles.avatarGroup}>
{renderAvatars.map((avatar, index) => (
<Avatar
src={avatar.src}
alt={getAcronymFromString(avatar.alt)}
key={index}
/>
))}

{avatars.length > limit && (
AugustinMauroy marked this conversation as resolved.
Show resolved Hide resolved
<span
onClick={() => setShowMore(!showMore)}
className={classNames(avatarstyles.avatarRoot, 'cursor-pointer')}
>
<span className={avatarstyles.avatar}>
{`${showMore ? '-' : '+'}${avatars.length - limit}`}
</span>
</span>
)}
</div>
);
};

export default AvatarGroup;
27 changes: 27 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@heroicons/react": "~2.0.18",
"@mdx-js/react": "^2.3.0",
"@nodevu/core": "~0.1.0",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-toast": "^1.1.5",
"@types/node": "18.18.3",
Expand Down
9 changes: 9 additions & 0 deletions util/__tests__/github.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { githubProfileAvatarUrl } from '@/util/github';

describe('Github utils', () => {
it('githubProfileAvatarUrl returns the correct URL', () => {
expect(githubProfileAvatarUrl('octocat')).toBe(
'https://avatars.githubusercontent.com/octocat'
);
});
});
15 changes: 15 additions & 0 deletions util/__tests__/string.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { getAcronymFromString } from '@/util/stringUtils';

describe('String utils', () => {
it('getAcronymFromString returns the correct acronym', () => {
expect(getAcronymFromString('John Doe')).toBe('JD');
});

it('getAcronymFromString returns the correct acronym for a single word', () => {
expect(getAcronymFromString('John')).toBe('J');
});

it('getAcronymFromString if the string is empty, it returns NA', () => {
expect(getAcronymFromString('')).toBe('NA');
});
});
2 changes: 2 additions & 0 deletions util/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const githubProfileAvatarUrl = (username: string): string =>
`https://avatars.githubusercontent.com/${username}`;
2 changes: 2 additions & 0 deletions util/stringutils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const getAcronymFromString = (str: string) =>
[...(str.trim().match(/\b(\w)/g) || '')].join('').toUpperCase();
Loading