Skip to content

Commit

Permalink
refactor: add action-icon (#436)
Browse files Browse the repository at this point in the history
* feat(action-icon): add new web-component

* refactor(conducting-equipment-editor): use action-icon (#417)

* refactor(conducting-equipment-editor): use action-icon

* fix(condicting-equpment-editor): add missing import statement

* refactor(ied-editor): use action-icon (#418)

* refactor(communication/connectedap-editor): use action-icon (#420)

* style(action-icon): make sure footer transform does not effect parent CSS (#419)

* fix(action-icon): make sure footer transform does not effect other CSS

* refactor(action-icon): improve styling

* refactor(action-icon): adjust action timing for header

* test(action-icon): adapt snapshots

* style(action-icon): minor changes

Co-authored-by: Jakob Vogelsang <jakob.vogelsang@omicronenergy.com>
Co-authored-by: Jakob Vogelsang <jakob-vogelsang@posteo.de>
  • Loading branch information
3 people authored Dec 15, 2021
1 parent 866b114 commit 8a5d569
Show file tree
Hide file tree
Showing 13 changed files with 563 additions and 511 deletions.
201 changes: 201 additions & 0 deletions src/action-icon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import {
css,
customElement,
html,
LitElement,
property,
TemplateResult,
} from 'lit-element';
import { nothing } from 'lit-html';

import '@material/mwc-icon';

/**
* A responsive container rendering actions in a header.
*
* The "action" slot may contain up to eight icon buttons.
* The "icon" slot, if filled overrides the icon property.
* The default slot will be rendered into the pane body in a single column.
*/
@customElement('action-icon')
export class ActionIcon extends LitElement {
/** caption text, displayed in the header */
@property({ type: String })
label?: string;
/** icon name, displayed unless the "icon" slot is filled */
@property({ type: String })
icon?: string;
/** color header with secondary theme color while focus is within */
@property({ type: Boolean })
secondary = false;
/** highlight pane with dotted outline */
@property({ type: Boolean })
highlighted = false;

async firstUpdated(): Promise<void> {
this.tabIndex = 0;
}

private renderIcon(): TemplateResult {
return html`<span>
<slot name="icon"
>${this.icon ? html`<mwc-icon>${this.icon}</mwc-icon>` : nothing}</slot
></span
> `;
}

render(): TemplateResult {
return html`<header>${this.label ?? nothing}</header>
<section>${this.renderIcon()}<slot name="action"></slot></section>
<footer>${this.label ?? nothing}</footer>`;
}

static styles = css`
:host {
display: flex;
flex-direction: column;
outline: none;
}
section {
align-self: center;
}
::slotted([slot='icon']),
mwc-icon {
display: block;
color: var(--mdc-theme-on-surface);
transition: transform 150ms linear, box-shadow 200ms linear;
outline-color: var(--mdc-theme-primary);
outline-style: solid;
margin: 0px;
outline-width: 0px;
width: 64px;
height: 64px;
--mdc-icon-size: 64px;
}
:host(:focus-within) ::slotted([slot='icon']),
:host(:focus-within) mwc-icon {
outline-style: solid;
outline-width: 4px;
transform: scale(0.8);
transition: all 250ms linear;
box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2);
}
:host([secondary]) ::slotted([slot='icon']),
:host([secondary]) mwc-icon {
outline-color: var(--mdc-theme-secondary);
}
:host([highlighted]) ::slotted([slot='icon']),
:host([highlighted]) mwc-icon {
outline-style: dotted;
outline-width: 2px;
}
::slotted([slot='icon']:hover),
mwc-icon:hover {
outline-style: dashed;
outline-width: 2px;
transition: transform 200ms linear, box-shadow 250ms linear;
}
::slotted([slot='action']) {
color: var(--mdc-theme-on-surface);
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 200ms linear;
position: absolute;
pointer-events: none;
z-index: 1;
opacity: 0;
margin-top: -56px;
margin-left: 8px;
}
:host(:focus-within) ::slotted([slot='action']) {
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 250ms linear;
pointer-events: auto;
opacity: 1;
}
:host(:focus-within) ::slotted([slot='action']:nth-of-type(1)) {
transform: translate(0px, -52px);
}
:host(:focus-within) ::slotted([slot='action']:nth-of-type(2)) {
transform: translate(0px, 52px);
}
:host(:focus-within) ::slotted([slot='action']:nth-of-type(3)) {
transform: translate(52px, 0px);
}
:host(:focus-within) ::slotted([slot='action']:nth-of-type(4)) {
transform: translate(-52px, 0px);
}
:host(:focus-within) ::slotted([slot='action']:nth-of-type(5)) {
transform: translate(52px, -52px);
}
:host(:focus-within) ::slotted([slot='action']:nth-of-type(6)) {
transform: translate(-52px, 52px);
}
:host(:focus-within) ::slotted([slot='action']:nth-of-type(7)) {
transform: translate(-52px, -52px);
}
:host(:focus-within) ::slotted([slot='action']:nth-of-type(8)) {
transform: translate(52px, 52px);
}
footer {
color: var(--mdc-theme-on-surface);
font-family: 'Roboto', sans-serif;
font-weight: 300;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin: 0px;
text-align: center;
align-self: center;
max-width: 64px;
direction: rtl;
}
header {
color: var(--mdc-theme-on-primary);
background-color: var(--mdc-theme-primary);
font-family: 'Roboto', sans-serif;
font-weight: 500;
font-size: 1.2em;
position: absolute;
text-align: center;
align-self: center;
max-width: 100vw;
padding: 4px 8px;
border-radius: 4px;
opacity: 0;
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 200ms linear;
}
:host(:hover) header {
position: absolute;
opacity: 1;
transform: translate(0, -40px);
box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2);
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 250ms linear;
}
:host(:focus-within) header {
position: absolute;
opacity: 1;
transform: translate(0, -80px);
box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2);
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 250ms linear;
}
`;
}
123 changes: 14 additions & 109 deletions src/editors/communication/connectedap-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
customElement,
html,
property,
css,
} from 'lit-element';
import { ifDefined } from 'lit-html/directives/if-defined';
import { translate, get } from 'lit-translate';
Expand All @@ -19,6 +18,7 @@ import { Checkbox } from '@material/mwc-checkbox';
import { List } from '@material/mwc-list';
import { ListItemBase } from '@material/mwc-list/mwc-list-item-base';

import '../../action-icon.js';
import '../../wizard-textfield.js';
import '../../filtered-list.js';
import {
Expand Down Expand Up @@ -276,15 +276,16 @@ function editConnectedApWizard(element: Element): Wizard {
/** [[`Communication`]] subeditor for a `ConnectedAP` element. */
@customElement('connectedap-editor')
export class ConnectedAPEditor extends LitElement {
@property()
/** SCL element ConnectedAP */
@property({ attribute: false })
element!: Element;

@property()
get apName(): string | null {
return this.element.getAttribute('apName') ?? null;
/** ConductingEquipment apName attribute */
@property({ type: String })
get apName(): string {
return this.element.getAttribute('apName') ?? 'UNDEFINED';
}

openEditWizard(): void {
private openEditWizard(): void {
this.dispatchEvent(newWizardEvent(editConnectedApWizard(this.element)));
}

Expand All @@ -303,116 +304,20 @@ export class ConnectedAPEditor extends LitElement {

render(): TemplateResult {
return html`
<div id="container" tabindex="0">
<mwc-icon class="fancy">settings_input_hdmi</mwc-icon>
<mwc-fab
<action-icon label="${this.apName}" icon="settings_input_hdmi"
><mwc-fab
slot="action"
mini
class="menu-item left"
icon="edit"
@click="${() => this.openEditWizard()}"
></mwc-fab>
<mwc-fab
slot="action"
mini
class="menu-item right"
icon="delete"
@click="${() => this.remove()}}"
></mwc-fab>
</div>
<h4>${this.apName}</h4>
></mwc-fab
></action-icon>
`;
}

static styles = css`
#container {
color: var(--mdc-theme-on-surface);
width: 64px;
height: 64px;
margin: auto;
position: relative;
transition: all 200ms linear;
}
#container:focus {
outline: none;
}
.fancy {
color: var(--mdc-theme-on-surface);
--mdc-icon-size: 64px;
transition: transform 150ms linear, box-shadow 200ms linear;
outline-color: var(--mdc-theme-primary);
outline-style: solid;
outline-width: 0px;
}
#container:focus > .fancy {
box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2);
}
#container:hover > .fancy {
outline: 2px dashed var(--mdc-theme-primary);
transition: transform 200ms linear, box-shadow 250ms linear;
}
#container:focus-within > .fancy {
outline: 2px solid var(--mdc-theme-primary);
background: var(--mdc-theme-on-primary);
transform: scale(0.8);
transition: transform 200ms linear, box-shadow 250ms linear;
}
.menu-item {
color: var(--mdc-theme-on-surface);
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 200ms linear;
position: absolute;
top: 8px;
left: 8px;
pointer-events: none;
z-index: 1;
opacity: 0;
}
#container:focus-within > .menu-item {
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 250ms linear;
pointer-events: auto;
opacity: 1;
}
#container:focus-within > .menu-item.up {
transform: translate(0px, -52px);
}
#container:focus-within > .menu-item.down {
transform: translate(0px, 52px);
}
#container:focus-within > .menu-item.right {
transform: translate(52px, 0px);
}
#container:focus-within > .menu-item.left {
transform: translate(-52px, 0px);
}
h4 {
color: var(--mdc-theme-on-surface);
font-family: 'Roboto', sans-serif;
font-weight: 300;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin: 0px;
opacity: 1;
transition: opacity 200ms linear;
text-align: center;
}
:host(.moving) #container,
:host(.moving) h4 {
opacity: 0.3;
}
`;
}
Loading

0 comments on commit 8a5d569

Please sign in to comment.