web/admin: rewrite sidebar to use full components, switch to categories

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer
2021-05-05 19:14:37 +02:00
parent be8b2bf6f6
commit 9e3b5d313b
6 changed files with 489 additions and 290 deletions

View File

@ -0,0 +1,167 @@
import { css, CSSResult, customElement, LitElement, property } from "lit-element";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFNav from "@patternfly/patternfly/components/Nav/nav.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import AKGlobal from "../../authentik.css";
import { TemplateResult, html } from "lit-html";
import { until } from "lit-html/directives/until";
import { ROUTE_SEPARATOR } from "../../constants";
@customElement("ak-sidebar-item")
export class SidebarItem extends LitElement {
static get styles(): CSSResult[] {
return [
PFBase,
PFPage,
PFNav,
AKGlobal,
css`
:host {
z-index: 100;
box-shadow: none !important;
}
.pf-c-nav__link.pf-m-current::after,
.pf-c-nav__link.pf-m-current:hover::after,
.pf-c-nav__item.pf-m-current:not(.pf-m-expanded) .pf-c-nav__link::after {
--pf-c-nav__link--m-current--after--BorderColor: #fd4b2d;
}
.pf-c-nav__section + .pf-c-nav__section {
--pf-c-nav__section--section--MarginTop: var(--pf-global--spacer--sm);
}
.pf-c-nav__list .sidebar-brand {
max-height: 82px;
margin-bottom: -0.5rem;
}
nav {
display: flex;
flex-direction: column;
max-height: 100vh;
height: 100%;
overflow-y: hidden;
}
.pf-c-nav__list {
flex-grow: 1;
overflow-y: auto;
}
.pf-c-nav__link {
--pf-c-nav__link--PaddingTop: 0.5rem;
--pf-c-nav__link--PaddingRight: 0.5rem;
--pf-c-nav__link--PaddingBottom: 0.5rem;
}
.pf-c-nav__section-title {
font-size: 12px;
}
.pf-c-nav__item {
--pf-c-nav__item--MarginTop: 0px;
}
`,
];
}
@property()
path?: string;
@property({ attribute: false })
condition: () => Promise<boolean> = async () => true;
activeMatchers: RegExp[] = [];
@property({ type: Boolean })
expanded = false;
@property({ type: Boolean })
isActive = false;
parent?: SidebarItem;
get childItems(): SidebarItem[] {
const children = Array.from(this.querySelectorAll<SidebarItem>("ak-sidebar-item") || []);
children.forEach(child => child.parent = this);
return children;
}
@property({attribute: false})
set activeWhen(regexp: string[]) {
regexp.forEach(r => {
this.activeMatchers.push(new RegExp(r));
});
}
firstUpdated(): void {
this.onHashChange();
window.addEventListener("hashchange", () => this.onHashChange());
}
onHashChange(): void {
const activePath = window.location.hash.slice(1, Infinity).split(ROUTE_SEPARATOR)[0];
this.childItems.forEach(item => {
this.expandParentRecursive(activePath, item);
});
this.isActive = this.matchesPath(activePath);
}
private matchesPath(path: string): boolean {
if (!this.path) {
return false;
}
if (this.path) {
if (new RegExp(`^${this.path}$`).exec(path)) {
return true;
}
}
return this.activeMatchers.some(v => {
const match = v.exec(path);
if (match !== null) {
return true;
}
});
}
expandParentRecursive(activePath: string, item: SidebarItem): void {
if (item.matchesPath(activePath) && item.parent) {
item.parent.expanded = true;
this.requestUpdate();
}
item.childItems.forEach(i => this.expandParentRecursive(activePath, i));
}
render(): TemplateResult {
return html`${until(this.renderInner())}`;
}
async renderInner(): Promise<TemplateResult> {
if (this.condition) {
const result = await this.condition();
if (!result) {
return html``;
}
}
if (this.childItems.length > 0) {
return html`<li class="pf-c-nav__item ${this.expanded ? "pf-m-expandable pf-m-expanded" : ""}">
<button class="pf-c-nav__link" aria-expanded="true" @click=${() => {
this.expanded = !this.expanded;
}}>
<slot name="label"></slot>
<span class="pf-c-nav__toggle">
<span class="pf-c-nav__toggle-icon">
<i class="fas fa-angle-right" aria-hidden="true"></i>
</span>
</span>
</button>
<section class="pf-c-nav__subnav" ?hidden=${!this.expanded}>
<ul class="pf-c-nav__list">
<slot></slot>
</ul>
</section>
</li>`;
}
return html`<li class="pf-c-nav__item">
<a href="#${this.path}" class="pf-c-nav__link ${this.isActive ? "pf-m-current" : ""}">
<slot name="label"></slot>
</a>
</li>`;
}
}