static: rewrite tabs to not use hash and render in shadow root
This commit is contained in:
parent
c7b6eac33d
commit
1e640fac76
|
@ -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
|
@ -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);
|
||||||
|
|
|
@ -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;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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">
|
||||||
|
|
Reference in New Issue