import { CSSResult, LitElement, css } from "lit"; import { TemplateResult, html } from "lit"; import { customElement, property } from "lit/decorators"; import { until } from "lit/directives/until"; import AKGlobal from "../../authentik.css"; import PFNav from "@patternfly/patternfly/components/Nav/nav.css"; import PFPage from "@patternfly/patternfly/components/Page/page.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; 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; } :host([highlight]) .pf-c-nav__item { background-color: var(--ak-accent); margin: 16px; } :host([highlight]) .pf-c-nav__item .pf-c-nav__link { padding-left: 0.5rem; } .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 = async () => true; activeMatchers: RegExp[] = []; @property({ type: Boolean }) expanded = false; @property({ type: Boolean }) isActive = false; @property({ type: Boolean }) isAbsoluteLink?: boolean; @property({ type: Boolean }) highlight?: boolean; parent?: SidebarItem; get childItems(): SidebarItem[] { const children = Array.from(this.querySelectorAll("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 { if (this.condition) { const result = await this.condition(); if (!result) { return html``; } } if (this.childItems.length > 0) { return html`
  • `; } return html`
  • ${this.path ? html` ` : html` `}
  • `; } }