Skip to content

Commit

Permalink
feat: avatar group storybook
Browse files Browse the repository at this point in the history
  • Loading branch information
driss-chelouati committed Sep 4, 2023
1 parent c327189 commit 2dfe0fa
Show file tree
Hide file tree
Showing 8 changed files with 345 additions and 3 deletions.
49 changes: 49 additions & 0 deletions src/plugins/components/avatar-group/avatar-group.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { html } from 'lit'
import { spread } from '@open-wc/lit-helpers'

import type { AvatarGroupAttrs } from './avatar-group.types'
import { Avatar } from '../avatar/avatar.component'
import * as variants from './avatar-group.variants'

/**
* Primary UI component for user interaction
*/
export const AvatarGroup = ({
avatars,
size = 'sm',
limit = 4,
...attrs
}: AvatarGroupAttrs) => {
return html`
<div
class=${['nui-avatar-group', size && variants.size[size]]
.filter(Boolean)
.join(' ')}
${spread(attrs)}
>
${avatars.map(
(avatar) => html`
<div class="nui-avatar-outer">
${Avatar({
shape: 'full',
size: size,
src: avatar.src,
'data-nui-tooltip': avatar.text,
})}
</div>
`,
)}
${avatars.length > limit
? html`
<div class="nui-avatar-count">
<div class="nui-avatar-count-inner">
<span class="nui-avatar-count-text">
+${avatars.length - limit + 1}
</span>
</div>
</div>
`
: ''}
</div>
`
}
104 changes: 104 additions & 0 deletions src/plugins/components/avatar-group/avatar-group.doc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Meta, Primary, Controls, Story } from '@storybook/blocks'
import * as AvatarGroupStories from './avatar-group.stories'
import { defaultAvatarGroupConfig } from '.'

<Meta of={AvatarGroupStories} />

# Avatar group

Avatars groups can have different sizes. This example shows an avatar group using the xs size. Use the size prop to change the size of the avatar group.

<Primary />

## Props

<Controls />

## Variants

<br />

### Size: xxs

Avatars can have different sizes and different shapes. The below examples shows all avatar sizes for the full shape.

<div className="flex gap-2 bg-slate-100 dark:bg-slate-900 p-6 rounded-sm">
<Story of={AvatarGroupStories.SizeXxs} />
</div>

<br />

### Size: xs

Avatars can have different sizes and different shapes. The below examples shows all avatar sizes for the full shape.

<div className="flex gap-2 bg-slate-100 dark:bg-slate-900 p-6 rounded-sm">
<Story of={AvatarGroupStories.SizeXs} />
</div>

<br />

### Size: sm

Avatars can have different sizes and different shapes. The below examples shows all avatar sizes for the full shape.

<div className="flex gap-2 bg-slate-100 dark:bg-slate-900 p-6 rounded-sm">
<Story of={AvatarGroupStories.SizeSm} />
</div>

<br />

### Size: md

Avatars can have different sizes and different shapes. The below examples shows all avatar sizes for the full shape.

<div className="flex gap-2 bg-slate-100 dark:bg-slate-900 p-6 rounded-sm">
<Story of={AvatarGroupStories.SizeMd} />
</div>

<br />

### Size: Lg
Avatars can have different sizes and different shapes. The below examples shows all avatar sizes for the full shape.

<div className="flex gap-2 bg-slate-100 dark:bg-slate-900 p-6 rounded-sm">
<Story of={AvatarGroupStories.SizeLg} />
</div>

<br />
<br />

## Customization

### Default config

<div class="relative">
<details class="relative bg-slate-50 border border-slate-200 rounded-lg p-4 [&>summary>svg]:open:-rotate-180">
<summary class="list-none cursor-pointer">
<span class="font-sans text-slate-500">View configuration options</span>
<svg
class="w-5 h-5 text-slate-500 absolute top-5 end-4 transition-transform duration-300"
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m6 9l6 6l6-6"
/>
</svg>
</summary>

<div class="!mt-4">
<pre >
{JSON.stringify(defaultAvatarGroupConfig, null, 2)}
</pre>
</div>

</details>
</div>
127 changes: 127 additions & 0 deletions src/plugins/components/avatar-group/avatar-group.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import type { Meta, StoryObj } from '@storybook/web-components'
import { html } from 'lit'

import type { AvatarGroupAttrs } from './avatar-group.types'
import { AvatarGroup } from './avatar-group.component'

const demoAvatars = [
{
src: 'https://apollux.cssninja.io/img/avatars/10.svg',
srcDark: 'https://apollux.cssninja.io/img/avatars/10.svg',
text: 'Kendra Wilson',
},
{
src: 'https://apollux.cssninja.io/img/avatars/12.svg',
srcDark: 'https://apollux.cssninja.io/img/avatars/12.svg',
text: 'Ella Milburn',
},
{
src: 'https://apollux.cssninja.io/img/avatars/8.svg',
srcDark: 'https://apollux.cssninja.io/img/avatars/8.svg',
text: 'John Baxter',
},
{
src: 'https://apollux.cssninja.io/img/avatars/24.svg',
srcDark: 'https://apollux.cssninja.io/img/avatars/24.svg',
text: 'Anna Lopez',
},
{
src: 'https://apollux.cssninja.io/img/avatars/25.svg',
srcDark: 'https://apollux.cssninja.io/img/avatars/25.svg',
text: 'Melany Smith',
},
]

