diff --git a/addon/components/o-s-s/layout/sidebar/group.hbs b/addon/components/o-s-s/layout/sidebar/group.hbs index f59b938fb..f72c50d12 100644 --- a/addon/components/o-s-s/layout/sidebar/group.hbs +++ b/addon/components/o-s-s/layout/sidebar/group.hbs @@ -60,6 +60,7 @@ @hasNotifications={{item.hasNotifications}} @link={{item.link}} @routePrefix={{item.routePrefix}} + @tag={{item.tag}} @lockedAction={{item.lockedAction}} @action={{item.action}} @disableAutoActive={{item.disableAutoActive}} diff --git a/addon/components/o-s-s/layout/sidebar/group.stories.js b/addon/components/o-s-s/layout/sidebar/group.stories.js index 69008cd91..c17eecbad 100644 --- a/addon/components/o-s-s/layout/sidebar/group.stories.js +++ b/addon/components/o-s-s/layout/sidebar/group.stories.js @@ -92,7 +92,8 @@ const defaultArgs = { hasNotifications: true, locked: false, link: 'http://upfluence.com', - lockedAction: action('lockedAction') + lockedAction: action('lockedAction'), + tag: { label: 'New', skin: 'chat-gpt', plain: true } } ] }; diff --git a/addon/components/o-s-s/layout/sidebar/group.ts b/addon/components/o-s-s/layout/sidebar/group.ts index dc9b2001e..c37a7538e 100644 --- a/addon/components/o-s-s/layout/sidebar/group.ts +++ b/addon/components/o-s-s/layout/sidebar/group.ts @@ -3,6 +3,8 @@ import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { scheduleOnce } from '@ember/runloop'; +import type { SidebarItemTag } from '@upfluence/oss-components/components/o-s-s/layout/sidebar/item'; + export type GroupItem = { icon?: string; locked?: boolean; @@ -13,6 +15,7 @@ export type GroupItem = { active: boolean; dataControlName?: string; disableAutoActive?: boolean; + tag?: SidebarItemTag; lockedAction?(): unknown; action?(): void; }; diff --git a/addon/components/o-s-s/layout/sidebar/item.hbs b/addon/components/o-s-s/layout/sidebar/item.hbs index c4ee48e28..c56390b53 100644 --- a/addon/components/o-s-s/layout/sidebar/item.hbs +++ b/addon/components/o-s-s/layout/sidebar/item.hbs @@ -28,6 +28,17 @@ {{@label}} + {{#if @tag}} + + {{/if}} + {{#if this.hasNotifications}}
{{/if}} diff --git a/addon/components/o-s-s/layout/sidebar/item.stories.js b/addon/components/o-s-s/layout/sidebar/item.stories.js index a47c6bae7..8c4c56ad2 100644 --- a/addon/components/o-s-s/layout/sidebar/item.stories.js +++ b/addon/components/o-s-s/layout/sidebar/item.stories.js @@ -75,6 +75,16 @@ export default { type: 'boolean' } }, + tag: { + description: 'A tag to display next to the label, passed down to OSS::Tag (label, skin, icon, plain)', + table: { + type: { + summary: '{ label?: string; skin?: string; icon?: string; plain?: boolean }' + }, + defaultValue: { summary: 'undefined' } + }, + control: { type: 'object' } + }, lockedAction: { description: 'Function to be called on click when item is locked', table: { @@ -125,8 +135,8 @@ const Template = (args) => ({ + @expanded={{this.expanded}} @tag={{this.tag}} + @lockedAction={{this.lockedAction}} @action={{this.action}} /> `, @@ -152,3 +162,10 @@ BasicUsage.args = defaultArgs; export const WithNamedBlockIcon = IconNamedBlockTemplate.bind({}); WithNamedBlockIcon.args = defaultArgs; + +export const WithTag = Template.bind({}); +WithTag.args = { + ...defaultArgs, + expanded: true, + tag: { label: 'New', skin: 'chat-gpt', plain: true } +}; diff --git a/addon/components/o-s-s/layout/sidebar/item.ts b/addon/components/o-s-s/layout/sidebar/item.ts index f61149a3e..0c8545ffe 100644 --- a/addon/components/o-s-s/layout/sidebar/item.ts +++ b/addon/components/o-s-s/layout/sidebar/item.ts @@ -3,13 +3,15 @@ import { action } from '@ember/object'; import type { OSSTagArgs } from '@upfluence/oss-components/components/o-s-s/tag'; +export type SidebarItemTag = Pick; + interface OSSLayoutSidebarItemArgs { link: string; routePrefix?: string; icon?: string; locked?: boolean; hasNotifications?: boolean; - tag?: Pick; + tag?: SidebarItemTag; expanded?: boolean; label?: string; disableAutoActive?: boolean; diff --git a/app/styles/organisms/sidebar.less b/app/styles/organisms/sidebar.less index 4cafb5e42..18d5fc518 100644 --- a/app/styles/organisms/sidebar.less +++ b/app/styles/organisms/sidebar.less @@ -128,6 +128,14 @@ a.oss-sidebar-item { } } + &__tag { + position: absolute; + top: -6px; + right: 0; + opacity: 0; + transition: opacity 300ms ease-in-out; + } + &__notification { width: 3px; height: 3px; @@ -170,6 +178,10 @@ a.oss-sidebar-item { width: fit-content; opacity: 1; } + + .oss-sidebar-item__tag { + opacity: 1; + } } &:focus:not(&.active):not(:hover), diff --git a/tests/integration/components/o-s-s/layout/sidebar/group-test.ts b/tests/integration/components/o-s-s/layout/sidebar/group-test.ts index 2acf2d216..189614622 100644 --- a/tests/integration/components/o-s-s/layout/sidebar/group-test.ts +++ b/tests/integration/components/o-s-s/layout/sidebar/group-test.ts @@ -219,4 +219,34 @@ module('Integration | Component | o-s-s/layout/sidebar/group', function (hooks) assert.dom('.oss-sidebar-group > div .oss-sidebar-item .oss-sidebar-item__icon i').hasClass('fa-ship'); }); }); + + module('an item has a tag', function (hooks) { + hooks.beforeEach(function () { + this.expanded = true; + this.items = [ + { + icon: 'far fa-search', + link: '/search', + active: false, + hasNotifications: false, + label: 'Search', + tag: { label: 'New', skin: 'chat-gpt', plain: true } + } + ]; + }); + + test('the tag is propagated to the underlying item', async function (assert) { + await renderComponent(); + + assert + .dom('.oss-sidebar-group .oss-sidebar-group__items-container .oss-sidebar-item__tag') + .hasText('New'); + assert + .dom('.oss-sidebar-group .oss-sidebar-group__items-container .oss-sidebar-item__tag') + .hasClass('upf-tag--chat-gpt'); + assert + .dom('.oss-sidebar-group .oss-sidebar-group__items-container .oss-sidebar-item__tag') + .hasClass('upf-tag--plain'); + }); + }); }); diff --git a/tests/integration/components/o-s-s/layout/sidebar/item-test.ts b/tests/integration/components/o-s-s/layout/sidebar/item-test.ts index 0343470c2..358d6150e 100644 --- a/tests/integration/components/o-s-s/layout/sidebar/item-test.ts +++ b/tests/integration/components/o-s-s/layout/sidebar/item-test.ts @@ -67,6 +67,26 @@ module('Integration | Component | oss/layout/sidebar/item', function (hooks) { assert.dom('.oss-sidebar-item__label').hasText('Label'); }); }); + + module('Tag', () => { + test('Default value for tag is undefined', async function (assert) { + await render(hbs``); + assert.dom('.oss-sidebar-item__tag').doesNotExist(); + }); + + test('When tag is passed, it is rendered as a direct child of the item with all its args', async function (assert) { + this.tag = { label: 'New', skin: 'chat-gpt', icon: 'fa-star', plain: true }; + await render(hbs``); + + assert.dom('.oss-sidebar-item > .oss-sidebar-item__tag').exists(); + assert.dom('.oss-sidebar-item__tag').hasClass('upf-tag'); + assert.dom('.oss-sidebar-item__tag').hasClass('upf-tag--chat-gpt'); + assert.dom('.oss-sidebar-item__tag').hasClass('upf-tag--plain'); + assert.dom('.oss-sidebar-item__tag').hasClass('upf-tag--xs'); + assert.dom('.oss-sidebar-item__tag i').hasClass('fa-star'); + assert.dom('.oss-sidebar-item__tag').hasText('New'); + }); + }); }); module('Actions', function (hooks) {