Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 24 additions & 2 deletions addon/components/o-s-s/avatar.stories.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { hbs } from 'ember-cli-htmlbars';

const SizeTypes = ['xs', 'sm', 'md', 'lg'];
const SkinType = [
'danger',
'xtd-orange',
'xtd-violet-light',
'xtd-violet',
'xtd-lime',
'primary',
'primary-light',
'xtd-cyan'
];

export default {
title: 'Components/OSS::Avatar',
Expand Down Expand Up @@ -41,6 +51,17 @@ export default {
type: 'text'
}
},
skin: {
description: 'Adjust the skin of the avatar component',
Comment thread
aprentout marked this conversation as resolved.
table: {
type: {
summary: SkinType.join(' | ')
},
defaultValue: { summary: undefined }
},
options: [undefined, ...SkinType],
control: { type: 'select' }
},
loading: {
description: 'Display loading state',
table: {
Expand Down Expand Up @@ -70,12 +91,13 @@ const defaultArgs = {
size: 'md',
image: undefined,
initials: undefined,
loading: false
loading: false,
skin: undefined
};

const Template = (args) => ({
template: hbs`
<OSS::Avatar @image={{this.image}} @initials={{this.initials}} @size={{this.size}} @loading={{this.loading}} />
<OSS::Avatar @image={{this.image}} @initials={{this.initials}} @size={{this.size}} @loading={{this.loading}} @skin={{this.skin}}/>
`,
context: args
});
Expand Down
29 changes: 26 additions & 3 deletions addon/components/o-s-s/avatar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,25 @@ export const SizeDefinition: SizeDefType = {
lg: 'upf-avatar--lg'
};

export const AvatarSkins = [
'danger',
'xtd-orange',
'xtd-violet-light',
'xtd-violet',
'xtd-lime',
'primary',
'primary-light',
'xtd-cyan'
] as const;

export type SkinType = (typeof AvatarSkins)[number];

export interface OSSAvatarArgs {
image?: string;
initials?: string;
size?: SizeType;
loading?: boolean;
skin?: SkinType;
}

export const DEFAULT_IMAGE_URL: string = '/@upfluence/oss-components/assets/images/avatar-placeholder.svg';
Expand All @@ -37,19 +51,28 @@ export default class OSSAvatar extends Component<OSSAvatarArgs> {
}

get computedClass(): string {
let classes = 'upf-avatar ';
const classes = ['upf-avatar'];
const size: SizeType = this.args.size || 'md';

if (this.args.loading) {
classes = classes.concat('upf-avatar--loading ');
classes.push('upf-avatar--loading');
}

if (this.args.skin) {
assert(
`[component][OSS::Avatar] Unknown skin. Available skins are: ${AvatarSkins.join(', ')}`,
AvatarSkins.includes(this.args.skin as SkinType)
);
classes.push('upf-avatar--skin', `upf-avatar--skin-${this.args.skin}`);
}

assert(
`[component][OSS::Avatar] Unknown size. Available sizes are: ${Object.keys(SizeDefinition).join(', ')}`,
Object.keys(SizeDefinition).includes(size as SizeType)
);

return classes.concat(SizeDefinition[size as SizeType]);
classes.push(SizeDefinition[size as SizeType])
return classes.join(' ')
}

@action
Expand Down
37 changes: 37 additions & 0 deletions app/styles/atoms/avatar.less
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,41 @@
.upf-skeleton-effect;
.border-radius-round;
}

&--skin {
color: var(--color-white);
border: 1px solid var(--color-white);
Comment thread
aprentout marked this conversation as resolved.

&-danger {
background-color: var(--color-error-400);
}

&-xtd-orange {
background-color: var(--color-orange-400);
}

&-xtd-violet-light {
background-color: var(--color-violet-400);
}

&-xtd-violet {
background-color: var(--color-violet-500);
}

&-xtd-lime {
background-color: var(--color-lime-500);
}

&-primary {
background-color: var(--color-primary-400);
}

&-primary-light {
background-color: var(--color-primary-300);
}

&-xtd-cyan {
background-color: var(--color-cyan-500);
}
}
}
9 changes: 9 additions & 0 deletions tests/dummy/app/templates/visual.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,15 @@
<OSS::Avatar @size="sm" />
<OSS::Avatar @size="md" />
<OSS::Avatar @size="lg" />
<OSS::Avatar @size="lg" @initials="U"/>
<OSS::Avatar @size="lg" @skin="danger" @initials="P"/>
<OSS::Avatar @size="lg" @skin="xtd-orange" @initials="F"/>
<OSS::Avatar @size="lg" @skin="xtd-violet-light" @initials="L"/>
<OSS::Avatar @size="lg" @skin="xtd-violet" @initials="U"/>
<OSS::Avatar @size="lg" @skin="xtd-lime" @initials="E"/>
<OSS::Avatar @size="lg" @skin="primary" @initials="N"/>
<OSS::Avatar @size="lg" @skin="primary-light" @initials="C"/>
<OSS::Avatar @size="lg" @skin="xtd-cyan" @initials="E"/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: how do we handle Avatars with 2 ou 3 letters ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply by passing 2 ou 3 letters :trollface:
It already works fine :)
Capture d’écran 2026-07-24 à 16 42 57

</div>
</div>

Expand Down
32 changes: 31 additions & 1 deletion tests/integration/components/o-s-s/avatar-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { find, render, setupOnerror, waitFor, waitUntil } from '@ember/test-helpers';

import { SizeDefinition, DEFAULT_IMAGE_URL } from '@upfluence/oss-components/components/o-s-s/avatar';
import { SizeDefinition, AvatarSkins, DEFAULT_IMAGE_URL } from '@upfluence/oss-components/components/o-s-s/avatar';

module('Integration | Component | o-s-s/avatar', function (hooks) {
setupRenderingTest(hooks);
Expand Down Expand Up @@ -63,6 +63,25 @@ module('Integration | Component | o-s-s/avatar', function (hooks) {
});
});

module('Skins', function () {
test('it sets no skin class when skin is not provided', async function (assert) {
await render(hbs`<OSS::Avatar />`);

assert.dom('.upf-avatar').exists();
assert.dom('.upf-avatar').hasNoClass(`upf-avatar--skin`);
});

AvatarSkins.forEach((skin) => {
test(`it sets the right class when using a supported skin: ${skin}`, async function (assert) {
this.skin = skin;
await render(hbs`<OSS::Avatar @skin={{this.skin}} />`);

assert.dom('.upf-avatar').hasClass(`upf-avatar--skin`).hasClass(`upf-avatar--skin-${skin}`);
})
})

})

module('Sizes', function () {
test('it sets the right default class when size is not provided', async function (assert) {
await render(hbs`<OSS::Avatar />`);
Expand Down Expand Up @@ -101,6 +120,17 @@ module('Integration | Component | o-s-s/avatar', function (hooks) {
await render(hbs`<OSS::Avatar @size="test" />`);
});

test('it throws an error if the wrong skin argument is passed', async function (assert: Assert) {
setupOnerror((err: Error) => {
assert.equal(
err.message,
`Assertion Failed: [component][OSS::Avatar] Unknown skin. Available skins are: ${AvatarSkins.join(', ')}`
);
});

await render(hbs`<OSS::Avatar @skin="test" />`);
});

test('it displays the initials when both initials and image are provided and the image fails to load', async function (assert) {
await render(hbs`<OSS::Avatar @image="/@upfluence/oss-components/assets/images/fail.svg" @initials="TS" />`);
await waitFor('.upf-avatar span');
Expand Down
Loading