diff --git a/addon/components/o-s-s/avatar.stories.js b/addon/components/o-s-s/avatar.stories.js index 950b243d1..aa1de57da 100644 --- a/addon/components/o-s-s/avatar.stories.js +++ b/addon/components/o-s-s/avatar.stories.js @@ -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', @@ -41,6 +51,17 @@ export default { type: 'text' } }, + skin: { + description: 'Adjust the skin of the avatar component', + table: { + type: { + summary: SkinType.join(' | ') + }, + defaultValue: { summary: undefined } + }, + options: [undefined, ...SkinType], + control: { type: 'select' } + }, loading: { description: 'Display loading state', table: { @@ -70,12 +91,13 @@ const defaultArgs = { size: 'md', image: undefined, initials: undefined, - loading: false + loading: false, + skin: undefined }; const Template = (args) => ({ template: hbs` - + `, context: args }); diff --git a/addon/components/o-s-s/avatar.ts b/addon/components/o-s-s/avatar.ts index 1ff489880..b02c93766 100644 --- a/addon/components/o-s-s/avatar.ts +++ b/addon/components/o-s-s/avatar.ts @@ -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'; @@ -37,11 +51,19 @@ export default class OSSAvatar extends Component { } 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( @@ -49,7 +71,8 @@ export default class OSSAvatar extends Component { Object.keys(SizeDefinition).includes(size as SizeType) ); - return classes.concat(SizeDefinition[size as SizeType]); + classes.push(SizeDefinition[size as SizeType]) + return classes.join(' ') } @action diff --git a/app/styles/atoms/avatar.less b/app/styles/atoms/avatar.less index 705b81e45..81c49e15f 100644 --- a/app/styles/atoms/avatar.less +++ b/app/styles/atoms/avatar.less @@ -70,4 +70,41 @@ .upf-skeleton-effect; .border-radius-round; } + + &--skin { + color: var(--color-white); + border: 1px solid var(--color-white); + + &-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); + } + } } diff --git a/tests/dummy/app/templates/visual.hbs b/tests/dummy/app/templates/visual.hbs index e6950b2e3..65f43cd82 100644 --- a/tests/dummy/app/templates/visual.hbs +++ b/tests/dummy/app/templates/visual.hbs @@ -385,6 +385,15 @@ + + + + + + + + + diff --git a/tests/integration/components/o-s-s/avatar-test.ts b/tests/integration/components/o-s-s/avatar-test.ts index 1339d2478..1590a3932 100644 --- a/tests/integration/components/o-s-s/avatar-test.ts +++ b/tests/integration/components/o-s-s/avatar-test.ts @@ -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); @@ -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``); + + 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``); + + 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``); @@ -101,6 +120,17 @@ module('Integration | Component | o-s-s/avatar', function (hooks) { await render(hbs``); }); + 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``); + }); + test('it displays the initials when both initials and image are provided and the image fails to load', async function (assert) { await render(hbs``); await waitFor('.upf-avatar span');