Due for amendment
This commit is contained in:
		| @ -148,7 +148,7 @@ export default [ | ||||
|     }, | ||||
|     // Admin interface | ||||
|     { | ||||
|         input: "./src/admin/AdminInterface.ts", | ||||
|         input: "./src/admin/AdminInterface/AdminInterface.ts", | ||||
|         output: [ | ||||
|             { | ||||
|                 format: "es", | ||||
|  | ||||
| @ -26,6 +26,7 @@ import { spread } from "@open-wc/lit-helpers"; | ||||
| import { msg, str } from "@lit/localize"; | ||||
| import { CSSResult, TemplateResult, css, html, nothing } from "lit"; | ||||
| import { customElement, property, state } from "lit/decorators.js"; | ||||
| import { classMap } from "lit/directives/class-map.js"; | ||||
| import { map } from "lit/directives/map.js"; | ||||
| 
 | ||||
| import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||||
| @ -33,14 +34,9 @@ import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css"; | ||||
| import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||
| import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||
| 
 | ||||
| import { | ||||
|     AdminApi, | ||||
|     CapabilitiesEnum, | ||||
|     CoreApi, | ||||
|     SessionUser, | ||||
|     UiThemeEnum, | ||||
|     Version, | ||||
| } from "@goauthentik/api"; | ||||
| import { AdminApi, CoreApi, SessionUser, UiThemeEnum, Version } from "@goauthentik/api"; | ||||
| 
 | ||||
| import "./AdminSidebar"; | ||||
| 
 | ||||
| @customElement("ak-interface-admin") | ||||
| export class AdminInterface extends Interface { | ||||
| @ -126,23 +122,26 @@ export class AdminInterface extends Interface { | ||||
|     } | ||||
| 
 | ||||
|     render(): TemplateResult { | ||||
|         const sidebarClasses = { | ||||
|             "pf-m-expanded": this.sidebarOpen, | ||||
|             "pf-m-collapsed": !this.sidebarOpen, | ||||
|             "pf-m-light": this.activeTheme === UiThemeEnum.Light, | ||||
|         }; | ||||
| 
 | ||||
|         const drawerOpen = this.notificationDrawerOpen || this.apiDrawerOpen; | ||||
|         const drawerClasses = { | ||||
|             "pf-m-expanded": drawerOpen, | ||||
|             "pf-m-collapsed": !drawerOpen, | ||||
|         }; | ||||
| 
 | ||||
|         return html` <ak-locale-context>
 | ||||
|             <div class="pf-c-page"> | ||||
|                 <ak-sidebar | ||||
|                     class="pf-c-page__sidebar ${this.sidebarOpen | ||||
|                         ? "pf-m-expanded" | ||||
|                         : "pf-m-collapsed"} ${this.activeTheme === UiThemeEnum.Light | ||||
|                         ? "pf-m-light" | ||||
|                         : ""}" | ||||
|                 > | ||||
|                     ${this.renderSidebarItems()} | ||||
|                 </ak-sidebar> | ||||
|                 <ak-admin-sidebar | ||||
|                     ?open=${this.sidebarOpen} | ||||
|                     class="pf-c-page__sidebar ${classMap(sidebarClasses)}" | ||||
|                 ></ak-admin-sidebar> | ||||
|                 <div class="pf-c-page__drawer"> | ||||
|                     <div | ||||
|                         class="pf-c-drawer ${this.notificationDrawerOpen || this.apiDrawerOpen | ||||
|                             ? "pf-m-expanded" | ||||
|                             : "pf-m-collapsed"}" | ||||
|                     > | ||||
|                     <div class="pf-c-drawer ${classMap(drawerClasses)}"> | ||||
|                         <div class="pf-c-drawer__main"> | ||||
|                             <div class="pf-c-drawer__content"> | ||||
|                                 <div class="pf-c-drawer__body"> | ||||
| @ -177,120 +176,4 @@ export class AdminInterface extends Interface { | ||||
|                 </div></div | ||||
|         ></ak-locale-context>`; | ||||
|     } | ||||
| 
 | ||||
|     renderSidebarItems(): TemplateResult { | ||||
|         // The second attribute type is of string[] to help with the 'activeWhen' control, which was
 | ||||
|         // commonplace and singular enough to merit its own handler.
 | ||||
|         type SidebarEntry = [ | ||||
|             path: string | null, | ||||
|             label: string, | ||||
|             attributes?: Record<string, any> | string[] | null, // eslint-disable-line
 | ||||
|             children?: SidebarEntry[], | ||||
|         ]; | ||||
| 
 | ||||
|         // prettier-ignore
 | ||||
|         const sidebarContent: SidebarEntry[] = [ | ||||
|             ["/if/user/", msg("User interface"), { "?isAbsoluteLink": true, "?highlight": true }], | ||||
|             [null, msg("Dashboards"), { "?expanded": true }, [ | ||||
|                 ["/administration/overview", msg("Overview")], | ||||
|                 ["/administration/dashboard/users", msg("User Statistics")], | ||||
|                 ["/administration/system-tasks", msg("System Tasks")]]], | ||||
|             [null, msg("Applications"), null, [ | ||||
|                 ["/core/providers", msg("Providers"), [`^/core/providers/(?<id>${ID_REGEX})$`]], | ||||
|                 ["/core/applications", msg("Applications"), [`^/core/applications/(?<slug>${SLUG_REGEX})$`]], | ||||
|                 ["/outpost/outposts", msg("Outposts")]]], | ||||
|             [null, msg("Events"), null, [ | ||||
|                 ["/events/log", msg("Logs"), [`^/events/log/(?<id>${UUID_REGEX})$`]], | ||||
|                 ["/events/rules", msg("Notification Rules")], | ||||
|                 ["/events/transports", msg("Notification Transports")]]], | ||||
|             [null, msg("Customisation"), null, [ | ||||
|                 ["/policy/policies", msg("Policies")], | ||||
|                 ["/core/property-mappings", msg("Property Mappings")], | ||||
|                 ["/blueprints/instances", msg("Blueprints")], | ||||
|                 ["/policy/reputation", msg("Reputation scores")]]], | ||||
|             [null, msg("Flows and Stages"), null, [ | ||||
|                 ["/flow/flows", msg("Flows"), [`^/flow/flows/(?<slug>${SLUG_REGEX})$`]], | ||||
|                 ["/flow/stages", msg("Stages")], | ||||
|                 ["/flow/stages/prompts", msg("Prompts")]]], | ||||
|             [null, msg("Directory"), null, [ | ||||
|                 ["/identity/users", msg("Users"), [`^/identity/users/(?<id>${ID_REGEX})$`]], | ||||
|                 ["/identity/groups", msg("Groups"), [`^/identity/groups/(?<id>${UUID_REGEX})$`]], | ||||
|                 ["/identity/roles", msg("Roles"), [`^/identity/roles/(?<id>${UUID_REGEX})$`]], | ||||
|                 ["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?<slug>${SLUG_REGEX})$`]], | ||||
|                 ["/core/tokens", msg("Tokens and App passwords")], | ||||
|                 ["/flow/stages/invitations", msg("Invitations")]]], | ||||
|             [null, msg("System"), null, [ | ||||
|                 ["/core/tenants", msg("Tenants")], | ||||
|                 ["/crypto/certificates", msg("Certificates")], | ||||
|                 ["/outpost/integrations", msg("Outpost Integrations")]]] | ||||
|         ]; | ||||
| 
 | ||||
|         // Typescript requires the type here to correctly type the recursive path
 | ||||
|         type SidebarRenderer = (_: SidebarEntry) => TemplateResult; | ||||
| 
 | ||||
|         const renderOneSidebarItem: SidebarRenderer = ([path, label, attributes, children]) => { | ||||
|             const properties = Array.isArray(attributes) | ||||
|                 ? { ".activeWhen": attributes } | ||||
|                 : attributes ?? {}; | ||||
|             if (path) { | ||||
|                 properties["path"] = path; | ||||
|             } | ||||
|             return html`<ak-sidebar-item ${spread(properties)}>
 | ||||
|                 ${label ? html`<span slot="label">${label}</span>` : nothing} | ||||
|                 ${map(children, renderOneSidebarItem)} | ||||
|             </ak-sidebar-item>`; | ||||
|         }; | ||||
| 
 | ||||
|         // prettier-ignore
 | ||||
|         return html` | ||||
|             ${this.renderNewVersionMessage()} | ||||
|             ${this.renderImpersonationMessage()} | ||||
|             ${map(sidebarContent, renderOneSidebarItem)} | ||||
|             ${this.renderEnterpriseMessage()} | ||||
|         `;
 | ||||
|     } | ||||
| 
 | ||||
|     renderNewVersionMessage() { | ||||
|         return this.version && this.version.versionCurrent !== VERSION | ||||
|             ? html` | ||||
|                   <ak-sidebar-item ?highlight=${true}> | ||||
|                       <span slot="label" | ||||
|                           >${msg("A newer version of the frontend is available.")}</span | ||||
|                       > | ||||
|                   </ak-sidebar-item> | ||||
|               ` | ||||
|             : nothing; | ||||
|     } | ||||
| 
 | ||||
|     renderImpersonationMessage() { | ||||
|         return this.user?.original | ||||
|             ? html`<ak-sidebar-item
 | ||||
|                   ?highlight=${true} | ||||
|                   @click=${() => { | ||||
|                       new CoreApi(DEFAULT_CONFIG).coreUsersImpersonateEndRetrieve().then(() => { | ||||
|                           window.location.reload(); | ||||
|                       }); | ||||
|                   }} | ||||
|               > | ||||
|                   <span slot="label" | ||||
|                       >${msg( | ||||
|                           str`You're currently impersonating ${this.user.user.username}. Click to stop.`, | ||||
|                       )}</span | ||||
|                   > | ||||
|               </ak-sidebar-item>` | ||||
|             : nothing; | ||||
|     } | ||||
| 
 | ||||
|     renderEnterpriseMessage() { | ||||
|         return this.config?.capabilities.includes(CapabilitiesEnum.IsEnterprise) | ||||
|             ? html` | ||||
|                   <ak-sidebar-item> | ||||
|                       <span slot="label">${msg("Enterprise")}</span> | ||||
|                       <ak-sidebar-item path="/enterprise/licenses"> | ||||
|                           <span slot="label">${msg("Licenses")}</span> | ||||
|                       </ak-sidebar-item> | ||||
|                   </ak-sidebar-item> | ||||
|               ` | ||||
|             : nothing; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										183
									
								
								web/src/admin/AdminInterface/AdminSidebar.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								web/src/admin/AdminInterface/AdminSidebar.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,183 @@ | ||||
| import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; | ||||
| import { VERSION } from "@goauthentik/common/constants"; | ||||
| import { me } from "@goauthentik/common/users"; | ||||
| import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; | ||||
| import { AKElement } from "@goauthentik/elements/Base"; | ||||
| import { ID_REGEX, SLUG_REGEX, UUID_REGEX } from "@goauthentik/elements/router/Route"; | ||||
| import { spread } from "@open-wc/lit-helpers"; | ||||
|  | ||||
| import { consume } from "@lit-labs/context"; | ||||
| import { msg, str } from "@lit/localize"; | ||||
| import { TemplateResult, html, nothing } from "lit"; | ||||
| import { customElement, property, state } from "lit/decorators.js"; | ||||
| import { map } from "lit/directives/map.js"; | ||||
|  | ||||
| import { | ||||
|     AdminApi, | ||||
|     CapabilitiesEnum, | ||||
|     type Config, | ||||
|     CoreApi, | ||||
|     ProvidersApi, | ||||
|     type SessionUser, | ||||
|     UiThemeEnum, | ||||
|     type UserSelf, | ||||
|     TypeCreate, | ||||
|     Version, | ||||
| } from "@goauthentik/api"; | ||||
|  | ||||
| @customElement("ak-admin-sidebar") | ||||
| export class AkAdminSidebar extends AKElement { | ||||
|     @property({ type: Boolean }) | ||||
|     open = true; | ||||
|  | ||||
|     @state() | ||||
|     version: Version["versionCurrent"] | null = null; | ||||
|  | ||||
|     @state() | ||||
|     impersonation: UserSelf["username"] | null = null; | ||||
|  | ||||
|     @state() | ||||
|     providerTypes: TypeCreate[] = []; | ||||
|  | ||||
|     @consume({ context: authentikConfigContext }) | ||||
|     public config!: Config; | ||||
|  | ||||
|     firstUpdated() { | ||||
|         new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve().then((version) => { | ||||
|             this.version = version.versionCurrent; | ||||
|         }); | ||||
|         me().then((user: SessionUser) => { | ||||
|             this.impersonation = user.original ? user.user.username : null; | ||||
|         }); | ||||
|         new ProvidersApi(DEFAULT_CONFIG).providersAllTypesList().then((types) => { | ||||
|             this.providerTypes = types; | ||||
|         });         | ||||
|     } | ||||
|  | ||||
|     render() { | ||||
|         return html` | ||||
|             <ak-sidebar | ||||
|                 class="pf-c-page__sidebar ${this.open ? "pf-m-expanded" : "pf-m-collapsed"} ${this | ||||
|                     .activeTheme === UiThemeEnum.Light | ||||
|                     ? "pf-m-light" | ||||
|                     : ""}" | ||||
|             > | ||||
|                 ${this.renderSidebarItems()} | ||||
|             </ak-sidebar> | ||||
|         `; | ||||
|     } | ||||
|  | ||||
|     renderSidebarItems(): TemplateResult { | ||||
|         // The second attribute type is of string[] to help with the 'activeWhen' control, which was | ||||
|         // commonplace and singular enough to merit its own handler. | ||||
|         type SidebarEntry = [ | ||||
|             path: string | null, | ||||
|             label: string, | ||||
|             attributes?: Record<string, any> | string[] | null, // eslint-disable-line | ||||
|             children?: SidebarEntry[], | ||||
|         ]; | ||||
|  | ||||
|         // prettier-ignore | ||||
|         const sidebarContent: SidebarEntry[] = [ | ||||
|             ["/if/user/", msg("User interface"), { "?isAbsoluteLink": true, "?highlight": true }], | ||||
|             [null, msg("Dashboards"), { "?expanded": true }, [ | ||||
|                 ["/administration/overview", msg("Overview")], | ||||
|                 ["/administration/dashboard/users", msg("User Statistics")], | ||||
|                 ["/administration/system-tasks", msg("System Tasks")]]], | ||||
|             [null, msg("Applications"), null, [ | ||||
|                 ["/core/applications", msg("Applications"), [`^/core/applications/(?<slug>${SLUG_REGEX})$`]], | ||||
|                 ["/core/providers", msg("Providers"), [`^/core/providers/(?<id>${ID_REGEX})$`]], | ||||
|                 ["/outpost/outposts", msg("Outposts")]]], | ||||
|             [null, msg("Events"), null, [ | ||||
|                 ["/events/log", msg("Logs"), [`^/events/log/(?<id>${UUID_REGEX})$`]], | ||||
|                 ["/events/rules", msg("Notification Rules")], | ||||
|                 ["/events/transports", msg("Notification Transports")]]], | ||||
|             [null, msg("Customisation"), null, [ | ||||
|                 ["/policy/policies", msg("Policies")], | ||||
|                 ["/core/property-mappings", msg("Property Mappings")], | ||||
|                 ["/blueprints/instances", msg("Blueprints")], | ||||
|                 ["/policy/reputation", msg("Reputation scores")]]], | ||||
|             [null, msg("Flows and Stages"), null, [ | ||||
|                 ["/flow/flows", msg("Flows"), [`^/flow/flows/(?<slug>${SLUG_REGEX})$`]], | ||||
|                 ["/flow/stages", msg("Stages")], | ||||
|                 ["/flow/stages/prompts", msg("Prompts")]]], | ||||
|             [null, msg("Directory"), null, [ | ||||
|                 ["/identity/users", msg("Users"), [`^/identity/users/(?<id>${ID_REGEX})$`]], | ||||
|                 ["/identity/groups", msg("Groups"), [`^/identity/groups/(?<id>${UUID_REGEX})$`]], | ||||
|                 ["/identity/roles", msg("Roles"), [`^/identity/roles/(?<id>${UUID_REGEX})$`]], | ||||
|                 ["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?<slug>${SLUG_REGEX})$`]], | ||||
|                 ["/core/tokens", msg("Tokens and App passwords")], | ||||
|                 ["/flow/stages/invitations", msg("Invitations")]]], | ||||
|             [null, msg("System"), null, [ | ||||
|                 ["/core/tenants", msg("Tenants")], | ||||
|                 ["/crypto/certificates", msg("Certificates")], | ||||
|                 ["/outpost/integrations", msg("Outpost Integrations")]]] | ||||
|         ]; | ||||
|  | ||||
|         // Typescript requires the type here to correctly type the recursive path | ||||
|         type SidebarRenderer = (_: SidebarEntry) => TemplateResult; | ||||
|  | ||||
|         const renderOneSidebarItem: SidebarRenderer = ([path, label, attributes, children]) => { | ||||
|             const properties = Array.isArray(attributes) | ||||
|                 ? { ".activeWhen": attributes } | ||||
|                 : attributes ?? {}; | ||||
|             if (path) { | ||||
|                 properties["path"] = path; | ||||
|             } | ||||
|             return html`<ak-sidebar-item ${spread(properties)}> | ||||
|                 ${label ? html`<span slot="label">${label}</span>` : nothing} | ||||
|                 ${map(children, renderOneSidebarItem)} | ||||
|             </ak-sidebar-item>`; | ||||
|         }; | ||||
|  | ||||
|         // prettier-ignore | ||||
|         return html` | ||||
|             ${this.renderNewVersionMessage()} | ||||
|             ${this.renderImpersonationMessage()} | ||||
|             ${map(sidebarContent, renderOneSidebarItem)} | ||||
|             ${this.renderEnterpriseMessage()} | ||||
|         `; | ||||
|     } | ||||
|  | ||||
|     renderNewVersionMessage() { | ||||
|         return this.version && this.version !== VERSION | ||||
|             ? html` | ||||
|                   <ak-sidebar-item ?highlight=${true}> | ||||
|                       <span slot="label" | ||||
|                           >${msg("A newer version of the frontend is available.")}</span | ||||
|                       > | ||||
|                   </ak-sidebar-item> | ||||
|               ` | ||||
|             : nothing; | ||||
|     } | ||||
|  | ||||
|     renderImpersonationMessage() { | ||||
|         const reload = () => | ||||
|             new CoreApi(DEFAULT_CONFIG).coreUsersImpersonateEndRetrieve().then(() => { | ||||
|                 window.location.reload(); | ||||
|             }); | ||||
|  | ||||
|         return this.impersonation | ||||
|             ? html`<ak-sidebar-item ?highlight=${true} @click=${reload}> | ||||
|                   <span slot="label" | ||||
|                       >${msg( | ||||
|                           str`You're currently impersonating ${this.impersonation}. Click to stop.` | ||||
|                       )}</span | ||||
|                   > | ||||
|               </ak-sidebar-item>` | ||||
|             : nothing; | ||||
|     } | ||||
|  | ||||
|     renderEnterpriseMessage() { | ||||
|         return this.config?.capabilities.includes(CapabilitiesEnum.IsEnterprise) | ||||
|             ? html` | ||||
|                   <ak-sidebar-item> | ||||
|                       <span slot="label">${msg("Enterprise")}</span> | ||||
|                       <ak-sidebar-item path="/enterprise/licenses"> | ||||
|                           <span slot="label">${msg("Licenses")}</span> | ||||
|                       </ak-sidebar-item> | ||||
|                   </ak-sidebar-item> | ||||
|               ` | ||||
|             : nothing; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										3
									
								
								web/src/admin/AdminInterface/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								web/src/admin/AdminInterface/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| import { AdminInterface } from "./AdminInterface"; | ||||
| import "./AdminInterface"; | ||||
| export { AdminInterface }; | ||||
							
								
								
									
										8
									
								
								web/src/elements/AuthentikContexts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								web/src/elements/AuthentikContexts.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| import { createContext } from "@lit-labs/context"; | ||||
| import { type Config } from "@goauthentik/api"; | ||||
|  | ||||
| export const authentikConfigContext = createContext<Config>( | ||||
|     Symbol("authentik-config-context") | ||||
| ); | ||||
|  | ||||
| export default authentikConfigContext; | ||||
| @ -1,6 +1,7 @@ | ||||
| import { config, tenant } from "@goauthentik/common/api/config"; | ||||
| import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; | ||||
| import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; | ||||
| import { ContextProvider } from "@lit-labs/context"; | ||||
| import { adaptCSS } from "@goauthentik/common/utils"; | ||||
|  | ||||
| import { localized } from "@lit/localize"; | ||||
| @ -12,6 +13,7 @@ import ThemeDark from "@goauthentik/common/styles/theme-dark.css"; | ||||
| import PFBase from "@patternfly/patternfly/patternfly-base.css"; | ||||
|  | ||||
| import { Config, CurrentTenant, UiThemeEnum } from "@goauthentik/api"; | ||||
| import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts"; | ||||
|  | ||||
| type AkInterface = HTMLElement & { | ||||
|     getTheme: () => Promise<UiThemeEnum>; | ||||
| @ -181,8 +183,25 @@ export class Interface extends AKElement implements AkInterface { | ||||
|     @state() | ||||
|     uiConfig?: UIConfig; | ||||
|  | ||||
|     _configContext = new ContextProvider(this, { | ||||
|         context: authentikConfigContext, | ||||
|         initialValue: undefined | ||||
|     }); | ||||
|  | ||||
|  | ||||
|     _config?: Config; | ||||
|  | ||||
|     @state() | ||||
|     config?: Config; | ||||
|     set config(c: Config) { | ||||
|         this._config = c; | ||||
|         this._configContext.setValue(c); | ||||
|         this.requestUpdate(); | ||||
|     } | ||||
|  | ||||
|     get config(): Config | undefined { | ||||
|         return this._config; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     constructor() { | ||||
|         super(); | ||||
|  | ||||
| @ -144,47 +144,84 @@ export class SidebarItem extends AKElement { | ||||
|         return this.renderInner(); | ||||
|     } | ||||
|  | ||||
|     renderInner(): TemplateResult { | ||||
|         if (this.childItems.length > 0) { | ||||
|             return html`<li | ||||
|                 class="pf-c-nav__item ${this.expanded ? "pf-m-expandable pf-m-expanded" : ""}" | ||||
|     renderWithChildren() { | ||||
|         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; | ||||
|                 }} | ||||
|             > | ||||
|                 <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> | ||||
|                 <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> | ||||
|                 </button> | ||||
|                 <section class="pf-c-nav__subnav" ?hidden=${!this.expanded}> | ||||
|                     <ul class="pf-c-nav__list"> | ||||
|                         <slot></slot> | ||||
|                     </ul> | ||||
|                 </section> | ||||
|             </li>`; | ||||
|                 </span> | ||||
|             </button> | ||||
|             <section class="pf-c-nav__subnav" ?hidden=${!this.expanded}> | ||||
|                 <ul class="pf-c-nav__list"> | ||||
|                     <slot></slot> | ||||
|                 </ul> | ||||
|             </section> | ||||
|         </li>`; | ||||
|     } | ||||
|  | ||||
|     renderWithPathAndChildren() { | ||||
|         return html`<li | ||||
|             class="pf-c-nav__item ${this.expanded ? "pf-m-expandable pf-m-expanded" : ""}" | ||||
|         > | ||||
|             <slot name="label"></slot> | ||||
|             <button | ||||
|                 class="pf-c-nav__link" | ||||
|                 aria-expanded="true" | ||||
|                 @click=${() => { | ||||
|                     this.expanded = !this.expanded; | ||||
|                 }} | ||||
|             > | ||||
|                 <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>`; | ||||
|     } | ||||
|  | ||||
|     renderWithPath() { | ||||
|         return html` | ||||
|             <a | ||||
|                 href="${this.isAbsoluteLink ? "" : "#"}${this.path}" | ||||
|                 class="pf-c-nav__link ${this.isActive ? "pf-m-current" : ""}" | ||||
|             > | ||||
|                 <slot name="label"></slot> | ||||
|             </a> | ||||
|         `; | ||||
|     } | ||||
|  | ||||
|     renderWithLabel() { | ||||
|         html` | ||||
|             <span class="pf-c-nav__link"> | ||||
|                 <slot name="label"></slot> | ||||
|             </span> | ||||
|         `; | ||||
|     } | ||||
|  | ||||
|     renderInner() { | ||||
|         if (this.childItems.length > 0) { | ||||
|             return this.path ? this.renderWithPathAndChildren() : this.renderWithChildren(); | ||||
|         } | ||||
|  | ||||
|         return html`<li class="pf-c-nav__item"> | ||||
|             ${this.path | ||||
|                 ? html` | ||||
|                       <a | ||||
|                           href="${this.isAbsoluteLink ? "" : "#"}${this.path}" | ||||
|                           class="pf-c-nav__link ${this.isActive ? "pf-m-current" : ""}" | ||||
|                       > | ||||
|                           <slot name="label"></slot> | ||||
|                       </a> | ||||
|                   ` | ||||
|                 : html` | ||||
|                       <span class="pf-c-nav__link"> | ||||
|                           <slot name="label"></slot> | ||||
|                       </span> | ||||
|                   `} | ||||
|             ${this.path ? this.renderWithPath() : this.renderWithLabel()} | ||||
|         </li>`; | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Ken Sternberg
					Ken Sternberg