diff --git a/addons/rose/addon/components/rose/layout/tabs.js b/addons/rose/addon/components/rose/layout/tabs.js new file mode 100644 index 000000000..88f0a170b --- /dev/null +++ b/addons/rose/addon/components/rose/layout/tabs.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../../templates/components/rose/layout/tabs'; + +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/components/rose/layout/tabs.stories.mdx b/addons/rose/addon/components/rose/layout/tabs.stories.mdx new file mode 100644 index 000000000..5ba3ad3f2 --- /dev/null +++ b/addons/rose/addon/components/rose/layout/tabs.stories.mdx @@ -0,0 +1,26 @@ +import { Meta, Story, Preview } from '@storybook/addon-docs/blocks'; +import { hbs } from 'ember-cli-htmlbars'; +import { action } from '@storybook/addon-actions'; + + + +# Tabs + +A tabs layout component to hold `Rose::Tab` definitions. + +```html + + + +``` + + + {{ + template: hbs` + + + + + `, + }} + diff --git a/addons/rose/addon/components/rose/notification.js b/addons/rose/addon/components/rose/notification.js index 856dbc863..8000e87b4 100644 --- a/addons/rose/addon/components/rose/notification.js +++ b/addons/rose/addon/components/rose/notification.js @@ -33,6 +33,5 @@ export default Component.extend({ } return icon; - } - + }, }); diff --git a/addons/rose/addon/components/rose/tab.js b/addons/rose/addon/components/rose/tab.js new file mode 100644 index 000000000..c37635f9b --- /dev/null +++ b/addons/rose/addon/components/rose/tab.js @@ -0,0 +1,7 @@ +import Component from '@ember/component'; +import layout from '../../templates/components/rose/tab'; + +export default Component.extend({ + layout, + tagName: '', +}); diff --git a/addons/rose/addon/components/rose/tab.stories.mdx b/addons/rose/addon/components/rose/tab.stories.mdx new file mode 100644 index 000000000..a4b7136aa --- /dev/null +++ b/addons/rose/addon/components/rose/tab.stories.mdx @@ -0,0 +1,43 @@ +import { Meta, Story, Preview } from '@storybook/addon-docs/blocks'; +import { hbs } from 'ember-cli-htmlbars'; +import { action } from '@storybook/addon-actions'; +import { text, boolean, select } from '@storybook/addon-knobs'; + + + +# Tab + +A tab item component with ability to configure icon, title, and badge sections. + +```html + +``` + + + {{ + template: hbs` + `, + context: { + title: text('title', 'Tab item'), + badge: text('badge', '3'), + icon: select( + 'icon', + { + 'info-circle-outline': 'info-circle-outline', + 'user-square-fill': 'user-square-fill', + 'check-circle-outline': 'check-circle-outline', + 'copy-action': 'copy-action', + 'unfold-more': 'unfold-more', + 'unfold-less': 'unfold-less', + }, + 'info-circle-outline' + ), + disabled: boolean('disabled', false) + }, + }} + diff --git a/addons/rose/addon/styles/rose/components/_notification.scss b/addons/rose/addon/styles/rose/components/_notification.scss index ac88ea4f4..c69dde3f1 100644 --- a/addons/rose/addon/styles/rose/components/_notification.scss +++ b/addons/rose/addon/styles/rose/components/_notification.scss @@ -58,11 +58,11 @@ } &:hover { - background-color: rgba(var(--stark-components), var(--opacity-3)) + background-color: rgba(var(--stark-components), var(--opacity-3)); } &:active { - background-color: rgba(var(--stark-components), var(--opacity-2)) + background-color: rgba(var(--stark-components), var(--opacity-2)); } } diff --git a/addons/rose/addon/styles/rose/components/_tab.scss b/addons/rose/addon/styles/rose/components/_tab.scss new file mode 100644 index 000000000..f6138608a --- /dev/null +++ b/addons/rose/addon/styles/rose/components/_tab.scss @@ -0,0 +1,53 @@ +@use '../variables/sizing'; +@use '../utilities/type'; + +.rose-tab { + @include type.type(s); + display: inline-block; + background-color: var(--subtle); + + .rose-tab-link { + text-decoration: none; + color: var(--ui-gray); + display: inline-block; + padding: sizing.rems(s) sizing.rems(m); + border-bottom: sizing.rems(xxxs) solid var(--subtle); + + &.rose-tab-link-disabled { + cursor: not-allowed; + pointer-events: none; + color: var(--ui-gray-subtler-2); + } + + &:active { + color: var(--action); + border-color: var(--action); + background-color: var(--subtle); + } + + &:hover { + color: var(--ui-gray); + border-color: var(--ui-gray-subtler-2); + background-color: var(--ui-gray-subtler-4); + } + + &:hover:active { + color: var(--action); + border-color: var(--action); + background-color: var(--ui-gray-subtler-4); + } + } + + .rose-tab-icon { + svg { + width: sizing.rems(m); + height: sizing.rems(m); + vertical-align: sub; + } + } + + .rose-tab-badge { + @include type.type(xs); + margin-left: sizing.rems(xxs); + } +} diff --git a/addons/rose/addon/styles/rose/components/card/_link.scss b/addons/rose/addon/styles/rose/components/card/_link.scss index ba0e367e8..26b3e3f8c 100644 --- a/addons/rose/addon/styles/rose/components/card/_link.scss +++ b/addons/rose/addon/styles/rose/components/card/_link.scss @@ -3,7 +3,7 @@ .rose-card-link { @include type.type(s); - border: 1px solid var(--ui-gray-subtler-2); + border: sizing.rems(xxxxs) solid var(--ui-gray-subtler-2); border-radius: sizing.rems(xxxs); color: var(--ui-gray); display: inline-flex; diff --git a/addons/rose/addon/styles/rose/components/layout/_index.scss b/addons/rose/addon/styles/rose/components/layout/_index.scss index 909cdbc83..27a5cbba3 100644 --- a/addons/rose/addon/styles/rose/components/layout/_index.scss +++ b/addons/rose/addon/styles/rose/components/layout/_index.scss @@ -1,6 +1,8 @@ @use '../../variables/sizing'; @use '../../variables/media'; +@import 'tabs'; + .rose-layout-page { display: grid; grid-template-areas: diff --git a/addons/rose/addon/styles/rose/components/layout/_tabs.scss b/addons/rose/addon/styles/rose/components/layout/_tabs.scss new file mode 100644 index 000000000..999018422 --- /dev/null +++ b/addons/rose/addon/styles/rose/components/layout/_tabs.scss @@ -0,0 +1,8 @@ +@use '../../variables/sizing'; + +.rose-layout-tabs { + border-bottom: sizing.rems(xxxxs) solid var(--ui-gray-subtler-2); + display: flex; + flex-wrap: wrap; + flex-direction: row; +} diff --git a/addons/rose/addon/templates/components/rose/layout/tabs.hbs b/addons/rose/addon/templates/components/rose/layout/tabs.hbs new file mode 100644 index 000000000..7b777cb8b --- /dev/null +++ b/addons/rose/addon/templates/components/rose/layout/tabs.hbs @@ -0,0 +1,3 @@ +
+ {{yield}} +
diff --git a/addons/rose/addon/templates/components/rose/tab.hbs b/addons/rose/addon/templates/components/rose/tab.hbs new file mode 100644 index 000000000..cfb65cf12 --- /dev/null +++ b/addons/rose/addon/templates/components/rose/tab.hbs @@ -0,0 +1,22 @@ +
+ + {{#if @icon}} + {{inline-svg @icon}} + {{/if}} + + {{#if @title}} + {{@title}} + {{/if}} + + {{#if @badge}} + {{@badge}} + {{/if}} + + + {{yield}} +
diff --git a/addons/rose/app/components/rose/layout/tabs.js b/addons/rose/app/components/rose/layout/tabs.js new file mode 100644 index 000000000..9de968192 --- /dev/null +++ b/addons/rose/app/components/rose/layout/tabs.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/layout/tabs'; diff --git a/addons/rose/app/components/rose/notification.js b/addons/rose/app/components/rose/notification.js index 228bd468c..bf9252122 100644 --- a/addons/rose/app/components/rose/notification.js +++ b/addons/rose/app/components/rose/notification.js @@ -1 +1 @@ -export { default } from 'rose/components/rose/notification'; \ No newline at end of file +export { default } from 'rose/components/rose/notification'; diff --git a/addons/rose/app/components/rose/tab.js b/addons/rose/app/components/rose/tab.js new file mode 100644 index 000000000..37b6e680c --- /dev/null +++ b/addons/rose/app/components/rose/tab.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/tab'; diff --git a/addons/rose/tests/dummy/app/templates/index.hbs b/addons/rose/tests/dummy/app/templates/index.hbs index a58b48caf..4b0ad9bdf 100644 --- a/addons/rose/tests/dummy/app/templates/index.hbs +++ b/addons/rose/tests/dummy/app/templates/index.hbs @@ -198,5 +198,7 @@ + + diff --git a/addons/rose/tests/integration/components/rose/layout/tabs-test.js b/addons/rose/tests/integration/components/rose/layout/tabs-test.js new file mode 100644 index 000000000..d14c5bc5f --- /dev/null +++ b/addons/rose/tests/integration/components/rose/layout/tabs-test.js @@ -0,0 +1,13 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/layout/tabs', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-layout-tabs')); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/notification-test.js b/addons/rose/tests/integration/components/rose/notification-test.js index 6027644d0..f8c1573b5 100644 --- a/addons/rose/tests/integration/components/rose/notification-test.js +++ b/addons/rose/tests/integration/components/rose/notification-test.js @@ -3,10 +3,10 @@ import { setupRenderingTest } from 'ember-qunit'; import { render, find, click } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; -module('Integration | Component | rose/notification', function(hooks) { +module('Integration | Component | rose/notification', function (hooks) { setupRenderingTest(hooks); - test('it renders', async function(assert) { + test('it renders', async function (assert) { await render(hbs` `); assert.ok(find('.rose-notification')); - assert.equal(find('.rose-notification-body').textContent.trim(), 'An error occurred.'); + assert.equal( + find('.rose-notification-body').textContent.trim(), + 'An error occurred.' + ); }); - test('it has optional dismiss button which triggers a function', async function(assert) { + test('it has optional dismiss button which triggers a function', async function (assert) { assert.expect(1); this.dismiss = () => assert.ok(true, 'dismiss clicked'); await render(hbs` diff --git a/addons/rose/tests/integration/components/rose/tab-test.js b/addons/rose/tests/integration/components/rose/tab-test.js new file mode 100644 index 000000000..b8eb0a74e --- /dev/null +++ b/addons/rose/tests/integration/components/rose/tab-test.js @@ -0,0 +1,50 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | rose/tab', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + await render(hbs``); + assert.ok(find('a')); + assert.ok(find('.rose-tab')); + assert.ok(find('.rose-tab-link')); + assert.notOk(find('.rose-tab-icon')); + assert.notOk(find('.rose-tab-badge')); + assert.notOk(find('.rose-tab-link-disabled')); + }); + + test('it renders with title', async function (assert) { + await render(hbs``); + assert.equal(find('a').title, 'Tab title'); + assert.equal(find('.rose-tab-link').textContent.trim(), 'Tab title'); + }); + + test('it renders with icon', async function (assert) { + await render(hbs``); + assert.ok(find('svg')); + assert.ok(find('.rose-tab-icon')); + }); + + test('it renders with badge', async function (assert) { + await render(hbs``); + assert.ok(find('.rose-tab-badge')); + assert.equal(find('.rose-tab-badge').textContent.trim(), '3'); + }); + + test('it render with attributes', async function (assert) { + await render(hbs``); + assert.ok(find('#tab')); + }); + + test('it renders disabled', async function (assert) { + this.set('disabled', true); + await render(hbs``); + assert.ok(find('.rose-tab-link-disabled')); + + this.set('disabled', false); + assert.notOk(find('.rose-tab-link-disabled')); + }); +});