Merge pull request #249 from hashicorp/populate-global-footer

Add global footer
This commit is contained in:
Randall Morey authored and GitHub committed 2020-10-01 11:28:10 -04:00
commit dbb0f0f9b1
29 files changed
+328 -10

No files matched your search

@@ -0,0 +1,12 @@
<LinkTo
...attributes
class="rose-footer-brand"
title={{@text}}
@route={{if @route @route "index"}}
>
{{#if @logo}}
{{inline-svg @logo}}
{{/if}}
</LinkTo>
@@ -0,0 +1,11 @@
<span class="rose-footer-copyright">
<span class="rose-footer-copyright-symbol">
&copy;
</span>
<span class="rose-footer-copyright-year">
{{this.currentYear}}
</span>
<span class="rose-footer-copyright-text">
{{@text}}
</span>
</span>
@@ -0,0 +1,8 @@
import Component from '@glimmer/component';
export default class RoseFooterCopyrightComponent extends Component {
// =attributes
currentYear = new Date().getFullYear();
}
@@ -0,0 +1,10 @@
<footer
...attributes
class="rose-footer"
>
{{yield (hash
nav=(component 'rose/footer/nav')
brand=(component 'rose/footer/brand')
text=(component "rose/anonymous" class="rose-footer-text")
)}}
</footer>
@@ -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';
<Meta title="Rose|Footer" component="Footer" />
# Footer
A footer component that allows four distinct sections to be configured: brand, nav, and text.
```html
<Rose::Footer as |footer|>
<footer.brand @logo="logo" @text="Product Name" />
<footer.text>Text</footer.text>
<footer.nav as |nav|>
<nav.link @route="index">Section</nav.link>
<nav.link @href="index">Section</nav.link>
</footer.nav>
</Rose::Footer>
```
<Preview>
<Story name="Basic">{{
template: hbs`
<Rose::Footer as |footer|>
<footer.brand @logo="logo" @text={{brandName}} />
<footer.text>{{footerText}}</footer.text>
<footer.nav as |nav|>
<nav.link @route="index">Section</nav.link>
<nav.link @href="index">Section</nav.link>
</footer.nav>
</Rose::Footer>
`,
context: {
brandName: text('brandName', 'Brand Name'),
footerText: text('footerText', 'Text'),
},
}}</Story>
</Preview>
@@ -0,0 +1,5 @@
<nav class="rose-footer-nav" aria-label="footer-nav">
{{yield (hash
link=(component 'rose/footer/nav/link')
)}}
</nav>
@@ -0,0 +1,20 @@
{{#if @href}}
<a target="_blank"
href={{@href}}
class="rose-footer-nav-link"
rel="noopener noreferrer"
>
{{yield}}
</a>
{{/if}}
{{#if @route}}
<LinkTo
...attributes
@route={{@route}}
@model={{@model}}
class="rose-footer-nav-link"
>
{{yield}}
</LinkTo>
{{/if}}
@@ -0,0 +1,11 @@
<span class="rose-footer-product">
<span class="rose-footer-product-text">
{{@text}}
</span>
{{#if @version}}
<span class="rose-footer-product-version">
v{{@version}}
</span>
{{/if}}
</span>
@@ -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")
)}}
</section>
@@ -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';
<Meta title="Rose|Layout|Global" component="Global" />
# 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
<Rose::Layout::Global as |layout|>
<layout.header />
<layout.body />
<layout.footer />
</Rose::Layout::Global>
```
<Preview>
<Story name="Global">{{
template: hbs`
<Rose::Layout::Global as |layout|>
<layout.header style="background: var(--brand-gray-5);">Header</layout.header>
<layout.body style="background: var(--brand-gray-7);">Body</layout.body>
</Rose::Layout::Global>
<Rose::Layout::Global as |layout|>
<layout.header style="background: var(--brand-gray-5);">Header</layout.header>
<layout.body style="background: var(--brand-gray-7);">Body</layout.body>
<layout.footer style="background: var(--brand-gray-5);">Footer</layout.footer>
</Rose::Layout::Global>
`,
}}</Story>
</Preview>
@@ -2,6 +2,7 @@
@import 'dropdown';
@import 'form';
@import 'header';
@import 'footer';
@import 'layout';
@import 'icon';
@import 'list';
@@ -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;
}
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -0,0 +1,7 @@
@use '../../variables/sizing';
.rose-footer-text {
display: inline-flex;
align-items: center;
margin: 0 sizing.rems(xs);
}
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/footer';
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/footer/brand';
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/footer/copyright';
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/footer/nav';
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/footer/nav/link';
@@ -0,0 +1 @@
export { default } from 'rose/components/rose/footer/product';
@@ -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`<Rose::Footer />`);
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`<Rose::Footer as |footer| >
<footer.brand />
</Rose::Footer>`);
assert.ok(find('.rose-footer-brand'));
});
test('it renders with nav', async function (assert) {
assert.expect(1);
await render(hbs`<Rose::Footer as |footer| >
<footer.nav />
</Rose::Footer>`);
assert.ok(find('.rose-footer-nav'));
});
test('it renders with text', async function (assert) {
assert.expect(1);
await render(hbs`<Rose::Footer as |footer| >
<footer.text />
</Rose::Footer>`);
assert.ok(find('.rose-footer-text'));
});
});
@@ -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`<Rose::Footer::nav />`);
assert.ok(find('.rose-footer-nav'));
});
test('it renders nav external link elements', async function (assert) {
assert.expect(1);
await render(hbs`<Rose::Footer::nav as |nav| >
<nav.link @href="index"/>
<nav.link @route="about"/>
</Rose::Footer::nav>`);
assert.equal(findAll('a').length, 2);
});
});
@@ -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`<Rose::Footer::Nav::Link @href="localhost" />`);
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`<Rose::Footer::Nav::Link @route="index" />`);
assert.ok(find('a'));
assert.ok(find('.rose-footer-nav-link'));
});
});
@@ -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`<Rose::Footer as |footer|>
<footer.text />
</Rose::Footer>`);
assert.ok(find('.rose-footer-text'));
});
test('it renders content', async function (assert) {
assert.expect(1);
await render(hbs`<Rose::Footer as |footer|>
<footer.text>content</footer.text>
</Rose::Footer>`);
assert.equal(find('.rose-footer-text').textContent.trim(), 'content');
});
});
@@ -30,4 +30,11 @@ module('Integration | Component | rose/layout/global', function (hooks) {
</Rose::Layout::Global>`);
assert.ok(find('.rose-layout-global-body'));
});
test('it renders with footer', async function (assert) {
await render(hbs`<Rose::Layout::Global as |layout|>
<layout.footer />
</Rose::Layout::Global>`);
assert.ok(find('.rose-layout-global-footer'));
});
});
+11
View File
@@ -37,6 +37,17 @@
{{outlet}}
</layout.body>
<layout.footer>
<Rose::Footer as |footer|>
<footer.brand @logo="logo-hashi" @text={{t "hashicorp.title"}} />
<footer.text>{{t "hashicorp.copyright"}}</footer.text>
<footer.text>{{t "hashicorp.product"}}</footer.text>
<footer.nav as |nav|>
<nav.link @href={{t "hashicorp.documentation.link"}}>{{t "hashicorp.documentation.title"}}</nav.link>
</footer.nav>
</Rose::Footer>
</layout.footer>
</Rose::Layout::Global>
<EmberNotify @closeAfter={{this.notifyTimeout}} as |message close|>
+8 -1
View File
@@ -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.
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