split sections and tools from header element

This commit is contained in:
Mads Rasmussen
2022-05-31 10:41:29 +02:00
parent 33f194db39
commit cf12e684a9
4 changed files with 255 additions and 212 deletions

View File

@@ -0,0 +1,199 @@
import { Subscription } from 'rxjs';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, CSSResultGroup, html, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { when } from 'lit/directives/when.js';
import { getUserSections } from '../core/api/fetcher';
import { UmbExtensionManifest } from '../core/extension';
import { UmbRouteLocation, UmbRouter } from '../core/router';
import { UmbSectionContext } from '../section.context';
import { UmbContextConsumerMixin } from '../core/context';
@customElement('umb-backoffice-header-sections')
export class UmbBackofficeHeaderSections extends UmbContextConsumerMixin(LitElement) {
static styles: CSSResultGroup = [
UUITextStyles,
css`
#tabs {
color: var(--uui-look-primary-contrast);
height: 60px;
font-size: 16px;
--uui-tab-text: var(--uui-look-primary-contrast);
--uui-tab-text-hover: var(--uui-look-primary-contrast-hover);
--uui-tab-text-active: var(--uui-interface-active);
--uui-tab-background: var(--uui-look-primary-surface);
}
#dropdown {
background-color: white;
border-radius: var(--uui-border-radius);
width: 100%;
height: 100%;
box-sizing: border-box;
box-shadow: var(--uui-shadow-depth-3);
min-width: 200px;
color: black; /* Change to variable */
}
`,
];
@state()
private _open = false;
@state()
private _allowedSection: Array<string> = [];
@state()
private _sections: Array<UmbExtensionManifest> = [];
@state()
private _visibleSections: Array<UmbExtensionManifest> = [];
@state()
private _extraSections: Array<UmbExtensionManifest> = [];
@state()
private _currentSectionAlias = '';
private _router?: UmbRouter;
private _sectionContext?: UmbSectionContext;
private _sectionSubscription?: Subscription;
private _currentSectionSubscription?: Subscription;
private _locationSubscription?: Subscription;
private _location? : UmbRouteLocation;
constructor () {
super();
this.consumeContext('umbRouter', (_instance: UmbRouter) => {
this._router = _instance;
this._useLocation();
});
this.consumeContext('umbSectionContext', (_instance: UmbSectionContext) => {
this._sectionContext = _instance;
this._useCurrentSection();
this._useSections();
});
}
private _handleMore(e: MouseEvent) {
e.stopPropagation();
this._open = !this._open;
}
private _handleTabClick(e: PointerEvent, section: UmbExtensionManifest) {
const tab = e.currentTarget as any;
// TODO: we need to be able to prevent the tab from setting the active state
if (tab.id === 'moreTab') {
return;
}
// TODO: this could maybe be handled by an anchor tag
this._router?.push(`/section/${section.meta.pathname}`);
this._sectionContext?.setCurrent(section.alias);
}
private _handleLabelClick(e: PointerEvent) {
const label = (e.target as any).label;
// TODO: set current section
//this._sectionContext?.setCurrent(section.alias);
const moreTab = this.shadowRoot?.getElementById('moreTab');
moreTab?.setAttribute('active', 'true');
this._open = false;
}
private _useLocation () {
this._locationSubscription?.unsubscribe();
this._locationSubscription = this._router?.location
.subscribe((location: UmbRouteLocation) => {
this._location = location;
});
}
private _useCurrentSection () {
this._currentSectionSubscription?.unsubscribe();
this._currentSectionSubscription = this._sectionContext?.getCurrent()
.subscribe(section => {
this._currentSectionAlias = section.alias;
});
}
private async _useSections() {
this._sectionSubscription?.unsubscribe();
const { data } = await getUserSections({});
this._allowedSection = data.sections;
this._sectionSubscription = this._sectionContext?.getSections()
.subscribe((sectionExtensions: any) => {
this._sections = sectionExtensions.filter((section: any) => this._allowedSection.includes(section.alias));
this._visibleSections = this._sections;
const currentSectionAlias = this._sections.find(section => section.meta.pathname === this._location?.params?.section)?.alias;
if (!currentSectionAlias) return;
this._sectionContext?.setCurrent(currentSectionAlias);
});
}
disconnectedCallback(): void {
super.disconnectedCallback();
this._locationSubscription?.unsubscribe();
this._sectionSubscription?.unsubscribe();
this._currentSectionSubscription?.unsubscribe();
}
render() {
return html`
<uui-tab-group id="tabs">
${this._visibleSections.map(
(section) => html`
<uui-tab
?active="${this._currentSectionAlias === section.alias}"
label="${section.name}"
@click="${(e: PointerEvent) => this._handleTabClick(e, section)}"></uui-tab>
`
)}
${this._renderExtraSections()}
</uui-tab-group>
`;
}
private _renderExtraSections() {
return when(
this._extraSections.length > 0,
() => html`
<uui-tab id="moreTab" @click="${this._handleTabClick}">
<uui-popover .open=${this._open} placement="bottom-start" @close="${() => (this._open = false)}">
<uui-button slot="trigger" look="primary" label="More" @click="${this._handleMore}" compact>
<uui-symbol-more></uui-symbol-more>
</uui-button>
<div slot="popover" id="dropdown">
${this._extraSections.map(
(section) => html`
<uui-menu-item
?active="${this._currentSectionAlias === section.alias}"
label="${section.name}"
@click-label="${this._handleLabelClick}"></uui-menu-item>
`
)}
</div>
</uui-popover>
</uui-tab>
`
);
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-backoffice-header-sections': UmbBackofficeHeaderSections;
}
}