// More on how to set up stories at: https://storybook.js.org/docs/web-components/writing-stories/introduction
const meta = {
title: 'Shuriken UI/Base/Avatar Group',
// tags: ['autodocs'],
render: (args) => AvatarGroup(args),
argTypes: {
size: {
control: { type: 'select' },
options: ['xxs', 'xs', 'sm', 'md', 'lg'],
defaultValue: 'sm',
},
limit: {
control: { type: 'number' },
defaultValue: 4,
},
avatars: {
control: { type: 'array' },
defaultValue: demoAvatars,
},
},
} satisfies Meta<AvatarGroupAttrs>

export default meta
type Story = StoryObj<AvatarGroupAttrs>

// first export is the Primary story

// #region Main
export const Main: Story = {
name: 'Main example',
args: {
// set default values used for UI preview
size: 'lg',
limit: 4,
avatars: demoAvatars,
},
}
// #endregion

// #region Size:XXs
export const SizeXxs: Story = {
name: 'Size: xxs',
args: {
size: 'xxs',
limit: 4,
avatars: demoAvatars,
},
}
// #endregion

// #region Size:Xs
export const SizeXs: Story = {
name: 'Size: xs',
args: {
size: 'xs',
limit: 4,
avatars: demoAvatars,
},
}
// #endregion

// #region Size:Sm
export const SizeSm: Story = {
name: 'Size: sm',
args: {
size: 'sm',
limit: 4,
avatars: demoAvatars,
},
}
// #endregion

// #region Size:Md
export const SizeMd: Story = {
name: 'Size: md',
args: {
size: 'md',
limit: 4,
avatars: demoAvatars,
},
}
// #endregion

// #region Size:Lg
export const SizeLg: Story = {
name: 'Size: lg',
args: {
size: 'lg',
limit: 4,
avatars: demoAvatars,
},
}
// #endregion
33 changes: 33 additions & 0 deletions src/plugins/components/avatar-group/avatar-group.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { axe } from 'vitest-axe'
import { expect, test, describe } from 'vitest'
import { render, html } from 'lit'

import { AvatarGroup } from './avatar-group.component'

describe('AvatarGroup', () => {
test('Should render slot', () => {
const avatarGroup = AvatarGroup({
size: 'sm',
avatars: [],
})

render(avatarGroup, document.body)

expect(
document.body.querySelector('.nui-avatar-group')?.outerHTML,
)?.toContain('Hello world')
})

test('Should have no axe violations', async () => {
const avatarGroup = AvatarGroup({
size: 'sm',
avatars: [],
})

render(avatarGroup, document.body)

expect(
await axe(document.body.querySelector('.nui-avatar-group')!.outerHTML),
)?.toHaveNoViolations()
})
})
20 changes: 20 additions & 0 deletions src/plugins/components/avatar-group/avatar-group.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { PropertyVariant } from '~/types/utils'

export interface AvatarGroupProps extends Record<string, unknown> {
limit?: number
size?: 'xxs' | 'xs' | 'sm' | 'md' | 'lg'
avatars: {
src?: string
srcDark?: string
text?: string
}[]
}

export interface AvatarGroupEvents {}

export interface AvatarGroupSlots {}

export type AvatarGroupAttrs = AvatarGroupProps &
AvatarGroupEvents &
AvatarGroupSlots
export type AvatarGroupVariant<T> = PropertyVariant<T, AvatarGroupProps>
9 changes: 9 additions & 0 deletions src/plugins/components/avatar-group/avatar-group.variants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { AvatarGroupVariant } from './avatar-group.types'

export const size = {
xxs: 'nui-avatar-group-xxs',
xs: 'nui-avatar-group-xs',
sm: 'nui-avatar-group-sm',
md: 'nui-avatar-group-md',
lg: 'nui-avatar-group-lg',
} as const satisfies AvatarGroupVariant<'size'>
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import plugin from 'tailwindcss/plugin'
import { defu } from 'defu'
import { type PluginOption, defaultPluginOptions } from '../options'
import { type PluginOption, defaultPluginOptions } from '../../options'

const defaultAvatarGroupConfig = {
export const defaultAvatarGroupConfig = {
avatarOuter: {
bg: 'white',
bgDark: 'muted-800',
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/components/avatar/avatar.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const Main: Story = {
name: 'Main example',
args: {
// set default values used for UI preview
size: 'xl',
size: '4xl',
shape: 'full',
src: 'https://apollux.cssninja.io/img/avatars/10.svg',
srcDark: 'https://apollux.cssninja.io/img/avatars/10.svg',
Expand Down

0 comments on commit 2dfe0fa

Please sign in to comment.