static: rewrite tabs to not use hash and render in shadow root

This commit is contained in:
Jens Langhammer 2020-11-26 23:31:56 +01:00
parent c7b6eac33d
commit 1e640fac76
7 changed files with 84 additions and 71 deletions

View File

@ -47,12 +47,12 @@
{% for application in object_list %} {% for application in object_list %}
<tr role="row"> <tr role="row">
<th role="columnheader"> <th role="columnheader">
<div> <a href="/applications/{{ application.slug }}/">
<div>{{ application.name }}</div> <div>{{ application.name }}</div>
{% if application.meta_publisher %} {% if application.meta_publisher %}
<small>{{ application.meta_publisher }}</small> <small>{{ application.meta_publisher }}</small>
{% endif %} {% endif %}
</div> </a>
</th> </th>
<td role="cell"> <td role="cell">
<code>{{ application.slug }}</span> <code>{{ application.slug }}</span>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4,6 +4,7 @@ export const PRIMARY_CLASS = "pf-m-primary";
export const SUCCESS_CLASS = "pf-m-success"; export const SUCCESS_CLASS = "pf-m-success";
export const ERROR_CLASS = "pf-m-danger"; export const ERROR_CLASS = "pf-m-danger";
export const PROGRESS_CLASS = "pf-m-in-progress"; export const PROGRESS_CLASS = "pf-m-in-progress";
export const CURRENT_CLASS = "pf-m-current";
export const ColorStyles = css` export const ColorStyles = css`
.pf-m-success { .pf-m-success {
color: var(--pf-global--success-color--100); color: var(--pf-global--success-color--100);

View File

@ -1,62 +1,52 @@
import { LitElement, html, customElement } from "lit-element"; import { LitElement, html, customElement, property } from "lit-element";
// @ts-ignore
import TabsStyle from "@patternfly/patternfly/components/Tabs/tabs.css";
// @ts-ignore
import GlobalsStyle from "@patternfly/patternfly/base/patternfly-globals.css";
import { CURRENT_CLASS } from "../constants";
@customElement("pb-tabs") @customElement("pb-tabs")
export class Tabs extends LitElement { export class Tabs extends LitElement {
_currentPage? = ""; @property()
_firstPage? = ""; currentPage?: string;
get currentPage() { static get styles() {
return this._currentPage; return [GlobalsStyle, TabsStyle];
} }
set currentPage(value) { render() {
try { let pages = Array.from(this.querySelectorAll("[slot]")!);
// Show active tab page if (!this.currentPage) {
this.querySelector( if (pages.length < 1) {
`.pf-c-tab-content[tab-name='${value}']` return html`<h1>no tabs defined</h1>`;
)?.removeAttribute("hidden"); }
// Update active status on buttons this.currentPage = pages[0].attributes.getNamedItem("slot")?.value;
this.querySelector( }
`.pf-c-tabs__item[tab-name='${value}']` return html`<div class="pf-c-tabs">
)?.classList.add("pf-m-current"); <ul class="pf-c-tabs__list">
// Hide other tab pages ${pages.map((page) => {
this.querySelectorAll( const slot = page.attributes.getNamedItem("slot")
`.pf-c-tab-content:not([tab-name='${value}'])` ?.value;
).forEach((el) => { return html` <li
el.setAttribute("hidden", ""); class="pf-c-tabs__item ${slot === this.currentPage
}); ? CURRENT_CLASS
// Update active status on other buttons : ""}"
this.querySelectorAll( >
`.pf-c-tabs__item:not([tab-name='${value}'])` <button
).forEach((el) => { class="pf-c-tabs__link"
el.classList.remove("pf-m-current"); @click=${() => {
}); this.currentPage = slot;
// Update window hash }}
window.location.hash = `#${value}`; >
this._currentPage = value; <span class="pf-c-tabs__item-text">
} catch (e) { ${page.attributes.getNamedItem("tab-title")
this.currentPage = this._firstPage; ?.value}
} </span>
} </button>
</li>`;
createRenderRoot() { })}
return this; </ul>
} </div>
<slot name="${this.currentPage}"></slot>`;
firstUpdated() {
this._firstPage = this.querySelector(".pf-c-tab-content")?.getAttribute(
"tab-name"
)!;
if (window.location.hash) {
this.currentPage = window.location.hash;
} else {
this.currentPage = this._firstPage;
}
this.querySelectorAll(".pf-c-tabs__item > button").forEach((button) => {
button.addEventListener("click", (e) => {
let tabPage = button.parentElement?.getAttribute("tab-name")!;
this.currentPage = tabPage;
});
});
} }
} }

View File

@ -47,12 +47,19 @@ export class Route {
} }
throw new Error("Route does not have callback or element"); throw new Error("Route does not have callback or element");
} }
toString(): string {
return `<Route url=${this.url} callback=${
this.callback ? "true" : "false"
}>`;
}
} }
export const SLUG_REGEX = "[-a-zA-Z0-9_]+"; export const SLUG_REGEX = "[-a-zA-Z0-9_]+";
export const ROUTES: Route[] = [ export const ROUTES: Route[] = [
// Prevent infinite Shell loops // Prevent infinite Shell loops
new Route(new RegExp(`^/$`)).redirect("/-/overview/"), new Route(new RegExp(`^/$`)).redirect("/-/overview/"),
new Route(new RegExp(`^#.*`)).redirect("/-/overview/"),
new Route(new RegExp(`^/applications/$`), html`<h1>test</h1>`), new Route(new RegExp(`^/applications/$`), html`<h1>test</h1>`),
new Route(new RegExp(`^/applications/(?<slug>${SLUG_REGEX})/$`)).then( new Route(new RegExp(`^/applications/(?<slug>${SLUG_REGEX})/$`)).then(
(args) => { (args) => {
@ -75,6 +82,10 @@ class RouteMatch {
render(): TemplateResult { render(): TemplateResult {
return this.route.render(this.arguments!.groups || {}); return this.route.render(this.arguments!.groups || {});
} }
toString(): string {
return `<RouteMatch url=${this.fullUrl} route=${this.route} arguments=${this.arguments}>`;
}
} }
@customElement("pb-router-outlet") @customElement("pb-router-outlet")
@ -112,6 +123,7 @@ export class RouterOutlet extends LitElement {
if (activeUrl === "") { if (activeUrl === "") {
activeUrl = this.defaultUrl!; activeUrl = this.defaultUrl!;
window.location.hash = `#${activeUrl}`; window.location.hash = `#${activeUrl}`;
console.debug(`passbook/router: set to ${window.location.hash}`);
return; return;
} }
let matchedRoute: RouteMatch | null = null; let matchedRoute: RouteMatch | null = null;
@ -124,6 +136,7 @@ export class RouterOutlet extends LitElement {
matchedRoute = new RouteMatch(route); matchedRoute = new RouteMatch(route);
matchedRoute.arguments = match; matchedRoute.arguments = match;
matchedRoute.fullUrl = activeUrl; matchedRoute.fullUrl = activeUrl;
console.debug(`passbook/router: found match ${matchedRoute}`);
return; return;
} }
}); });

View File

@ -1,4 +1,4 @@
import { customElement, html, LitElement, property } from "lit-element"; import { css, customElement, html, LitElement, property } from "lit-element";
import { Application } from "../../api/application"; import { Application } from "../../api/application";
import { COMMON_STYLES } from "../../common/styles"; import { COMMON_STYLES } from "../../common/styles";
@ -18,24 +18,33 @@ export class ApplicationViewPage extends LitElement {
application?: Application; application?: Application;
static get styles() { static get styles() {
return COMMON_STYLES; return COMMON_STYLES.concat(
css`
img.pf-icon {
max-height: 24px;
}
`
);
} }
render() { render() {
return html`<section class="pf-c-page__main-section pf-m-light"> return html`<section class="pf-c-page__main-section pf-m-light">
<div class="pf-c-content"> <div class="pf-c-content">
<h1> <h1>
<i class="pf-icon pf-icon-applications"></i> <img
class="pf-icon"
src="${this.application?.meta_icon || ""}"
/>
${this.application?.name} ${this.application?.name}
</h1> </h1>
<p> <p>${this.application?.meta_publisher}</p>
External Applications which use passbook as
Identity-Provider, utilizing protocols like OAuth2 and
SAML.
</p>
</div> </div>
</section> </section>
<section class="pf-c-page__main-section pf-m-no-padding-mobile"> <section class="pf-c-page__main-section pf-m-no-padding-mobile">
<pb-tabs>
<div slot="page-1" tab-title="Users">users</div>
<div slot="page-2" tab-title="Containers">foo</div>
</pb-tabs>
<div class="pf-c-card"> <div class="pf-c-card">
<div class="pf-c-toolbar"> <div class="pf-c-toolbar">
<div class="pf-c-toolbar__content"> <div class="pf-c-toolbar__content">