View File

@@ -0,0 +1,44 @@
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, CSSResultGroup, html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
@customElement('umb-backoffice-header-tools')
export class UmbBackofficeHeaderTools extends LitElement {
static styles: CSSResultGroup = [
UUITextStyles,
css`
#tools {
display: flex;
align-items: center;
gap: var(--uui-size-space-2);
}
.tool {
font-size: 18px;
}
`,
];
render() {
return html`
<div id="tools">
<uui-button class="tool" look="primary" label="Search" compact>
<uui-icon name="search"></uui-icon>
</uui-button>
<uui-button class="tool" look="primary" label="Help" compact>
<uui-icon name="favorite"></uui-icon>
</uui-button>
<uui-button look="primary" style="font-size: 14px;" label="User" compact>
<uui-avatar name="Mads Rasmussen"></uui-avatar>
</uui-button>
</div>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-backoffice-header-tools': UmbBackofficeHeaderTools;
}
}

View File

@@ -1,25 +1,19 @@
import { Subscription } from 'rxjs';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, CSSResultGroup, html, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { when } from 'lit/directives/when.js';
import { getUserSections } from '../core/api/fetcher';
import { UmbExtensionManifest, UmbManifestSectionMeta } from '../core/extension';
import { UmbRouteLocation, UmbRouter } from '../core/router';
import { UmbSectionContext } from '../section.context';
import { UmbContextConsumerMixin } from '../core/context';
// TODO: umb or not umb in file name?
import { customElement } from 'lit/decorators.js';
import './backoffice-header-sections.element';
import './backoffice-header-tools.element';
@customElement('umb-backoffice-header')
export class UmbBackofficeHeader extends UmbContextConsumerMixin(LitElement) {
export class UmbBackofficeHeader extends LitElement {
static styles: CSSResultGroup = [
UUITextStyles,
css`
:host {
width: 100%;
}
#appHeader {
background-color: var(--uui-look-primary-surface);
display: flex;
@@ -41,181 +35,10 @@ export class UmbBackofficeHeader extends UmbContextConsumerMixin(LitElement) {
#sections {
flex: 1 1 auto;
display: flex;
align-items: center;
gap: var(--uui-size-space-2);
}
#tabs {
color: var(--uui-look-primary-contrast);
height: 60px;
font-size: 16px;
--uui-tab-text: var(--uui-look-primary-contrast);
--uui-tab-text-hover: var(--uui-look-primary-contrast-hover);
--uui-tab-text-active: var(--uui-interface-active);
--uui-tab-background: var(--uui-look-primary-surface);
}
#tools {
display: flex;
align-items: center;
gap: var(--uui-size-space-2);
}
.tool {
font-size: 18px;
}
#dropdown {
background-color: white;
border-radius: var(--uui-border-radius);
width: 100%;
height: 100%;
box-sizing: border-box;
box-shadow: var(--uui-shadow-depth-3);
min-width: 200px;
color: black; /* Change to variable */
}
`,
];
@state()
private _open = false;
@state()
private _allowedSection: Array<string> = [];
@state()
private _sections: Array<UmbExtensionManifest> = [];
@state()
private _visibleSections: Array<UmbExtensionManifest> = [];
@state()
private _extraSections: Array<UmbExtensionManifest> = [];
@state()
private _currentSectionAlias = '';
private _router?: UmbRouter;
private _sectionContext?: UmbSectionContext;
private _sectionSubscription?: Subscription;
private _currentSectionSubscription?: Subscription;
private _locationSubscription?: Subscription;
private _location? : UmbRouteLocation;
constructor () {
super();
this.consumeContext('umbRouter', (_instance: UmbRouter) => {
this._router = _instance;
this._useLocation();
});
this.consumeContext('umbSectionContext', (_instance: UmbSectionContext) => {
this._sectionContext = _instance;
this._useCurrentSection();
this._useSections();
});
}
private _handleMore(e: MouseEvent) {
e.stopPropagation();
this._open = !this._open;
}
private _handleTabClick(e: PointerEvent, section: UmbExtensionManifest) {
const tab = e.currentTarget as any;
// TODO: we need to be able to prevent the tab from setting the active state
if (tab.id === 'moreTab') {
return;
}
// TODO: this could maybe be handled by an anchor tag
this._router?.push(`/section/${section.meta.pathname}`);
this._sectionContext?.setCurrent(section.alias);
}
private _handleLabelClick(e: PointerEvent) {
const label = (e.target as any).label;
// TODO: set current section
//this._sectionContext?.setCurrent(section.alias);
const moreTab = this.shadowRoot?.getElementById('moreTab');
moreTab?.setAttribute('active', 'true');
this._open = false;
}
private _useLocation () {
this._locationSubscription?.unsubscribe();
this._locationSubscription = this._router?.location
.subscribe((location: UmbRouteLocation) => {
this._location = location;
});
}
private _useCurrentSection () {
this._currentSectionSubscription?.unsubscribe();
this._currentSectionSubscription = this._sectionContext?.getCurrent()
.subscribe(section => {
this._currentSectionAlias = section.alias;
});
}
private async _useSections() {
this._sectionSubscription?.unsubscribe();
const { data } = await getUserSections({});
this._allowedSection = data.sections;
this._sectionSubscription = this._sectionContext?.getSections()
.subscribe((sectionExtensions: any) => {
this._sections = sectionExtensions.filter((section: any) => this._allowedSection.includes(section.alias));
this._visibleSections = this._sections;
const currentSectionAlias = this._sections.find(section => section.meta.pathname === this._location?.params?.section)?.alias;
if (!currentSectionAlias) return;
this._sectionContext?.setCurrent(currentSectionAlias);
});
}
disconnectedCallback(): void {
super.disconnectedCallback();
this._locationSubscription?.unsubscribe();
this._sectionSubscription?.unsubscribe();
this._currentSectionSubscription?.unsubscribe();
}
private _renderExtraSections() {
return when(
this._extraSections.length > 0,
() => html`
<uui-tab id="moreTab" @click="${this._handleTabClick}">
<uui-popover .open=${this._open} placement="bottom-start" @close="${() => (this._open = false)}">
<uui-button slot="trigger" look="primary" label="More" @click="${this._handleMore}" compact>
<uui-symbol-more></uui-symbol-more>
</uui-button>
<div slot="popover" id="dropdown">
${this._extraSections.map(
(section) => html`
<uui-menu-item
?active="${this._currentSectionAlias === section.alias}"
label="${section.name}"
@click-label="${this._handleLabelClick}"></uui-menu-item>
`
)}
</div>
</uui-popover>
</uui-tab>
`
);
}
render() {
return html`
<div id="appHeader">
@@ -223,31 +46,8 @@ export class UmbBackofficeHeader extends UmbContextConsumerMixin(LitElement) {
<img src="/umbraco_logomark_white.svg" alt="Umbraco" />
</uui-button>
<div id="sections">
<uui-tab-group id="tabs">
${this._visibleSections.map(
(section) => html`
<uui-tab
?active="${this._currentSectionAlias === section.alias}"
label="${section.name}"
@click="${(e: PointerEvent) => this._handleTabClick(e, section)}"></uui-tab>
`
)}
${this._renderExtraSections()}
</uui-tab-group>
</div>
<div id="tools">
<uui-button class="tool" look="primary" label="Search" compact>
<uui-icon name="search"></uui-icon>
</uui-button>
<uui-button class="tool" look="primary" label="Help" compact>
<uui-icon name="favorite"></uui-icon>
</uui-button>
<uui-button look="primary" style="font-size: 14px;" label="User" compact>
<uui-avatar name="Mads Rasmussen"></uui-avatar>
</uui-button>
</div>
<umb-backoffice-header-sections id="sections"></umb-backoffice-header-sections>
<umb-backoffice-header-tools></umb-backoffice-header-tools>
</div>
`;
}

View File

@@ -1,11 +1,11 @@
import './backoffice-header.element';
import './backoffice-sidebar.element';
import './backoffice-main.element';
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, html, LitElement } from 'lit';
import './backoffice-header.element';
import './backoffice-sidebar.element';
import './backoffice-main.element';
@defineElement('umb-backoffice')
export class UmbBackoffice extends LitElement {
static styles = [