chore: 🤖 add primary nav component for sidebar
This commit is contained in:
13 files changed
+347
-177
No files matched your search
@@ -0,0 +1,11 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../templates/components/rose/nav/primary';
|
||||
import ComponentAutoId from '../../../mixins/component-auto-id';
|
||||
|
||||
/**
|
||||
* A simple navigation component intended for the sidebar layout region.
|
||||
*/
|
||||
export default Component.extend(ComponentAutoId, {
|
||||
layout,
|
||||
tagName: '',
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
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|Nav/Primary" component="Nav/Primary" />
|
||||
|
||||
# Primary Navigation
|
||||
|
||||
A simple navigation component intended for use in the sidebar layout region.
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic Primary Nav" height="8rem">{{
|
||||
template: hbs`
|
||||
<Rose::Nav::Primary @title={{title}} as |nav|>
|
||||
<nav.link @route="index" class="active">Item Name</nav.link>
|
||||
<nav.link @route="index">Item Name</nav.link>
|
||||
</Rose::Nav::Primary>
|
||||
`,
|
||||
context: {
|
||||
title: text('title', 'Title'),
|
||||
},
|
||||
}}</Story>
|
||||
</Preview>
|
||||
|
||||
_Note_: do not assign the `active` class directly. This is done by the link
|
||||
component automatically. We use it in this story for illustrative purposes.
|
||||
|
||||
```htmlbars
|
||||
<Rose::Nav::Primary @title="Title" as |nav|>
|
||||
<nav.link @route="index">Item Name</nav.link>
|
||||
<nav.link @route="about">Item Name</nav.link>
|
||||
</Rose::Nav::Primary>
|
||||
```
|
||||
@@ -4,3 +4,4 @@
|
||||
@import 'layout';
|
||||
@import 'notification';
|
||||
@import 'card';
|
||||
@import 'nav';
|
||||
@@ -0,0 +1 @@
|
||||
@import "primary";
|
||||
@@ -0,0 +1,40 @@
|
||||
@use '../../variables/sizing';
|
||||
@use '../../utilities/type';
|
||||
|
||||
.rose-nav-primary {
|
||||
$threePX: sizing.rems(xxxs) + sizing.rems(xxxxs);
|
||||
|
||||
.rose-nav-title {
|
||||
@include type.type(xs, semibold);
|
||||
display: block;
|
||||
color: var(--ui-gray);
|
||||
text-transform: uppercase;
|
||||
$lineHeight: 20 / 12;
|
||||
line-height: $lineHeight;
|
||||
padding: 0 sizing.rems(m);
|
||||
margin-bottom: $threePX;
|
||||
border-bottom: sizing.rems(xxxxs) solid var(--ui-gray-subtler-2);
|
||||
}
|
||||
|
||||
.rose-nav-link {
|
||||
@include type.type(s);
|
||||
display: block;
|
||||
color: var(--stark);
|
||||
$lineHeight: 36 / 14;
|
||||
line-height: $lineHeight;
|
||||
text-decoration: none;
|
||||
padding: 0 sizing.rems(m);
|
||||
border-right: $threePX solid transparent;
|
||||
|
||||
&.active {
|
||||
color: var(--action);
|
||||
border-color: currentColor;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
color: var(--action);
|
||||
background-color: var(--action-subtler-1h);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@
|
||||
--success-starker-1: #{color(green, 800)};
|
||||
|
||||
--action-subtler-2: #{color(blue, 010)};
|
||||
--action-subtler-1h: #{color(blue, 050)};
|
||||
--action-subtler-1: #{color(blue, 100)};
|
||||
--action: #{color(blue)};
|
||||
--action-starker-1: #{color(blue, 700)};
|
||||
@@ -115,6 +116,7 @@
|
||||
--success-starker-1: #{color(green, 200)};
|
||||
|
||||
--action-subtler-2: #{color(blue, 900)};
|
||||
--action-subtler-1h: #{color(blue, 800)};
|
||||
--action-subtler-1: #{color(blue, 800)};
|
||||
--action: #{color(blue)};
|
||||
--action-starker-1: #{color(blue, 300)};
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<nav
|
||||
...attributes
|
||||
class="rose-nav-primary"
|
||||
id={{this.id}}
|
||||
aria-labelledby={{if @title (concat "title-" this.id)}}>
|
||||
|
||||
{{#if @title}}
|
||||
<span class="rose-nav-title" id="title-{{this.id}}">
|
||||
{{@title}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{yield (hash
|
||||
link=(component "link-to" class="rose-nav-link")
|
||||
)}}
|
||||
|
||||
</nav>
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from 'rose/components/rose/nav/primary';
|
||||
@@ -1,187 +1,202 @@
|
||||
<Rose::Header as |header|>
|
||||
<Rose::Layout::Page as |page|>
|
||||
<page.header>
|
||||
<Rose::Header as |header|>
|
||||
|
||||
<header.brand @logo="logo" @text="Product Name" />
|
||||
<header.brand @logo="logo" @text="Product Name" />
|
||||
|
||||
<header.nav as |nav|>
|
||||
<nav.dropdown @text="org-name" as |dropdown|>
|
||||
<dropdown.link @route="index">Menu item</dropdown.link>
|
||||
<dropdown.link @route="about">Menu item</dropdown.link>
|
||||
<dropdown.button>Button menu item</dropdown.button>
|
||||
</nav.dropdown>
|
||||
<nav.link @route="index">Section</nav.link>
|
||||
<nav.link @route="about">Section</nav.link>
|
||||
</header.nav>
|
||||
<header.nav as |nav|>
|
||||
<nav.dropdown @text="org-name" as |dropdown|>
|
||||
<dropdown.link @route="index">Menu item</dropdown.link>
|
||||
<dropdown.link @route="about">Menu item</dropdown.link>
|
||||
<dropdown.button>Button menu item</dropdown.button>
|
||||
</nav.dropdown>
|
||||
<nav.link @route="index">Section</nav.link>
|
||||
<nav.link @route="about">Section</nav.link>
|
||||
</header.nav>
|
||||
|
||||
|
||||
<header.utilities as |utilities|>
|
||||
<utilities.dropdown
|
||||
@text="user@example.net"
|
||||
@iconOnly={{true}}
|
||||
@icon="user-square-fill" as |dropdown|
|
||||
<header.utilities as |utilities|>
|
||||
<utilities.dropdown
|
||||
@text="user@example.net"
|
||||
@iconOnly={{true}}
|
||||
@icon="user-square-fill" as |dropdown|
|
||||
>
|
||||
<dropdown.link @route="index">Menu item</dropdown.link>
|
||||
<dropdown.link @route="about">Menu item</dropdown.link>
|
||||
<dropdown.button>Button menu item</dropdown.button>
|
||||
</utilities.dropdown>
|
||||
</header.utilities>
|
||||
|
||||
</Rose::Header>
|
||||
</page.header>
|
||||
|
||||
<page.sidebar>
|
||||
<Rose::Nav::Primary @title="Title" as |nav|>
|
||||
<nav.link @route="index">Item Name</nav.link>
|
||||
<nav.link @route="about">Item Name</nav.link>
|
||||
<nav.link @route="about">Item Name</nav.link>
|
||||
<nav.link @route="about">Item Name</nav.link>
|
||||
</Rose::Nav::Primary>
|
||||
</page.sidebar>
|
||||
|
||||
<page.main>
|
||||
|
||||
Dummy app index template
|
||||
|
||||
<Rose::Notification
|
||||
@style="error"
|
||||
@heading="Error"
|
||||
@dismiss={{this.actionHandler}}
|
||||
@dismissText="Dismiss"
|
||||
>
|
||||
<dropdown.link @route="index">Menu item</dropdown.link>
|
||||
<dropdown.link @route="about">Menu item</dropdown.link>
|
||||
<dropdown.button>Button menu item</dropdown.button>
|
||||
</utilities.dropdown>
|
||||
</header.utilities>
|
||||
An error occurred.
|
||||
</Rose::Notification>
|
||||
|
||||
</Rose::Header>
|
||||
<h2>Icon</h2>
|
||||
<Rose::Icon @name="alert-circle-fill" />
|
||||
<Rose::Icon @name="alert-circle-fill" @size="medium" />
|
||||
<Rose::Icon @name="alert-circle-fill" @size="small" />
|
||||
|
||||
<h2>Button</h2>
|
||||
<Rose::Button @style="primary">Primary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="primary" @disabled={{true}}>Primary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<Rose::Button @style="secondary">Secondary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="secondary" @disabled={{true}}>Secondary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<h2>Form</h2>
|
||||
<Rose::Form
|
||||
@onSubmit={{this.actionHandler}}
|
||||
@cancel={{this.actionHandler}}
|
||||
@disabled={{false}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@value="Read only"
|
||||
readonly={{true}}
|
||||
/>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
@error={{true}}
|
||||
/>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h3>Textareas</h3>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@value="Read only"
|
||||
readonly={{true}}
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
@error={{true}}
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h3>Selects</h3>
|
||||
<form.select
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{fn this.actionHandler}}
|
||||
as |field|
|
||||
>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose an option</select.option>
|
||||
<select.option @value="value-1">Value 1</select.option>
|
||||
<select.option @value="value-2">Value 2</select.option>
|
||||
<select.option @value="value-3">Value 3</select.option>
|
||||
</field.field>
|
||||
</form.select>
|
||||
<form.select
|
||||
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{fn this.actionHandler}}
|
||||
as |field|
|
||||
>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose an option</select.option>
|
||||
</field.field>
|
||||
</form.select>
|
||||
|
||||
|
||||
Dummy app index template
|
||||
<h3>Radio Group</h3>
|
||||
<form.radioGroup @name="color" @selectedValue={{this.color}} as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@label="Red"
|
||||
@value="red"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Green"
|
||||
@value="green"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Blue"
|
||||
@value="blue"
|
||||
@disabled={{true}}
|
||||
/>
|
||||
</form.radioGroup>
|
||||
|
||||
<Rose::Notification
|
||||
@style="error"
|
||||
@heading="Error"
|
||||
@dismiss={{this.actionHandler}}
|
||||
@dismissText="Dismiss"
|
||||
>
|
||||
An error occurred.
|
||||
</Rose::Notification>
|
||||
<h3>Checkboxes</h3>
|
||||
<form.checkbox
|
||||
@label="Label"
|
||||
/>
|
||||
<form.checkbox
|
||||
@error={{true}}
|
||||
@label="Error"
|
||||
/>
|
||||
<form.checkbox
|
||||
@checked={{true}}
|
||||
@label="Checked"
|
||||
/>
|
||||
<form.checkbox
|
||||
@label="Disabled"
|
||||
disabled={{true}}
|
||||
/>
|
||||
<form.checkbox
|
||||
@checked={{true}}
|
||||
@label="Disabled + Checked"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h2>Icon</h2>
|
||||
<Rose::Icon @name="alert-circle-fill" />
|
||||
<Rose::Icon @name="alert-circle-fill" @size="medium" />
|
||||
<Rose::Icon @name="alert-circle-fill" @size="small" />
|
||||
<form.actions
|
||||
@submitText="Save"
|
||||
@cancelText="Cancel" />
|
||||
</Rose::Form>
|
||||
|
||||
<h2>Button</h2>
|
||||
<Rose::Button @style="primary">Primary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="primary" @disabled={{true}}>Primary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<Rose::Button @style="secondary">Secondary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="secondary" @disabled={{true}}>Secondary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<h2>Form</h2>
|
||||
<Rose::Form
|
||||
@onSubmit={{this.actionHandler}}
|
||||
@cancel={{this.actionHandler}}
|
||||
@disabled={{false}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<h3>Inputs</h3>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@value="Read only"
|
||||
readonly={{true}}
|
||||
/>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
@error={{true}}
|
||||
/>
|
||||
<form.input
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h3>Textareas</h3>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@value="Read only"
|
||||
readonly={{true}}
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
@error={{true}}
|
||||
/>
|
||||
<form.textarea
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@value="Text"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<h3>Selects</h3>
|
||||
<form.select
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{fn this.actionHandler}}
|
||||
as |field|
|
||||
>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose an option</select.option>
|
||||
<select.option @value="value-1">Value 1</select.option>
|
||||
<select.option @value="value-2">Value 2</select.option>
|
||||
<select.option @value="value-3">Value 3</select.option>
|
||||
</field.field>
|
||||
</form.select>
|
||||
<form.select
|
||||
|
||||
@label="Label"
|
||||
@helperText="Helper text"
|
||||
@onChange={{fn this.actionHandler}}
|
||||
as |field|
|
||||
>
|
||||
<field.field as |select|>
|
||||
<select.option>Choose an option</select.option>
|
||||
</field.field>
|
||||
</form.select>
|
||||
|
||||
|
||||
<h3>Radio Group</h3>
|
||||
<form.radioGroup @name="color" @selectedValue={{this.color}} as |radioGroup|>
|
||||
<radioGroup.radio
|
||||
@label="Red"
|
||||
@value="red"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Green"
|
||||
@value="green"
|
||||
/>
|
||||
<radioGroup.radio
|
||||
@label="Blue"
|
||||
@value="blue"
|
||||
@disabled={{true}}
|
||||
/>
|
||||
</form.radioGroup>
|
||||
|
||||
<h3>Checkboxes</h3>
|
||||
<form.checkbox
|
||||
@label="Label"
|
||||
/>
|
||||
<form.checkbox
|
||||
@error={{true}}
|
||||
@label="Error"
|
||||
/>
|
||||
<form.checkbox
|
||||
@checked={{true}}
|
||||
@label="Checked"
|
||||
/>
|
||||
<form.checkbox
|
||||
@label="Disabled"
|
||||
disabled={{true}}
|
||||
/>
|
||||
<form.checkbox
|
||||
@checked={{true}}
|
||||
@label="Disabled + Checked"
|
||||
disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.actions
|
||||
@submitText="Save"
|
||||
@cancelText="Cancel" />
|
||||
</Rose::Form>
|
||||
|
||||
<Rose::Card::Link @title="I'm a card" />
|
||||
<Rose::Card::Link @title="I'm a card" @description="I'm a description" />
|
||||
<Rose::Card::Link @title="I'm a card" @description="I'm a description" @subtitle="I'm a subtitle"/>
|
||||
<Rose::Card::Link @title="I'm a card" />
|
||||
<Rose::Card::Link @title="I'm a card" @description="I'm a description" />
|
||||
<Rose::Card::Link @title="I'm a card" @description="I'm a description" @subtitle="I'm a subtitle"/>
|
||||
</page.main>
|
||||
</Rose::Layout::Page>
|
||||
@@ -0,0 +1,34 @@
|
||||
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/nav/primary', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function(assert) {
|
||||
assert.expect(2)
|
||||
await render(hbs`
|
||||
<Rose::Nav::Primary @title="Title" as |nav|>
|
||||
<nav.link @route="index">Item Name</nav.link>
|
||||
</Rose::Nav::Primary>
|
||||
`);
|
||||
assert.equal(find('.rose-nav-title').textContent.trim(), 'Title');
|
||||
assert.equal(find('.rose-nav-link').textContent.trim(), 'Item Name');
|
||||
});
|
||||
|
||||
test('it associates title with nav via aria-labelledby', async function (assert) {
|
||||
assert.expect(2)
|
||||
await render(hbs`
|
||||
<Rose::Nav::Primary @title="Title" as |nav|>
|
||||
<nav.link @route="index">Item Name</nav.link>
|
||||
</Rose::Nav::Primary>
|
||||
`);
|
||||
const el = find('.rose-nav-primary');
|
||||
const id = el.id;
|
||||
const titleId = `title-${id}`;
|
||||
const titleEl = find('.rose-nav-title');
|
||||
assert.equal(titleEl.id, titleId);
|
||||
assert.equal(el.getAttribute('aria-labelledby').trim(), titleId);
|
||||
});
|
||||
});
|
||||
@@ -3,6 +3,10 @@
|
||||
@import 'rose';
|
||||
@import 'notify';
|
||||
|
||||
.rose-nav-primary {
|
||||
margin-top: sizing.rems(xxl);
|
||||
}
|
||||
|
||||
.projects-overview {
|
||||
margin: sizing.rems(l);
|
||||
|
||||
|
||||
@@ -29,7 +29,15 @@
|
||||
{{outlet}}
|
||||
</page.main>
|
||||
|
||||
<page.sidebar />
|
||||
<page.sidebar>
|
||||
<Rose::Nav::Primary @title={{t 'dev.title'}} as |nav|>
|
||||
<nav.link @route="orgs" class="active">{{t 'dev.item-name'}}</nav.link>
|
||||
<nav.link @route="index">{{t 'dev.item-name'}}</nav.link>
|
||||
<nav.link @route="index">{{t 'dev.item-name'}}</nav.link>
|
||||
<nav.link @route="index">{{t 'dev.item-name'}}</nav.link>
|
||||
</Rose::Nav::Primary>
|
||||
</page.sidebar>
|
||||
|
||||
</Rose::Layout::Page>
|
||||
|
||||
<EmberNotify @closeAfter={{4000}} as |message close|>
|
||||
|
||||
@@ -21,3 +21,5 @@ dev:
|
||||
menu-item: Menu item
|
||||
button-menu-item: Button menu item
|
||||
section: Section
|
||||
title: Title
|
||||
item-name: Item Name
|
||||
Reference in new issue
Block a user