Merge branch 'develop' into ICU-179-tab-component
This commit is contained in:
35 files changed
+593
-258
No files matched your search
@@ -0,0 +1,11 @@
|
||||
import Component from '@ember/component';
|
||||
import layout from '../../../templates/components/rose/nav/sidebar';
|
||||
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/Sidebar" component="Nav/Sidebar" />
|
||||
|
||||
# Sidebar Navigation
|
||||
|
||||
A simple navigation component intended for use in the sidebar layout region.
|
||||
|
||||
<Preview>
|
||||
<Story name="Basic Sidebar Nav" height="8rem">{{
|
||||
template: hbs`
|
||||
<Rose::Nav::Sidebar @title={{title}} as |nav|>
|
||||
<nav.link @route="index" class="active">Item Name</nav.link>
|
||||
<nav.link @route="index">Item Name</nav.link>
|
||||
</Rose::Nav::Sidebar>
|
||||
`,
|
||||
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::Sidebar @title="Title" as |nav|>
|
||||
<nav.link @route="index">Item Name</nav.link>
|
||||
<nav.link @route="about">Item Name</nav.link>
|
||||
</Rose::Nav::Sidebar>
|
||||
```
|
||||
@@ -20,8 +20,9 @@ export default Component.extend({
|
||||
get icon() {
|
||||
let icon = 'info-circle-fill';
|
||||
|
||||
switch (this.style) {
|
||||
case 'failure':
|
||||
|
||||
switch(this.style) {
|
||||
case 'error':
|
||||
icon = 'cancel-square-fill';
|
||||
break;
|
||||
case 'success':
|
||||
|
||||
@@ -8,7 +8,7 @@ import { text, boolean, select } from '@storybook/addon-knobs';
|
||||
# Notification
|
||||
|
||||
Notifications come in four semantic styles: `info` (default), `success`,
|
||||
`warning`, and `failure`. Heading text is required. Additional block content
|
||||
`warning`, and `error`. Heading text is required. Additional block content
|
||||
is optional.
|
||||
|
||||
Notifications may be made dismissible by passing a `@dismiss` function into
|
||||
@@ -69,7 +69,7 @@ handler takes appropriate action and hides the notification.
|
||||
Careful now.
|
||||
</Rose::Notification>
|
||||
<Rose::Notification
|
||||
@style="failure"
|
||||
@style="error"
|
||||
@heading="Error"
|
||||
@dismiss={{dismiss}}
|
||||
@dismissText="Dismiss"
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
@import 'notification';
|
||||
@import 'card';
|
||||
@import 'tab';
|
||||
@import 'nav';
|
||||
@@ -82,7 +82,7 @@
|
||||
color: var(--header-color);
|
||||
}
|
||||
|
||||
&.is-failure {
|
||||
&.is-error {
|
||||
--icon-color: var(--failure);
|
||||
--header-color: var(--failure);
|
||||
--border-color: var(--failure-subtler-1);
|
||||
|
||||
@@ -24,8 +24,13 @@
|
||||
}
|
||||
|
||||
&:hover {
|
||||
$s: sizing.rems(s); // 12
|
||||
$xs: sizing.rems(xs); // 8
|
||||
$xxs: sizing.rems(xxs); // 4
|
||||
border-color: var(--ui-gray);
|
||||
background-color: var(--ui-gray-subtler-5);
|
||||
box-shadow: 0 $xs $s rgba(var(--stark-components), var(--opacity-3)),
|
||||
0 $xxs $xxs rgba(var(--stark-components), var(--opacity-4));
|
||||
}
|
||||
|
||||
&:active {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@use '../../utilities/type';
|
||||
|
||||
.rose-form-input {
|
||||
margin-bottom: sizing.rems(l);
|
||||
margin-bottom: sizing.rems(m);
|
||||
|
||||
.rose-form-input-label {
|
||||
@include type.type(s, semibold);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@use '../../utilities/type';
|
||||
|
||||
.rose-form-select {
|
||||
margin-bottom: sizing.rems(l);
|
||||
margin-bottom: sizing.rems(m);
|
||||
|
||||
.rose-form-select-label {
|
||||
@include type.type(s, semibold);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
.rose-header-brand-text {
|
||||
@include type.type(m, normal);
|
||||
margin: 0;
|
||||
margin-left: sizing.rems(s);
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
top: -1000px;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@use '../../variables/sizing';
|
||||
@use '../../variables/media';
|
||||
|
||||
@import 'tabs';
|
||||
@@ -8,7 +9,7 @@
|
||||
'header header header header'
|
||||
'sidebar main main main';
|
||||
// Define static grid column for sidebar
|
||||
grid-template-columns: 12rem auto 1fr;
|
||||
grid-template-columns: 16rem auto 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
height: 100vh;
|
||||
}
|
||||
@@ -23,6 +24,7 @@
|
||||
|
||||
.rose-layout-sidebar {
|
||||
grid-area: sidebar;
|
||||
border-right: sizing.rems(xxxxs) solid var(--ui-border-subtler-1);
|
||||
}
|
||||
|
||||
@media (max-width: media.width(small)) {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
@import "sidebar";
|
||||
@@ -0,0 +1,40 @@
|
||||
@use '../../variables/sizing';
|
||||
@use '../../utilities/type';
|
||||
|
||||
.rose-nav-sidebar {
|
||||
$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-sidebar"
|
||||
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/sidebar';
|
||||
@@ -1,190 +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::Sidebar @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::Sidebar>
|
||||
</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" />
|
||||
|
||||
Dummy app index template
|
||||
<h2>Button</h2>
|
||||
<Rose::Button @style="primary">Primary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="primary" @disabled={{true}}>Primary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<Rose::Notification
|
||||
@style="failure"
|
||||
@heading="Error"
|
||||
@dismiss={{this.actionHandler}}
|
||||
@dismissText="Dismiss"
|
||||
>
|
||||
An error occurred.
|
||||
</Rose::Notification>
|
||||
<Rose::Button @style="secondary">Secondary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="secondary" @disabled={{true}}>Secondary</Rose::Button>
|
||||
<br>
|
||||
|
||||
<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>Form</h2>
|
||||
<Rose::Form
|
||||
@onSubmit={{this.actionHandler}}
|
||||
@cancel={{this.actionHandler}}
|
||||
@disabled={{false}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<h2>Button</h2>
|
||||
<Rose::Button @style="primary">Primary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="primary" @disabled={{true}}>Primary</Rose::Button>
|
||||
<br>
|
||||
<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}}
|
||||
/>
|
||||
|
||||
<Rose::Button @style="secondary">Secondary</Rose::Button>
|
||||
<br>
|
||||
<Rose::Button @style="secondary" @disabled={{true}}>Secondary</Rose::Button>
|
||||
<br>
|
||||
<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}}
|
||||
/>
|
||||
|
||||
<h2>Form</h2>
|
||||
<Rose::Form
|
||||
@onSubmit={{this.actionHandler}}
|
||||
@cancel={{this.actionHandler}}
|
||||
@disabled={{false}}
|
||||
as |form|
|
||||
>
|
||||
<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
|
||||
|
||||
<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>
|
||||
@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>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}}
|
||||
/>
|
||||
<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>
|
||||
<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::Layout::Tabs>
|
||||
<Rose::Tab @title="Text" @badge="3" @icon="info-circle-outline" />
|
||||
</Rose::Layout::Tabs>
|
||||
<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,33 @@
|
||||
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/sidebar', function(hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
test('it renders', async function(assert) {
|
||||
assert.expect(2)
|
||||
await render(hbs`
|
||||
<Rose::Nav::Sidebar @title="Title" as |nav|>
|
||||
<nav.link @route="index">Item Name</nav.link>
|
||||
</Rose::Nav::Sidebar>
|
||||
`);
|
||||
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::Sidebar @title="Title" as |nav|>
|
||||
<nav.link @route="index">Item Name</nav.link>
|
||||
</Rose::Nav::Sidebar>
|
||||
`);
|
||||
const el = find('.rose-nav-sidebar');
|
||||
const id = el.id;
|
||||
const titleId = `title-${id}`;
|
||||
assert.equal(find('.rose-nav-title').id, titleId);
|
||||
assert.equal(el.getAttribute('aria-labelledby').trim(), titleId);
|
||||
});
|
||||
});
|
||||
@@ -1,44 +1,30 @@
|
||||
<form
|
||||
...attributes
|
||||
novalidate
|
||||
method="post"
|
||||
{{on "submit" @submit}}>
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
as |form|
|
||||
>
|
||||
|
||||
<Rose::Form::Input
|
||||
<form.input
|
||||
name="name"
|
||||
@type="name"
|
||||
@value={{@model.name}}
|
||||
@label={{t "form.label.name"}}
|
||||
@error={{false}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
readonly={{false}} />
|
||||
|
||||
<Rose::Form::Textarea
|
||||
<form.textarea
|
||||
name="description"
|
||||
@type="description"
|
||||
@value={{@model.description}}
|
||||
@label={{t "form.label.description"}}
|
||||
@error={{false}}
|
||||
disabled={{@model.isSaving}}
|
||||
readonly={{false}}
|
||||
/>
|
||||
readonly={{false}} />
|
||||
|
||||
<section class="form-actions">
|
||||
<Rose::Button
|
||||
@disabled={{@model.cannotSave}}
|
||||
@submit={{true}}
|
||||
@style="primary"
|
||||
>
|
||||
{{t 'actions.save'}}
|
||||
</Rose::Button>
|
||||
<form.actions
|
||||
@disabled={{if @model.cannotSave @model.cannotSave}}
|
||||
@submitText={{t "actions.save"}}
|
||||
@cancelText={{t "actions.cancel"}} />
|
||||
|
||||
<Rose::Button
|
||||
@disabled={{@model.cannotSave}}
|
||||
@style="secondary"
|
||||
{{on "click" @cancel}}
|
||||
>
|
||||
{{t 'actions.cancel'}}
|
||||
</Rose::Button>
|
||||
</section>
|
||||
</form>
|
||||
</Rose::Form>
|
||||
@@ -1,9 +1,3 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default class OrgsOrgProjectsIndexRoute extends Route {
|
||||
@action
|
||||
new() {
|
||||
this.transitionTo('orgs.org.projects.new');
|
||||
}
|
||||
}
|
||||
export default class OrgsOrgProjectsIndexRoute extends Route {}
|
||||
@@ -1,7 +1,12 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
|
||||
export default class OrgsOrgProjectsNewRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service notify;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
@@ -31,15 +36,15 @@ export default class OrgsOrgProjectsNewRoute extends Route {
|
||||
* @param {Event} e
|
||||
*/
|
||||
@action
|
||||
async save(project, e) {
|
||||
// Prevent default behavior, since this was trigger from a form submission.
|
||||
e.preventDefault();
|
||||
async save(project) {
|
||||
try {
|
||||
await project.save();
|
||||
this.transitionTo('orgs.org.projects.project', project);
|
||||
// TODO: replace with translated strings
|
||||
this.notify.success('Project created.');
|
||||
} catch (e) {
|
||||
// TODO: error handling
|
||||
throw e;
|
||||
// TODO: replace with translated strings
|
||||
this.notify.error('Project could not be created.', {closeAfter: null});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ export default class OrgsOrgProjectsProjectRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service scope;
|
||||
@service notify;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -44,14 +45,14 @@ export default class OrgsOrgProjectsProjectRoute extends Route {
|
||||
* @param {Event} e
|
||||
*/
|
||||
@action
|
||||
async save(project, e) {
|
||||
// Prevent default behavior, since this was trigger from a form submission.
|
||||
e.preventDefault();
|
||||
async save(project) {
|
||||
try {
|
||||
await project.save();
|
||||
// TODO: replace with translated strings
|
||||
this.notify.success('Save succeeded.');
|
||||
} catch (e) {
|
||||
// TODO: error handling
|
||||
throw e;
|
||||
// TODO: replace with translated strings
|
||||
this.notify.error('An error occurred.', {closeAfter: null});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,9 +65,11 @@ export default class OrgsOrgProjectsProjectRoute extends Route {
|
||||
try {
|
||||
await project.destroyRecord();
|
||||
this.transitionTo('orgs.org.projects');
|
||||
// TODO: replace with translated strings
|
||||
this.notify.success('Deleted project succesfully.');
|
||||
} catch (e) {
|
||||
// TODO: error handling
|
||||
throw e;
|
||||
// TODO: replace with translated strings
|
||||
this.notify.error('An error occurred.', {closeAfter: null});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* This file is essentially a rip of the default ember notify styles, with some
|
||||
* minor tweaks for positioning.
|
||||
*/
|
||||
|
||||
@-webkit-keyframes "ember-notify-show" {
|
||||
from {
|
||||
left: -310px;
|
||||
}
|
||||
to {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
@keyframes "ember-notify-show" {
|
||||
from {
|
||||
left: -310px;
|
||||
}
|
||||
to {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes "ember-notify-hide" {
|
||||
from {
|
||||
left: 0;
|
||||
}
|
||||
to {
|
||||
left: -310px;
|
||||
}
|
||||
}
|
||||
@keyframes "ember-notify-hide" {
|
||||
from {
|
||||
left: 0;
|
||||
}
|
||||
to {
|
||||
left: -310px;
|
||||
}
|
||||
}
|
||||
.ember-notify-cn {
|
||||
position: fixed;
|
||||
z-index: 5000;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
.ember-notify {
|
||||
display: block;
|
||||
margin: 10px;
|
||||
position: relative;
|
||||
width: 300px;
|
||||
box-sizing: border-box;
|
||||
//border: 1px solid #ccc;
|
||||
//padding: 10px;
|
||||
.close {
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.ember-notify-show {
|
||||
-webkit-animation-duration: 500ms;
|
||||
animation-duration: 500ms;
|
||||
-webkit-animation-name: ember-notify-show;
|
||||
animation-name: ember-notify-show;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
.ember-notify-hide {
|
||||
-webkit-animation-duration: 250ms;
|
||||
animation-duration: 250ms;
|
||||
-webkit-animation-name: ember-notify-hide;
|
||||
animation-name: ember-notify-hide;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045);
|
||||
animation-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045);
|
||||
&:hover {
|
||||
-webkit-animation-play-state: paused;
|
||||
-moz-animation-play-state: paused;
|
||||
-o-animation-play-state: paused;
|
||||
animation-play-state: paused;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 680px) {
|
||||
.ember-notify-cn {
|
||||
width: 100%;
|
||||
padding-left: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ember-notify {
|
||||
width: 100%;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
+22
-18
@@ -1,7 +1,26 @@
|
||||
@use 'rose/variables/sizing';
|
||||
|
||||
@import 'rose';
|
||||
@import 'notify';
|
||||
|
||||
.rose-nav-sidebar {
|
||||
margin-top: sizing.rems(xxl);
|
||||
}
|
||||
|
||||
.rose-form {
|
||||
width: 66%;
|
||||
|
||||
.rose-form-input {
|
||||
width: 100%;
|
||||
|
||||
.rose-form-input-field {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.projects-overview {
|
||||
margin: 0 10px;
|
||||
margin: sizing.rems(l);
|
||||
|
||||
.projects {
|
||||
display: flex;
|
||||
@@ -17,25 +36,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.project-new-link {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
padding: 10px;
|
||||
color: #ffffff;
|
||||
text-shadow: 0px 1px 1px rgba(0, 0, 0, 0.25);
|
||||
background: #1563ff;
|
||||
border: 1px solid #082766;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
|
||||
border-radius: 2px;
|
||||
position: relative;
|
||||
float: right;
|
||||
top: -50px;
|
||||
}
|
||||
|
||||
.project-overview,
|
||||
.project-new {
|
||||
margin: 0 10px;
|
||||
margin: sizing.rems(l);
|
||||
|
||||
.breadcrumbs,
|
||||
.breadcrumbs a {
|
||||
color: #6f7682;
|
||||
|
||||
@@ -1,14 +1,53 @@
|
||||
<HeadLayout />
|
||||
|
||||
{{title (app-name)}}
|
||||
|
||||
<Rose::Layout::Page as |page|>
|
||||
<page.header>
|
||||
<Rose::Header as |header|>
|
||||
<header.brand @logo="logo" @text={{app-name}} />
|
||||
<header.brand @logo="logo-hashi" @text={{app-name}} />
|
||||
<header.nav as |nav|>
|
||||
<nav.dropdown @text={{t 'dev.default-org'}} as |dropdown|>
|
||||
<dropdown.link @route="index">{{t 'dev.menu-item'}}</dropdown.link>
|
||||
<dropdown.link @route="orgs">{{t 'dev.menu-item'}}</dropdown.link>
|
||||
<dropdown.button>{{t 'dev.button-menu-item'}}</dropdown.button>
|
||||
</nav.dropdown>
|
||||
<nav.link @route="index">{{t 'dev.section'}}</nav.link>
|
||||
<nav.link @route="index">{{t 'dev.section'}}</nav.link>
|
||||
</header.nav>
|
||||
<header.utilities as |utilities|>
|
||||
<utilities.dropdown
|
||||
@text="user@example.net"
|
||||
@iconOnly={{true}}
|
||||
@icon="user-square-fill" as |dropdown|
|
||||
>
|
||||
<dropdown.link @route="index">{{t 'dev.menu-item'}}</dropdown.link>
|
||||
<dropdown.button>{{t 'dev.button-menu-item'}}</dropdown.button>
|
||||
</utilities.dropdown>
|
||||
</header.utilities>
|
||||
</Rose::Header>
|
||||
</page.header>
|
||||
|
||||
<page.main>
|
||||
{{title (app-name)}}
|
||||
{{outlet}}
|
||||
</page.main>
|
||||
|
||||
<page.sidebar />
|
||||
<page.sidebar>
|
||||
<Rose::Nav::Sidebar @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>
|
||||
</Rose::Nav::Sidebar>
|
||||
</page.sidebar>
|
||||
|
||||
</Rose::Layout::Page>
|
||||
|
||||
<EmberNotify @closeAfter={{4000}} as |message close|>
|
||||
<Rose::Notification
|
||||
@style={{message.type}}
|
||||
@heading={{t (concat 'states.' message.type)}}
|
||||
@dismiss={{close}}
|
||||
@dismissText={{t 'actions.dismiss'}}
|
||||
>
|
||||
{{message.text}}
|
||||
</Rose::Notification>
|
||||
</EmberNotify>
|
||||
@@ -1 +1,3 @@
|
||||
{{title (t "resources.projects")}}
|
||||
|
||||
{{outlet}}
|
||||
@@ -1,13 +1,11 @@
|
||||
<div class="projects-overview">
|
||||
|
||||
<h2>{{t "resources.projects"}}</h2>
|
||||
<Rose::Button
|
||||
class="project-new-link"
|
||||
@style="primary"
|
||||
@iconLeft="plus-plain"
|
||||
{{on "click" (route-action "new")}}
|
||||
>
|
||||
{{t 'titles.new'}}
|
||||
</Rose::Button>
|
||||
|
||||
<LinkTo @route="orgs.org.projects.new">
|
||||
<Rose::Icon @name="plus-circle-outline" @size="medium" />
|
||||
{{t "titles.new"}}
|
||||
</LinkTo>
|
||||
|
||||
<ul class="projects">
|
||||
{{#each @model as |project|}}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
{{title (t "titles.new")}}
|
||||
|
||||
<div class="project-new">
|
||||
<div class="breadcrumbs">
|
||||
<LinkTo @route='orgs.org.projects'>{{t "resources.projects"}}</LinkTo>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
{{title @model.name}}
|
||||
|
||||
<div class="project-overview">
|
||||
<div class="breadcrumbs">
|
||||
<LinkTo @route='orgs.org.projects'>{{t "resources.projects"}}</LinkTo>
|
||||
|
||||
@@ -41,7 +41,7 @@ module.exports = function (environment) {
|
||||
'frame-src': ["'self'"],
|
||||
'font-src': ["'self'"],
|
||||
'connect-src': ["'self'"],
|
||||
'img-src': ["'self'"],
|
||||
'img-src': ["'self'", "data:"],
|
||||
'style-src': ["'self'"],
|
||||
'media-src': ["'self'"],
|
||||
'manifest-src': ["'self'"],
|
||||
|
||||
@@ -15,6 +15,9 @@ module.exports = function (defaults) {
|
||||
onlyIncluded: true,
|
||||
extension: 'scss',
|
||||
},
|
||||
emberNotify: {
|
||||
importCss: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Use `app.import` to add additional libraries to the generated
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
"ember-intl": "^5.1.1",
|
||||
"ember-load-initializers": "^2.1.1",
|
||||
"ember-maybe-import-regenerator": "^0.1.6",
|
||||
"ember-modifier": "^1.0.3",
|
||||
"ember-notify": "^6.0.0",
|
||||
"ember-page-title": "^5.2.1",
|
||||
"ember-qunit": "^4.6.0",
|
||||
"ember-resolver": "^7.0.0",
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<svg
|
||||
width="30"
|
||||
height="30"
|
||||
viewBox="0 0 30 30"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g id="logomark">
|
||||
<path
|
||||
d="M0 7.19579L11.4553 0.58728V5.55192L4.30398 9.68052V25.5537L0 23.069V7.19579Z"
|
||||
fill="currentColor">
|
||||
</path>
|
||||
|
||||
<path
|
||||
d="M16.0285 0.58728V13.2291H11.4553V8.51084L7.15165 10.9956V27.1919L11.4553 29.6829V17.0771H16.0285V21.7641L20.3321 19.2788V3.07229L16.0285 0.58728Z"
|
||||
fill="currentColor">
|
||||
</path>
|
||||
|
||||
<path
|
||||
d="M27.4838 23.0789L16.0285 29.6875V24.7228L23.1798 20.5939V4.72074L27.4838 7.20576V23.0789Z"
|
||||
fill="currentColor">
|
||||
</path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 633 B |
@@ -1,12 +1,25 @@
|
||||
actions:
|
||||
cancel: Cancel
|
||||
delete: Delete
|
||||
dismiss: Dismiss
|
||||
save: Save
|
||||
resources:
|
||||
projects: Projects
|
||||
titles:
|
||||
new: New
|
||||
states:
|
||||
info: Info
|
||||
success: Success
|
||||
warning: Warning
|
||||
error: Error
|
||||
form:
|
||||
label:
|
||||
name: Name
|
||||
description: Description
|
||||
dev:
|
||||
default-org: Default Org
|
||||
menu-item: Menu item
|
||||
button-menu-item: Button menu item
|
||||
section: Section
|
||||
title: Title
|
||||
item-name: Item Name
|
||||
@@ -7815,6 +7815,14 @@ ember-modifier@^1.0.3:
|
||||
ember-cli-string-utils "^1.1.0"
|
||||
ember-modifier-manager-polyfill "^1.2.0"
|
||||
|
||||
ember-notify@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ember-notify/-/ember-notify-6.0.0.tgz#f92978e3452934f7c9b70d76ad2ec62bf072495a"
|
||||
integrity sha512-2ewX5xwkGyZtkRRlgT/Tam5PaxGy78IoXltwt4s8roEam1esXNHfafzycvJwcuX7Hgrwr7LlTpmKP+81vWT3QQ==
|
||||
dependencies:
|
||||
ember-cli-babel "^7.7.3"
|
||||
ember-cli-htmlbars "^3.0.1"
|
||||
|
||||
ember-page-title@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ember-page-title/-/ember-page-title-5.2.1.tgz#12261e010bec96af6200cd132fe4068e717ccbec"
|
||||
|
||||
Reference in new issue
Block a user