diff --git a/addons/rose/addon/components/rose/footer/brand/index.hbs b/addons/rose/addon/components/rose/footer/brand/index.hbs new file mode 100644 index 000000000..27b91417f --- /dev/null +++ b/addons/rose/addon/components/rose/footer/brand/index.hbs @@ -0,0 +1,12 @@ + + + {{#if @logo}} + {{inline-svg @logo}} + {{/if}} + + diff --git a/addons/rose/addon/components/rose/footer/copyright/index.hbs b/addons/rose/addon/components/rose/footer/copyright/index.hbs new file mode 100644 index 000000000..47e582dcb --- /dev/null +++ b/addons/rose/addon/components/rose/footer/copyright/index.hbs @@ -0,0 +1,11 @@ + + + © + + + {{this.currentYear}} + + + {{@text}} + + diff --git a/addons/rose/addon/components/rose/footer/copyright/index.js b/addons/rose/addon/components/rose/footer/copyright/index.js new file mode 100644 index 000000000..a9068f750 --- /dev/null +++ b/addons/rose/addon/components/rose/footer/copyright/index.js @@ -0,0 +1,8 @@ +import Component from '@glimmer/component'; + +export default class RoseFooterCopyrightComponent extends Component { + + // =attributes + currentYear = new Date().getFullYear(); + +} diff --git a/addons/rose/addon/components/rose/footer/index.hbs b/addons/rose/addon/components/rose/footer/index.hbs new file mode 100644 index 000000000..bbe5ecc72 --- /dev/null +++ b/addons/rose/addon/components/rose/footer/index.hbs @@ -0,0 +1,10 @@ + diff --git a/addons/rose/addon/components/rose/footer/index.stories.mdx b/addons/rose/addon/components/rose/footer/index.stories.mdx new file mode 100644 index 000000000..608bc1068 --- /dev/null +++ b/addons/rose/addon/components/rose/footer/index.stories.mdx @@ -0,0 +1,40 @@ +import { Meta, Story, Preview } from '@storybook/addon-docs/blocks'; +import { hbs } from 'ember-cli-htmlbars'; +import { action } from '@storybook/addon-actions'; +import { text } from '@storybook/addon-knobs'; + + + +# Footer + +A footer component that allows four distinct sections to be configured: brand, nav, and text. + +```html + + + Text + + Section + Section + + +``` + + + {{ + template: hbs` + + + {{footerText}} + + Section + Section + + + `, + context: { + brandName: text('brandName', 'Brand Name'), + footerText: text('footerText', 'Text'), + }, + }} + diff --git a/addons/rose/addon/components/rose/footer/nav/index.hbs b/addons/rose/addon/components/rose/footer/nav/index.hbs new file mode 100644 index 000000000..c03ac88c9 --- /dev/null +++ b/addons/rose/addon/components/rose/footer/nav/index.hbs @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/addons/rose/addon/components/rose/footer/nav/link/index.hbs b/addons/rose/addon/components/rose/footer/nav/link/index.hbs new file mode 100644 index 000000000..bebaacc29 --- /dev/null +++ b/addons/rose/addon/components/rose/footer/nav/link/index.hbs @@ -0,0 +1,20 @@ +{{#if @href}} + + {{yield}} + +{{/if}} + +{{#if @route}} + + {{yield}} + +{{/if}} diff --git a/addons/rose/addon/components/rose/footer/product/index.hbs b/addons/rose/addon/components/rose/footer/product/index.hbs new file mode 100644 index 000000000..6d3436db1 --- /dev/null +++ b/addons/rose/addon/components/rose/footer/product/index.hbs @@ -0,0 +1,11 @@ + + + {{@text}} + + + {{#if @version}} + + v{{@version}} + + {{/if}} + \ No newline at end of file diff --git a/addons/rose/addon/components/rose/layout/global/index.hbs b/addons/rose/addon/components/rose/layout/global/index.hbs index bfa2c8e75..373f70531 100644 --- a/addons/rose/addon/components/rose/layout/global/index.hbs +++ b/addons/rose/addon/components/rose/layout/global/index.hbs @@ -2,5 +2,6 @@ {{yield (hash header=(component "rose/anonymous" tagName="header" class="rose-layout-global-header") body=(component "rose/anonymous" class="rose-layout-global-body") + footer=(component "rose/anonymous" class="rose-layout-global-footer") )}} diff --git a/addons/rose/addon/components/rose/layout/global/index.stories.mdx b/addons/rose/addon/components/rose/layout/global/index.stories.mdx index 9b8e34ea4..22cb6b8e6 100644 --- a/addons/rose/addon/components/rose/layout/global/index.stories.mdx +++ b/addons/rose/addon/components/rose/layout/global/index.stories.mdx @@ -1,29 +1,29 @@ 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'; # Layout|Global -A top-level layout/positioning component that allows two distinct sections to -be configured: header and body. +A top-level layout/positioning component that allows three distinct sections to +be configured: header, body, and footer. -```htmlbars +```html + ``` {{ template: hbs` - - Header - Body - + + Header + Body + Footer + `, }} diff --git a/addons/rose/addon/styles/rose/components/_index.scss b/addons/rose/addon/styles/rose/components/_index.scss index 19a9d3de6..6e6ef8490 100644 --- a/addons/rose/addon/styles/rose/components/_index.scss +++ b/addons/rose/addon/styles/rose/components/_index.scss @@ -2,6 +2,7 @@ @import 'dropdown'; @import 'form'; @import 'header'; +@import 'footer'; @import 'layout'; @import 'icon'; @import 'list'; diff --git a/addons/rose/addon/styles/rose/components/footer/_brand.scss b/addons/rose/addon/styles/rose/components/footer/_brand.scss new file mode 100644 index 000000000..26e5f2983 --- /dev/null +++ b/addons/rose/addon/styles/rose/components/footer/_brand.scss @@ -0,0 +1,14 @@ +@use '../../variables/sizing'; + +.rose-footer-brand { + display: flex; + align-items: center; + color: var(--ui-gray-starker-1); + margin: sizing.rems(xs); + + svg { + $logoSize: sizing.rems(m); + display: inline-block; + width: $logoSize; + } +} diff --git a/addons/rose/addon/styles/rose/components/footer/_index.scss b/addons/rose/addon/styles/rose/components/footer/_index.scss new file mode 100644 index 000000000..9632c4e0c --- /dev/null +++ b/addons/rose/addon/styles/rose/components/footer/_index.scss @@ -0,0 +1,17 @@ +@use '../../variables/sizing'; +@use '../../variables/media'; +@use '../../utilities/type'; + +@import 'brand'; +@import 'nav'; +@import 'text'; +@import 'link'; + +.rose-footer { + @include type.type(xs); + + display: flex; + justify-content: center; + color: var(--ui-gray-starker-1); + height: sizing.rems(xxl) + sizing.rems(xxs); +} diff --git a/addons/rose/addon/styles/rose/components/footer/_link.scss b/addons/rose/addon/styles/rose/components/footer/_link.scss new file mode 100644 index 000000000..dc35db4c0 --- /dev/null +++ b/addons/rose/addon/styles/rose/components/footer/_link.scss @@ -0,0 +1,9 @@ +@use '../../variables/sizing'; + +.rose-footer-nav-link { + display: inline-flex; + align-items: center; + text-decoration: underline; + color: var(--ui-gray-starker-1); + margin: 0 sizing.rems(xs); +} diff --git a/addons/rose/addon/styles/rose/components/footer/_nav.scss b/addons/rose/addon/styles/rose/components/footer/_nav.scss new file mode 100644 index 000000000..bd23dde4a --- /dev/null +++ b/addons/rose/addon/styles/rose/components/footer/_nav.scss @@ -0,0 +1,9 @@ +@use '../../variables/sizing'; + +.rose-footer-nav { + grid-area: nav; + display: flex; + flex-wrap: wrap; + align-items: center; + margin-right: sizing.rems(s); +} diff --git a/addons/rose/addon/styles/rose/components/footer/_text.scss b/addons/rose/addon/styles/rose/components/footer/_text.scss new file mode 100644 index 000000000..9e7b29b8b --- /dev/null +++ b/addons/rose/addon/styles/rose/components/footer/_text.scss @@ -0,0 +1,7 @@ +@use '../../variables/sizing'; + +.rose-footer-text { + display: inline-flex; + align-items: center; + margin: 0 sizing.rems(xs); +} diff --git a/addons/rose/app/components/rose/footer.js b/addons/rose/app/components/rose/footer.js new file mode 100644 index 000000000..ccac33104 --- /dev/null +++ b/addons/rose/app/components/rose/footer.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/footer'; \ No newline at end of file diff --git a/addons/rose/app/components/rose/footer/brand.js b/addons/rose/app/components/rose/footer/brand.js new file mode 100644 index 000000000..995d715ba --- /dev/null +++ b/addons/rose/app/components/rose/footer/brand.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/footer/brand'; \ No newline at end of file diff --git a/addons/rose/app/components/rose/footer/copyright.js b/addons/rose/app/components/rose/footer/copyright.js new file mode 100644 index 000000000..d46304fc7 --- /dev/null +++ b/addons/rose/app/components/rose/footer/copyright.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/footer/copyright'; \ No newline at end of file diff --git a/addons/rose/app/components/rose/footer/nav.js b/addons/rose/app/components/rose/footer/nav.js new file mode 100644 index 000000000..3ca032af2 --- /dev/null +++ b/addons/rose/app/components/rose/footer/nav.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/footer/nav'; \ No newline at end of file diff --git a/addons/rose/app/components/rose/footer/nav/link.js b/addons/rose/app/components/rose/footer/nav/link.js new file mode 100644 index 000000000..e38b27530 --- /dev/null +++ b/addons/rose/app/components/rose/footer/nav/link.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/footer/nav/link'; \ No newline at end of file diff --git a/addons/rose/app/components/rose/footer/product.js b/addons/rose/app/components/rose/footer/product.js new file mode 100644 index 000000000..7193b5690 --- /dev/null +++ b/addons/rose/app/components/rose/footer/product.js @@ -0,0 +1 @@ +export { default } from 'rose/components/rose/footer/product'; \ No newline at end of file diff --git a/addons/rose/tests/integration/components/rose/footer-test.js b/addons/rose/tests/integration/components/rose/footer-test.js new file mode 100644 index 000000000..4a43f0d4f --- /dev/null +++ b/addons/rose/tests/integration/components/rose/footer-test.js @@ -0,0 +1,42 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | rose/footer', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + assert.expect(4); + await render(hbs``); + assert.ok(find('.rose-footer')); + assert.notOk(find('.rose-footer-nav')); + assert.notOk(find('.rose-footer-text')); + assert.notOk(find('.rose-footer-brand')); + }); + + test('it renders with brand', async function (assert) { + assert.expect(1); + await render(hbs` + + `); + assert.ok(find('.rose-footer-brand')); + }); + + test('it renders with nav', async function (assert) { + assert.expect(1); + await render(hbs` + + `); + assert.ok(find('.rose-footer-nav')); + }); + + test('it renders with text', async function (assert) { + assert.expect(1); + await render(hbs` + + `); + assert.ok(find('.rose-footer-text')); + }); + +}); diff --git a/addons/rose/tests/integration/components/rose/footer/nav-test.js b/addons/rose/tests/integration/components/rose/footer/nav-test.js new file mode 100644 index 000000000..782602f44 --- /dev/null +++ b/addons/rose/tests/integration/components/rose/footer/nav-test.js @@ -0,0 +1,24 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find, findAll } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | rose/footer/nav', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + assert.expect(1); + await render(hbs``); + assert.ok(find('.rose-footer-nav')); + }); + + test('it renders nav external link elements', async function (assert) { + assert.expect(1); + await render(hbs` + + + `); + assert.equal(findAll('a').length, 2); + }); + +}); diff --git a/addons/rose/tests/integration/components/rose/footer/nav/link-test.js b/addons/rose/tests/integration/components/rose/footer/nav/link-test.js new file mode 100644 index 000000000..d5405db01 --- /dev/null +++ b/addons/rose/tests/integration/components/rose/footer/nav/link-test.js @@ -0,0 +1,22 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | rose/footer/nav/link', function(hooks) { + setupRenderingTest(hooks); + + test('it renders with @href', async function (assert) { + assert.expect(2); + await render(hbs``); + assert.ok(find('a')); + assert.ok(find('.rose-footer-nav-link')); + }); + + test('it renders with @route', async function (assert) { + assert.expect(2); + await render(hbs``); + assert.ok(find('a')); + assert.ok(find('.rose-footer-nav-link')); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/footer/text-test.js b/addons/rose/tests/integration/components/rose/footer/text-test.js new file mode 100644 index 000000000..d3cbfacff --- /dev/null +++ b/addons/rose/tests/integration/components/rose/footer/text-test.js @@ -0,0 +1,24 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, find } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | rose/footer/text', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + assert.expect(1); + await render(hbs` + + `); + assert.ok(find('.rose-footer-text')); + }); + + test('it renders content', async function (assert) { + assert.expect(1); + await render(hbs` + content + `); + assert.equal(find('.rose-footer-text').textContent.trim(), 'content'); + }); +}); diff --git a/addons/rose/tests/integration/components/rose/layout/global-test.js b/addons/rose/tests/integration/components/rose/layout/global-test.js index 2e6b91039..aa87f074b 100644 --- a/addons/rose/tests/integration/components/rose/layout/global-test.js +++ b/addons/rose/tests/integration/components/rose/layout/global-test.js @@ -30,4 +30,11 @@ module('Integration | Component | rose/layout/global', function (hooks) { `); assert.ok(find('.rose-layout-global-body')); }); + + test('it renders with footer', async function (assert) { + await render(hbs` + + `); + assert.ok(find('.rose-layout-global-footer')); + }); }); diff --git a/ui/core/app/templates/application.hbs b/ui/core/app/templates/application.hbs index d63eee931..a40b1dcba 100644 --- a/ui/core/app/templates/application.hbs +++ b/ui/core/app/templates/application.hbs @@ -37,6 +37,17 @@ {{outlet}} + + + + {{t "hashicorp.copyright"}} + {{t "hashicorp.product"}} + + {{t "hashicorp.documentation.title"}} + + + + diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml index a86a36263..6755b8976 100644 --- a/ui/core/translations/en-us.yaml +++ b/ui/core/translations/en-us.yaml @@ -17,4 +17,11 @@ titles: global: Global actions: Actions descriptions: - empty-set: There are no items to display yet. You may be able to add items or try back later. \ No newline at end of file + empty-set: There are no items to display yet. You may be able to add items or try back later. +hashicorp: + title: HashiCorp + copyright: © 2020 HashiCorp + product: Boundary v0.1 + documentation: + title: Documentation + link: https://boundaryproject.io