Compare commits
	
		
			1 Commits
		
	
	
		
			flows/buff
			...
			safari-cra
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 76c3c7d968 | 
| @ -4,6 +4,7 @@ import { ROUTES } from "@goauthentik/admin/Routes"; | |||||||
| import { | import { | ||||||
|     EVENT_API_DRAWER_TOGGLE, |     EVENT_API_DRAWER_TOGGLE, | ||||||
|     EVENT_NOTIFICATION_DRAWER_TOGGLE, |     EVENT_NOTIFICATION_DRAWER_TOGGLE, | ||||||
|  |     EVENT_SIDEBAR_TOGGLE, | ||||||
| } from "@goauthentik/common/constants"; | } from "@goauthentik/common/constants"; | ||||||
| import { configureSentry } from "@goauthentik/common/sentry"; | import { configureSentry } from "@goauthentik/common/sentry"; | ||||||
| import { me } from "@goauthentik/common/users"; | import { me } from "@goauthentik/common/users"; | ||||||
| @ -11,6 +12,8 @@ import { WebsocketClient } from "@goauthentik/common/ws"; | |||||||
| import { AuthenticatedInterface } from "@goauthentik/elements/Interface"; | import { AuthenticatedInterface } from "@goauthentik/elements/Interface"; | ||||||
| import "@goauthentik/elements/ak-locale-context"; | import "@goauthentik/elements/ak-locale-context"; | ||||||
| import "@goauthentik/elements/banner/EnterpriseStatusBanner"; | import "@goauthentik/elements/banner/EnterpriseStatusBanner"; | ||||||
|  | import "@goauthentik/elements/banner/EnterpriseStatusBanner"; | ||||||
|  | import "@goauthentik/elements/banner/VersionBanner"; | ||||||
| import "@goauthentik/elements/banner/VersionBanner"; | import "@goauthentik/elements/banner/VersionBanner"; | ||||||
| import "@goauthentik/elements/messages/MessageContainer"; | import "@goauthentik/elements/messages/MessageContainer"; | ||||||
| import "@goauthentik/elements/messages/MessageContainer"; | import "@goauthentik/elements/messages/MessageContainer"; | ||||||
| @ -40,6 +43,8 @@ if (process.env.NODE_ENV === "development") { | |||||||
|  |  | ||||||
| @customElement("ak-interface-admin") | @customElement("ak-interface-admin") | ||||||
| export class AdminInterface extends AuthenticatedInterface { | export class AdminInterface extends AuthenticatedInterface { | ||||||
|  |     //#region Properties | ||||||
|  |  | ||||||
|     @property({ type: Boolean }) |     @property({ type: Boolean }) | ||||||
|     notificationDrawerOpen = getURLParam("notificationDrawerOpen", false); |     notificationDrawerOpen = getURLParam("notificationDrawerOpen", false); | ||||||
|  |  | ||||||
| @ -54,6 +59,17 @@ export class AdminInterface extends AuthenticatedInterface { | |||||||
|     @query("ak-about-modal") |     @query("ak-about-modal") | ||||||
|     aboutModal?: AboutModal; |     aboutModal?: AboutModal; | ||||||
|  |  | ||||||
|  |     @state() | ||||||
|  |     sidebarVisible = false; | ||||||
|  |  | ||||||
|  |     #toggleSidebar = () => { | ||||||
|  |         this.sidebarVisible = !this.sidebarVisible; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Styles | ||||||
|  |  | ||||||
|     static get styles(): CSSResult[] { |     static get styles(): CSSResult[] { | ||||||
|         return [ |         return [ | ||||||
|             PFBase, |             PFBase, | ||||||
| @ -67,23 +83,30 @@ export class AdminInterface extends AuthenticatedInterface { | |||||||
|                     z-index: auto !important; |                     z-index: auto !important; | ||||||
|                     background-color: transparent; |                     background-color: transparent; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 .display-none { |                 .display-none { | ||||||
|                     display: none; |                     display: none; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 .pf-c-page { |                 .pf-c-page { | ||||||
|                     background-color: var(--pf-c-page--BackgroundColor) !important; |                     background-color: var(--pf-c-page--BackgroundColor) !important; | ||||||
|                 } |                 } | ||||||
|                 /* Global page background colour */ |  | ||||||
|                 :host([theme="dark"]) .pf-c-page { |                 :host([theme="dark"]) { | ||||||
|                     --pf-c-page--BackgroundColor: var(--ak-dark-background); |                     /* Global page background colour */ | ||||||
|  |                     .pf-c-page { | ||||||
|  |                         --pf-c-page--BackgroundColor: var(--ak-dark-background); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 ak-enterprise-status, |  | ||||||
|                 ak-version-banner { |                 ak-page-navbar { | ||||||
|                     grid-area: header; |                     grid-area: header; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 ak-admin-sidebar { |                 ak-admin-sidebar { | ||||||
|                     grid-area: nav; |                     grid-area: nav; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 .pf-c-drawer__panel { |                 .pf-c-drawer__panel { | ||||||
|                     z-index: var(--pf-global--ZIndex--xl); |                     z-index: var(--pf-global--ZIndex--xl); | ||||||
|                 } |                 } | ||||||
| @ -91,6 +114,10 @@ export class AdminInterface extends AuthenticatedInterface { | |||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Lifecycle | ||||||
|  |  | ||||||
|     constructor() { |     constructor() { | ||||||
|         super(); |         super(); | ||||||
|         this.ws = new WebsocketClient(); |         this.ws = new WebsocketClient(); | ||||||
| @ -123,12 +150,26 @@ export class AdminInterface extends AuthenticatedInterface { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async connectedCallback(): Promise<void> { | ||||||
|  |         super.connectedCallback(); | ||||||
|  |  | ||||||
|  |         window.addEventListener(EVENT_SIDEBAR_TOGGLE, this.#toggleSidebar); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     disconnectedCallback(): void { | ||||||
|  |         super.disconnectedCallback(); | ||||||
|  |         window.removeEventListener(EVENT_SIDEBAR_TOGGLE, this.#toggleSidebar); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     render(): TemplateResult { |     render(): TemplateResult { | ||||||
|         const sidebarClasses = { |         const sidebarClasses = { | ||||||
|             "pf-m-light": this.activeTheme === UiThemeEnum.Light, |             "pf-m-light": this.activeTheme === UiThemeEnum.Light, | ||||||
|  |             "pf-m-expanded": !this.sidebarVisible, | ||||||
|  |             "pf-m-collapsed": this.sidebarVisible, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         const drawerOpen = this.notificationDrawerOpen || this.apiDrawerOpen; |         const drawerOpen = this.notificationDrawerOpen || this.apiDrawerOpen; | ||||||
|  |  | ||||||
|         const drawerClasses = { |         const drawerClasses = { | ||||||
|             "pf-m-expanded": drawerOpen, |             "pf-m-expanded": drawerOpen, | ||||||
|             "pf-m-collapsed": !drawerOpen, |             "pf-m-collapsed": !drawerOpen, | ||||||
| @ -136,11 +177,16 @@ export class AdminInterface extends AuthenticatedInterface { | |||||||
|  |  | ||||||
|         return html` <ak-locale-context> |         return html` <ak-locale-context> | ||||||
|             <div class="pf-c-page"> |             <div class="pf-c-page"> | ||||||
|                 <ak-enterprise-status interface="admin"></ak-enterprise-status> |                 <ak-page-navbar> | ||||||
|                 <ak-version-banner></ak-version-banner> |                     <ak-version-banner></ak-version-banner> | ||||||
|  |                     <ak-enterprise-status interface="admin"></ak-enterprise-status> | ||||||
|  |                 </ak-page-navbar> | ||||||
|  |  | ||||||
|                 <ak-admin-sidebar |                 <ak-admin-sidebar | ||||||
|                     class="pf-c-page__sidebar ${classMap(sidebarClasses)}" |                     class="pf-c-page__sidebar | ||||||
|  |                      ${classMap(sidebarClasses)}" | ||||||
|                 ></ak-admin-sidebar> |                 ></ak-admin-sidebar> | ||||||
|  |  | ||||||
|                 <div class="pf-c-page__drawer"> |                 <div class="pf-c-page__drawer"> | ||||||
|                     <div class="pf-c-drawer ${classMap(drawerClasses)}"> |                     <div class="pf-c-drawer ${classMap(drawerClasses)}"> | ||||||
|                         <div class="pf-c-drawer__main"> |                         <div class="pf-c-drawer__main"> | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| import { EVENT_SIDEBAR_TOGGLE } from "@goauthentik/common/constants"; |  | ||||||
| import { me } from "@goauthentik/common/users"; | import { me } from "@goauthentik/common/users"; | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import { | import { | ||||||
| @ -31,16 +30,9 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(WithVersion(AKElement | |||||||
|         me().then((user: SessionUser) => { |         me().then((user: SessionUser) => { | ||||||
|             this.impersonation = user.original ? user.user.username : null; |             this.impersonation = user.original ? user.user.username : null; | ||||||
|         }); |         }); | ||||||
|         this.toggleOpen = this.toggleOpen.bind(this); |  | ||||||
|         this.checkWidth = this.checkWidth.bind(this); |         this.checkWidth = this.checkWidth.bind(this); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // This has to be a bound method so the event listener can be removed on disconnection as |  | ||||||
|     // needed. |  | ||||||
|     toggleOpen() { |  | ||||||
|         this.open = !this.open; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     checkWidth() { |     checkWidth() { | ||||||
|         // This works just fine, but it assumes that the `--ak-sidebar--minimum-auto-width` is in |         // This works just fine, but it assumes that the `--ak-sidebar--minimum-auto-width` is in | ||||||
|         // REMs. If that changes, this code will have to be adjusted as well. |         // REMs. If that changes, this code will have to be adjusted as well. | ||||||
| @ -52,7 +44,7 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(WithVersion(AKElement | |||||||
|  |  | ||||||
|     connectedCallback() { |     connectedCallback() { | ||||||
|         super.connectedCallback(); |         super.connectedCallback(); | ||||||
|         window.addEventListener(EVENT_SIDEBAR_TOGGLE, this.toggleOpen); |  | ||||||
|         window.addEventListener("resize", this.checkWidth); |         window.addEventListener("resize", this.checkWidth); | ||||||
|         // After connecting to the DOM, we can now perform this check to see if the sidebar should |         // After connecting to the DOM, we can now perform this check to see if the sidebar should | ||||||
|         // be open by default. |         // be open by default. | ||||||
| @ -63,7 +55,6 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(WithVersion(AKElement | |||||||
|     // connection, and removing them before disconnection. |     // connection, and removing them before disconnection. | ||||||
|  |  | ||||||
|     disconnectedCallback() { |     disconnectedCallback() { | ||||||
|         window.removeEventListener(EVENT_SIDEBAR_TOGGLE, this.toggleOpen); |  | ||||||
|         window.removeEventListener("resize", this.checkWidth); |         window.removeEventListener("resize", this.checkWidth); | ||||||
|         super.disconnectedCallback(); |         super.disconnectedCallback(); | ||||||
|     } |     } | ||||||
| @ -71,8 +62,9 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(WithVersion(AKElement | |||||||
|     render() { |     render() { | ||||||
|         return html` |         return html` | ||||||
|             <ak-sidebar |             <ak-sidebar | ||||||
|                 class="pf-c-page__sidebar ${this.open ? "pf-m-expanded" : "pf-m-collapsed"} ${this |                 class="pf-c-page__sidebar | ||||||
|                     .activeTheme === UiThemeEnum.Light |                 ${this.open ? "pf-m-expanded" : "pf-m-collapsed"} ${this.activeTheme === | ||||||
|  |                 UiThemeEnum.Light | ||||||
|                     ? "pf-m-light" |                     ? "pf-m-light" | ||||||
|                     : ""}" |                     : ""}" | ||||||
|             > |             > | ||||||
| @ -81,19 +73,6 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(WithVersion(AKElement | |||||||
|         `; |         `; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     updated() { |  | ||||||
|         // This is permissible as`:host.classList` is not one of the properties Lit uses as a |  | ||||||
|         // scheduling trigger. This sort of shenanigans can trigger an loop, in that it will trigger |  | ||||||
|         // a browser reflow, which may trigger some other styling the application is monitoring, |  | ||||||
|         // triggering a re-render which triggers a browser reflow, ad infinitum. But we've been |  | ||||||
|         // living with that since jQuery, and it's both well-known and fortunately rare. |  | ||||||
|  |  | ||||||
|         // eslint-disable-next-line wc/no-self-class |  | ||||||
|         this.classList.remove("pf-m-expanded", "pf-m-collapsed"); |  | ||||||
|         // eslint-disable-next-line wc/no-self-class |  | ||||||
|         this.classList.add(this.open ? "pf-m-expanded" : "pf-m-collapsed"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     renderSidebarItems(): TemplateResult { |     renderSidebarItems(): TemplateResult { | ||||||
|         // The second attribute type is of string[] to help with the 'activeWhen' control, which was |         // The second attribute type is of string[] to help with the 'activeWhen' control, which was | ||||||
|         // commonplace and singular enough to merit its own handler. |         // commonplace and singular enough to merit its own handler. | ||||||
|  | |||||||
| @ -94,10 +94,13 @@ export class AdminOverviewPage extends AdminOverviewBase { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     render(): TemplateResult { |     render(): TemplateResult { | ||||||
|         const name = this.user?.user.name ?? this.user?.user.username; |         const username = this.user?.user.name || this.user?.user.username; | ||||||
|  |  | ||||||
|         return html`<ak-page-header description=${msg("General system status")} ?hasIcon=${false}> |         return html` <ak-page-header | ||||||
|                 <span slot="header"> ${msg(str`Welcome, ${name || ""}.`)} </span> |                 header=${msg(str`Welcome, ${username || ""}.`)} | ||||||
|  |                 description=${msg("General system status")} | ||||||
|  |                 ?hasIcon=${false} | ||||||
|  |             > | ||||||
|             </ak-page-header> |             </ak-page-header> | ||||||
|             <section class="pf-c-page__main-section"> |             <section class="pf-c-page__main-section"> | ||||||
|                 <div class="pf-l-grid pf-m-gutter"> |                 <div class="pf-l-grid pf-m-gutter"> | ||||||
|  | |||||||
| @ -83,13 +83,10 @@ export class AdminSettingsPage extends AKElement { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     render() { |     render() { | ||||||
|         if (!this.settings) { |         if (!this.settings) return nothing; | ||||||
|             return nothing; |  | ||||||
|         } |  | ||||||
|         return html` |         return html` | ||||||
|             <ak-page-header icon="fa fa-cog" header="" description=""> |             <ak-page-header icon="fa fa-cog" header="${msg("System settings")}"> </ak-page-header> | ||||||
|                 <span slot="header"> ${msg("System settings")} </span> |  | ||||||
|             </ak-page-header> |  | ||||||
|             <section class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter"> |             <section class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter"> | ||||||
|                 <div class="pf-c-card"> |                 <div class="pf-c-card"> | ||||||
|                     <div class="pf-c-card__body"> |                     <div class="pf-c-card__body"> | ||||||
|  | |||||||
| @ -17,6 +17,13 @@ | |||||||
|  |  | ||||||
|     /* Minimum width after which the sidebar becomes automatic */ |     /* Minimum width after which the sidebar becomes automatic */ | ||||||
|     --ak-sidebar--minimum-auto-width: 80rem; |     --ak-sidebar--minimum-auto-width: 80rem; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The height of the navbar and branded sidebar. | ||||||
|  |      * @todo This shouldn't be necessary. The sidebar can instead use a grid layout | ||||||
|  |      * ensuring they share the same height. | ||||||
|  |      */ | ||||||
|  |     --ak-navbar--height: 7rem; | ||||||
| } | } | ||||||
|  |  | ||||||
| @supports selector(::-webkit-scrollbar) { | @supports selector(::-webkit-scrollbar) { | ||||||
|  | |||||||
| @ -67,6 +67,12 @@ export class NavigationButtons extends AKElement { | |||||||
|                 :host([theme="light"]) .pf-c-page__header-tools-group .pf-c-button { |                 :host([theme="light"]) .pf-c-page__header-tools-group .pf-c-button { | ||||||
|                     color: var(--ak-global--Color--100) !important; |                     color: var(--ak-global--Color--100) !important; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |                 @media (max-width: 768px) { | ||||||
|  |                     .pf-c-avatar { | ||||||
|  |                         display: none; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             `, |             `, | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
| @ -156,9 +162,7 @@ export class NavigationButtons extends AKElement { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     renderImpersonation() { |     renderImpersonation() { | ||||||
|         if (!this.me?.original) { |         if (!this.me?.original) return nothing; | ||||||
|             return nothing; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         const onClick = async () => { |         const onClick = async () => { | ||||||
|             await new CoreApi(DEFAULT_CONFIG).coreUsersImpersonateEndRetrieve(); |             await new CoreApi(DEFAULT_CONFIG).coreUsersImpersonateEndRetrieve(); | ||||||
| @ -175,6 +179,14 @@ export class NavigationButtons extends AKElement { | |||||||
|             </div>`; |             </div>`; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     renderAvatar() { | ||||||
|  |         return html`<img | ||||||
|  |             class="pf-c-avatar" | ||||||
|  |             src=${ifDefined(this.me?.user.avatar)} | ||||||
|  |             alt="${msg("Avatar image")}" | ||||||
|  |         />`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     get userDisplayName() { |     get userDisplayName() { | ||||||
|         return match<UserDisplay | undefined, string | undefined>(this.uiConfig?.navbar.userDisplay) |         return match<UserDisplay | undefined, string | undefined>(this.uiConfig?.navbar.userDisplay) | ||||||
|             .with(UserDisplay.username, () => this.me?.user.username) |             .with(UserDisplay.username, () => this.me?.user.username) | ||||||
| @ -212,11 +224,7 @@ export class NavigationButtons extends AKElement { | |||||||
|                       </div> |                       </div> | ||||||
|                   </div>` |                   </div>` | ||||||
|                 : nothing} |                 : nothing} | ||||||
|             <img |             ${this.renderAvatar()} | ||||||
|                 class="pf-c-avatar" |  | ||||||
|                 src=${ifDefined(this.me?.user.avatar)} |  | ||||||
|                 alt="${msg("Avatar image")}" |  | ||||||
|             /> |  | ||||||
|         </div>`; |         </div>`; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,15 +10,18 @@ import { me } from "@goauthentik/common/users"; | |||||||
| import "@goauthentik/components/ak-nav-buttons"; | import "@goauthentik/components/ak-nav-buttons"; | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider"; | import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider"; | ||||||
|  | import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand"; | ||||||
|  | import { themeImage } from "@goauthentik/elements/utils/images"; | ||||||
| import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; | import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; | ||||||
|  |  | ||||||
| import { msg } from "@lit/localize"; | import { msg } from "@lit/localize"; | ||||||
| import { CSSResult, TemplateResult, css, html, nothing } from "lit"; | import { CSSResult, LitElement, TemplateResult, css, html, nothing } from "lit"; | ||||||
| import { customElement, property, state } from "lit/decorators.js"; | import { customElement, property, state } from "lit/decorators.js"; | ||||||
|  |  | ||||||
| import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css"; | import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css"; | ||||||
| import PFButton from "@patternfly/patternfly/components/Button/button.css"; | import PFButton from "@patternfly/patternfly/components/Button/button.css"; | ||||||
| import PFContent from "@patternfly/patternfly/components/Content/content.css"; | import PFContent from "@patternfly/patternfly/components/Content/content.css"; | ||||||
|  | import PFDrawer from "@patternfly/patternfly/components/Drawer/drawer.css"; | ||||||
| import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css"; | import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css"; | ||||||
| import PFNotificationBadge from "@patternfly/patternfly/components/NotificationBadge/notification-badge.css"; | import PFNotificationBadge from "@patternfly/patternfly/components/NotificationBadge/notification-badge.css"; | ||||||
| import PFPage from "@patternfly/patternfly/components/Page/page.css"; | import PFPage from "@patternfly/patternfly/components/Page/page.css"; | ||||||
| @ -26,34 +29,52 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; | |||||||
|  |  | ||||||
| import { SessionUser } from "@goauthentik/api"; | import { SessionUser } from "@goauthentik/api"; | ||||||
|  |  | ||||||
| @customElement("ak-page-header") | //#region Page Navbar | ||||||
| export class PageHeader extends WithBrandConfig(AKElement) { |  | ||||||
|     @property() |  | ||||||
|     icon?: string; |  | ||||||
|  |  | ||||||
|     @property({ type: Boolean }) | export interface PageNavbarDetails { | ||||||
|     iconImage = false; |     header?: string; | ||||||
|  |  | ||||||
|     @property() |  | ||||||
|     header = ""; |  | ||||||
|  |  | ||||||
|     @property() |  | ||||||
|     description?: string; |     description?: string; | ||||||
|  |     icon?: string; | ||||||
|  |     iconImage?: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|     @property({ type: Boolean }) | /** | ||||||
|     hasIcon = true; |  * A global navbar component at the top of the page. | ||||||
|  |  * | ||||||
|  |  * Internally, this component listens for the `ak-page-header` event, which is | ||||||
|  |  * dispatched by the `ak-page-header` component. | ||||||
|  |  */ | ||||||
|  | @customElement("ak-page-navbar") | ||||||
|  | export class AKPageNavbar extends WithBrandConfig(AKElement) implements PageNavbarDetails { | ||||||
|  |     //#region Static Properties | ||||||
|  |  | ||||||
|     @state() |     private static elementRef: AKPageNavbar | null = null; | ||||||
|     me?: SessionUser; |  | ||||||
|  |  | ||||||
|     @state() |     static readonly setNavbarDetails = (detail: Partial<PageNavbarDetails>): void => { | ||||||
|     uiConfig!: UIConfig; |         const { elementRef } = AKPageNavbar; | ||||||
|  |         if (!elementRef) { | ||||||
|  |             console.debug( | ||||||
|  |                 `ak-page-header: Could not find ak-page-navbar, skipping event dispatch.`, | ||||||
|  |             ); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const { header, description, icon, iconImage } = detail; | ||||||
|  |  | ||||||
|  |         elementRef.header = header; | ||||||
|  |         elementRef.description = description; | ||||||
|  |         elementRef.icon = icon; | ||||||
|  |         elementRef.iconImage = iconImage || false; | ||||||
|  |         elementRef.hasIcon = !!icon; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     static get styles(): CSSResult[] { |     static get styles(): CSSResult[] { | ||||||
|         return [ |         return [ | ||||||
|             PFBase, |             PFBase, | ||||||
|             PFButton, |             PFButton, | ||||||
|             PFPage, |             PFPage, | ||||||
|  |             PFDrawer, | ||||||
|  |  | ||||||
|             PFNotificationBadge, |             PFNotificationBadge, | ||||||
|             PFContent, |             PFContent, | ||||||
|             PFAvatar, |             PFAvatar, | ||||||
| @ -63,55 +84,212 @@ export class PageHeader extends WithBrandConfig(AKElement) { | |||||||
|                     position: sticky; |                     position: sticky; | ||||||
|                     top: 0; |                     top: 0; | ||||||
|                     z-index: var(--pf-global--ZIndex--lg); |                     z-index: var(--pf-global--ZIndex--lg); | ||||||
|  |                     --pf-c-page__header-tools--MarginRight: 0; | ||||||
|  |                     --ak-brand-logo-height: var(--pf-global--FontSize--4xl, 2.25rem); | ||||||
|  |                     --ak-brand-background-color: var( | ||||||
|  |                         --pf-c-page__sidebar--m-light--BackgroundColor | ||||||
|  |                     ); | ||||||
|                 } |                 } | ||||||
|                 .bar { |  | ||||||
|  |                 :host([theme="dark"]) { | ||||||
|  |                     --ak-brand-background-color: var(--pf-c-page__sidebar--BackgroundColor); | ||||||
|  |                     --pf-c-page__sidebar--BackgroundColor: var(--ak-dark-background-light); | ||||||
|  |                     color: var(--ak-dark-foreground); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 navbar { | ||||||
|                     border-bottom: var(--pf-global--BorderWidth--sm); |                     border-bottom: var(--pf-global--BorderWidth--sm); | ||||||
|                     border-bottom-style: solid; |                     border-bottom-style: solid; | ||||||
|                     border-bottom-color: var(--pf-global--BorderColor--100); |                     border-bottom-color: var(--pf-global--BorderColor--100); | ||||||
|  |                     background-color: var(--pf-c-page--BackgroundColor); | ||||||
|  |  | ||||||
|                     display: flex; |                     display: flex; | ||||||
|                     flex-direction: row; |                     flex-direction: row; | ||||||
|                     min-height: 114px; |                     min-height: 6rem; | ||||||
|                     max-height: 114px; |  | ||||||
|                     background-color: var(--pf-c-page--BackgroundColor); |                     display: grid; | ||||||
|  |                     row-gap: var(--pf-global--spacer--sm); | ||||||
|  |                     column-gap: var(--pf-global--spacer--sm); | ||||||
|  |                     grid-template-columns: [brand] auto [toggle] auto [primary] 1fr [secondary] auto; | ||||||
|  |                     grid-template-rows: auto auto; | ||||||
|  |                     grid-template-areas: | ||||||
|  |                         "brand toggle primary secondary" | ||||||
|  |                         "brand toggle description secondary"; | ||||||
|  |  | ||||||
|  |                     @media (max-width: 768px) { | ||||||
|  |                         row-gap: var(--pf-global--spacer--xs); | ||||||
|  |  | ||||||
|  |                         align-items: center; | ||||||
|  |                         grid-template-areas: | ||||||
|  |                             "toggle primary secondary" | ||||||
|  |                             "toggle description description"; | ||||||
|  |                         justify-content: space-between; | ||||||
|  |                         width: 100%; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 .pf-c-page__main-section.pf-m-light { |  | ||||||
|                     background-color: transparent; |                 .items { | ||||||
|  |                     display: block; | ||||||
|  |  | ||||||
|  |                     &.primary { | ||||||
|  |                         grid-column: primary; | ||||||
|  |                         grid-row: primary / description; | ||||||
|  |  | ||||||
|  |                         align-content: center; | ||||||
|  |                         padding-block: var(--pf-global--spacer--md); | ||||||
|  |  | ||||||
|  |                         @media (min-width: 426px) { | ||||||
|  |                             &.block-sibling { | ||||||
|  |                                 padding-block-end: 0; | ||||||
|  |                                 grid-row: primary; | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                         @media (max-width: 768px) { | ||||||
|  |                             padding-block: var(--pf-global--spacer--sm); | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                         .accent-icon { | ||||||
|  |                             height: 1em; | ||||||
|  |                             width: 1em; | ||||||
|  |  | ||||||
|  |                             @media (max-width: 768px) { | ||||||
|  |                                 display: none; | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     &.page-description { | ||||||
|  |                         grid-area: description; | ||||||
|  |                         padding-block-end: var(--pf-global--spacer--md); | ||||||
|  |  | ||||||
|  |                         @media (max-width: 425px) { | ||||||
|  |                             display: none; | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                         @media (min-width: 769px) { | ||||||
|  |                             text-wrap: balance; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     &.secondary { | ||||||
|  |                         grid-area: secondary; | ||||||
|  |                         flex: 0 0 auto; | ||||||
|  |                         justify-self: end; | ||||||
|  |                         padding-block: var(--pf-global--spacer--sm); | ||||||
|  |                         padding-inline-end: var(--pf-global--spacer--sm); | ||||||
|  |  | ||||||
|  |                         @media (min-width: 769px) { | ||||||
|  |                             align-content: center; | ||||||
|  |                             padding-block: var(--pf-global--spacer--md); | ||||||
|  |                             padding-inline-end: var(--pf-global--spacer--xl); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 .pf-c-page__main-section { |  | ||||||
|                     flex-grow: 1; |                 .brand { | ||||||
|                     flex-shrink: 1; |                     grid-area: brand; | ||||||
|  |                     background-color: var(--ak-brand-background-color); | ||||||
|  |                     height: 100%; | ||||||
|  |                     width: var(--pf-c-page__sidebar--Width); | ||||||
|  |                     align-items: center; | ||||||
|  |                     padding-inline: var(--pf-global--spacer--sm); | ||||||
|  |  | ||||||
|                     display: flex; |                     display: flex; | ||||||
|                     flex-direction: column; |  | ||||||
|                     justify-content: center; |                     justify-content: center; | ||||||
|  |  | ||||||
|  |                     &.pf-m-collapsed { | ||||||
|  |                         display: none; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     @media (max-width: 1279px) { | ||||||
|  |                         display: none; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|                 img.pf-icon { |  | ||||||
|                     max-height: 24px; |                 .sidebar-trigger { | ||||||
|  |                     grid-area: toggle; | ||||||
|  |                     height: 100%; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |                 .logo { | ||||||
|  |                     flex: 0 0 auto; | ||||||
|  |                     height: var(--ak-brand-logo-height); | ||||||
|  |  | ||||||
|  |                     & img { | ||||||
|  |                         height: 100%; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 .sidebar-trigger, |                 .sidebar-trigger, | ||||||
|                 .notification-trigger { |                 .notification-trigger { | ||||||
|                     font-size: 24px; |                     font-size: 1.5rem; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 .notification-trigger.has-notifications { |                 .notification-trigger.has-notifications { | ||||||
|                     color: var(--pf-global--active-color--100); |                     color: var(--pf-global--active-color--100); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |                 .page-title { | ||||||
|  |                     display: flex; | ||||||
|  |                     gap: var(--pf-global--spacer--xs); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 h1 { |                 h1 { | ||||||
|                     display: flex; |                     display: flex; | ||||||
|                     flex-direction: row; |                     flex-direction: row; | ||||||
|                     align-items: center !important; |                     align-items: center !important; | ||||||
|                 } |                 } | ||||||
|                 .pf-c-page__header-tools { |  | ||||||
|                     flex-shrink: 0; |  | ||||||
|                 } |  | ||||||
|                 .pf-c-page__header-tools-group { |  | ||||||
|                     height: 100%; |  | ||||||
|                 } |  | ||||||
|                 :host([theme="dark"]) .pf-c-page__header-tools { |  | ||||||
|                     color: var(--ak-dark-foreground) !important; |  | ||||||
|                 } |  | ||||||
|             `, |             `, | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#region Properties | ||||||
|  |  | ||||||
|  |     @property({ type: String }) | ||||||
|  |     icon?: string; | ||||||
|  |  | ||||||
|  |     @property({ type: Boolean }) | ||||||
|  |     iconImage = false; | ||||||
|  |  | ||||||
|  |     @property({ type: String }) | ||||||
|  |     header?: string; | ||||||
|  |  | ||||||
|  |     @property({ type: String }) | ||||||
|  |     description?: string; | ||||||
|  |  | ||||||
|  |     @property({ type: Boolean }) | ||||||
|  |     hasIcon = true; | ||||||
|  |  | ||||||
|  |     @property({ type: Boolean }) | ||||||
|  |     open = true; | ||||||
|  |  | ||||||
|  |     @state() | ||||||
|  |     me?: SessionUser; | ||||||
|  |  | ||||||
|  |     @state() | ||||||
|  |     uiConfig!: UIConfig; | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  |     //#region Methods | ||||||
|  |  | ||||||
|  |     #toggleSidebar() { | ||||||
|  |         this.open = !this.open; | ||||||
|  |  | ||||||
|  |         this.dispatchEvent( | ||||||
|  |             new CustomEvent(EVENT_SIDEBAR_TOGGLE, { | ||||||
|  |                 bubbles: true, | ||||||
|  |                 composed: true, | ||||||
|  |             }), | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#region Constructor | ||||||
|  |  | ||||||
|     constructor() { |     constructor() { | ||||||
|         super(); |         super(); | ||||||
|         window.addEventListener(EVENT_WS_MESSAGE, () => { |         window.addEventListener(EVENT_WS_MESSAGE, () => { | ||||||
| @ -119,13 +297,23 @@ export class PageHeader extends WithBrandConfig(AKElement) { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async firstUpdated() { |     connectedCallback(): void { | ||||||
|  |         super.connectedCallback(); | ||||||
|  |         AKPageNavbar.elementRef = this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     disconnectedCallback(): void { | ||||||
|  |         super.disconnectedCallback(); | ||||||
|  |         AKPageNavbar.elementRef = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async firstUpdated() { | ||||||
|         this.me = await me(); |         this.me = await me(); | ||||||
|         this.uiConfig = await uiConfig(); |         this.uiConfig = await uiConfig(); | ||||||
|         this.uiConfig.navbar.userDisplay = UserDisplay.none; |         this.uiConfig.navbar.userDisplay = UserDisplay.none; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setTitle(header?: string) { |     #setTitle(header?: string) { | ||||||
|         const currentIf = currentInterface(); |         const currentIf = currentInterface(); | ||||||
|         let title = this.brand?.brandingTitle || TITLE_DEFAULT; |         let title = this.brand?.brandingTitle || TITLE_DEFAULT; | ||||||
|         if (currentIf === "admin") { |         if (currentIf === "admin") { | ||||||
| @ -141,65 +329,146 @@ export class PageHeader extends WithBrandConfig(AKElement) { | |||||||
|     willUpdate() { |     willUpdate() { | ||||||
|         // Always update title, even if there's no header value set, |         // Always update title, even if there's no header value set, | ||||||
|         // as in that case we still need to return to the generic title |         // as in that case we still need to return to the generic title | ||||||
|         this.setTitle(this.header); |         this.#setTitle(this.header); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     //#region Render | ||||||
|  |  | ||||||
|     renderIcon() { |     renderIcon() { | ||||||
|         if (this.icon) { |         if (this.icon) { | ||||||
|             if (this.iconImage && !this.icon.startsWith("fa://")) { |             if (this.iconImage && !this.icon.startsWith("fa://")) { | ||||||
|                 return html`<img class="pf-icon" src="${this.icon}" alt="page icon" />`; |                 return html`<img class="accent-icon pf-icon" src="${this.icon}" alt="page icon" />`; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             const icon = this.icon.replaceAll("fa://", "fa "); |             const icon = this.icon.replaceAll("fa://", "fa "); | ||||||
|             return html`<i class=${icon}></i>`; |  | ||||||
|  |             return html`<i class="accent-icon ${icon}"></i>`; | ||||||
|         } |         } | ||||||
|         return nothing; |         return nothing; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     render(): TemplateResult { |     render(): TemplateResult { | ||||||
|         return html`<div class="bar"> |         return html`<navbar aria-label="Main" class="navbar"> | ||||||
|             <button |                 <aside class="brand ${this.open ? "" : "pf-m-collapsed"}"> | ||||||
|                 class="sidebar-trigger pf-c-button pf-m-plain" |                     <a href="#/"> | ||||||
|                 @click=${() => { |                         <div class="logo"> | ||||||
|                     this.dispatchEvent( |                             <img | ||||||
|                         new CustomEvent(EVENT_SIDEBAR_TOGGLE, { |                                 src=${themeImage( | ||||||
|                             bubbles: true, |                                     this.brand?.brandingLogo ?? DefaultBrand.brandingLogo, | ||||||
|                             composed: true, |                                 )} | ||||||
|                         }), |                                 alt="${msg("authentik Logo")}" | ||||||
|                     ); |                                 loading="lazy" | ||||||
|                 }} |                             /> | ||||||
|             > |                         </div> | ||||||
|                 <i class="fas fa-bars"></i> |                     </a> | ||||||
|             </button> |                 </aside> | ||||||
|             <section class="pf-c-page__main-section pf-m-light"> |                 <button | ||||||
|                 <div class="pf-c-content"> |                     class="sidebar-trigger pf-c-button pf-m-plain" | ||||||
|                     <h1> |                     @click=${this.#toggleSidebar} | ||||||
|  |                     aria-label=${msg("Toggle sidebar")} | ||||||
|  |                     aria-expanded=${this.open ? "true" : "false"} | ||||||
|  |                 > | ||||||
|  |                     <i class="fas fa-bars"></i> | ||||||
|  |                 </button> | ||||||
|  |  | ||||||
|  |                 <section | ||||||
|  |                     class="items primary pf-c-content ${this.description ? "block-sibling" : ""}" | ||||||
|  |                 > | ||||||
|  |                     <h1 class="page-title"> | ||||||
|                         ${this.hasIcon |                         ${this.hasIcon | ||||||
|                             ? html`<slot name="icon">${this.renderIcon()}</slot> ` |                             ? html`<slot name="icon">${this.renderIcon()}</slot>` | ||||||
|                             : nothing} |                             : nothing} | ||||||
|                         <slot name="header">${this.header}</slot> |                         ${this.header} | ||||||
|                     </h1> |                     </h1> | ||||||
|                     ${this.description ? html`<p>${this.description}</p>` : html``} |                 </section> | ||||||
|                 </div> |                 ${this.description | ||||||
|             </section> |                     ? html`<section class="items page-description pf-c-content"> | ||||||
|             <div class="pf-c-page__header-tools"> |                           <p>${this.description}</p> | ||||||
|                 <div class="pf-c-page__header-tools-group"> |                       </section>` | ||||||
|                     <ak-nav-buttons .uiConfig=${this.uiConfig} .me=${this.me}> |                     : nothing} | ||||||
|                         <a |  | ||||||
|                             class="pf-c-button pf-m-secondary pf-m-small pf-u-display-none pf-u-display-block-on-md" |                 <section class="items secondary"> | ||||||
|                             href="${globalAK().api.base}if/user/" |                     <div class="pf-c-page__header-tools-group"> | ||||||
|                             slot="extra" |                         <ak-nav-buttons .uiConfig=${this.uiConfig} .me=${this.me}> | ||||||
|                         > |                             <a | ||||||
|                             ${msg("User interface")} |                                 class="pf-c-button pf-m-secondary pf-m-small pf-u-display-none pf-u-display-block-on-md" | ||||||
|                         </a> |                                 href="${globalAK().api.base}if/user/" | ||||||
|                     </ak-nav-buttons> |                                 slot="extra" | ||||||
|                 </div> |                             > | ||||||
|             </div> |                                 ${msg("User interface")} | ||||||
|         </div>`; |                             </a> | ||||||
|  |                         </ak-nav-buttons> | ||||||
|  |                     </div> | ||||||
|  |                 </section> | ||||||
|  |             </navbar> | ||||||
|  |             <slot></slot>`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //#endregion | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //#endregion | ||||||
|  |  | ||||||
|  | //#region Page Header | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A page header component, used to display the page title and description. | ||||||
|  |  * | ||||||
|  |  * Internally, this component dispatches the `ak-page-header` event, which is | ||||||
|  |  * listened to by the `ak-page-navbar` component. | ||||||
|  |  * | ||||||
|  |  * @singleton | ||||||
|  |  */ | ||||||
|  | @customElement("ak-page-header") | ||||||
|  | export class AKPageHeader extends LitElement implements PageNavbarDetails { | ||||||
|  |     @property({ type: String }) | ||||||
|  |     header?: string; | ||||||
|  |  | ||||||
|  |     @property({ type: String }) | ||||||
|  |     description?: string; | ||||||
|  |  | ||||||
|  |     @property({ type: String }) | ||||||
|  |     icon?: string; | ||||||
|  |  | ||||||
|  |     @property({ type: Boolean }) | ||||||
|  |     iconImage = false; | ||||||
|  |  | ||||||
|  |     static get styles(): CSSResult[] { | ||||||
|  |         return [ | ||||||
|  |             css` | ||||||
|  |                 :host { | ||||||
|  |                     display: none; | ||||||
|  |                 } | ||||||
|  |             `, | ||||||
|  |         ]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     connectedCallback(): void { | ||||||
|  |         super.connectedCallback(); | ||||||
|  |  | ||||||
|  |         AKPageNavbar.setNavbarDetails({ | ||||||
|  |             header: this.header, | ||||||
|  |             description: this.description, | ||||||
|  |             icon: this.icon, | ||||||
|  |             iconImage: this.iconImage, | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     updated(): void { | ||||||
|  |         AKPageNavbar.setNavbarDetails({ | ||||||
|  |             header: this.header, | ||||||
|  |             description: this.description, | ||||||
|  |             icon: this.icon, | ||||||
|  |             iconImage: this.iconImage, | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //#endregion | ||||||
|  |  | ||||||
| declare global { | declare global { | ||||||
|     interface HTMLElementTagNameMap { |     interface HTMLElementTagNameMap { | ||||||
|         "ak-page-header": PageHeader; |         "ak-page-header": AKPageHeader; | ||||||
|  |         "ak-page-navbar": AKPageNavbar; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -35,10 +35,7 @@ export class Sidebar extends AKElement { | |||||||
|                 .pf-c-nav__section + .pf-c-nav__section { |                 .pf-c-nav__section + .pf-c-nav__section { | ||||||
|                     --pf-c-nav__section--section--MarginTop: var(--pf-global--spacer--sm); |                     --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 { |                 nav { | ||||||
|                     display: flex; |                     display: flex; | ||||||
|                     flex-direction: column; |                     flex-direction: column; | ||||||
| @ -70,7 +67,6 @@ export class Sidebar extends AKElement { | |||||||
|             class="pf-c-nav ${this.activeTheme === UiThemeEnum.Light ? "pf-m-light" : ""}" |             class="pf-c-nav ${this.activeTheme === UiThemeEnum.Light ? "pf-m-light" : ""}" | ||||||
|             aria-label=${msg("Global")} |             aria-label=${msg("Global")} | ||||||
|         > |         > | ||||||
|             <ak-sidebar-brand></ak-sidebar-brand> |  | ||||||
|             <ul class="pf-c-nav__list"> |             <ul class="pf-c-nav__list"> | ||||||
|                 <slot></slot> |                 <slot></slot> | ||||||
|             </ul> |             </ul> | ||||||
|  | |||||||
| @ -1,4 +1,3 @@ | |||||||
| import { EVENT_SIDEBAR_TOGGLE } from "@goauthentik/common/constants"; |  | ||||||
| import { AKElement } from "@goauthentik/elements/Base"; | import { AKElement } from "@goauthentik/elements/Base"; | ||||||
| import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider"; | import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider"; | ||||||
| import { themeImage } from "@goauthentik/elements/utils/images"; | import { themeImage } from "@goauthentik/elements/utils/images"; | ||||||
| @ -42,22 +41,16 @@ export class SidebarBrand extends WithBrandConfig(AKElement) { | |||||||
|                     display: flex; |                     display: flex; | ||||||
|                     flex-direction: row; |                     flex-direction: row; | ||||||
|                     align-items: center; |                     align-items: center; | ||||||
|                     height: 114px; |                     height: var(--ak-navbar-height); | ||||||
|                     min-height: 114px; |  | ||||||
|                     border-bottom: var(--pf-global--BorderWidth--sm); |                     border-bottom: var(--pf-global--BorderWidth--sm); | ||||||
|                     border-bottom-style: solid; |                     border-bottom-style: solid; | ||||||
|                     border-bottom-color: var(--pf-global--BorderColor--100); |                     border-bottom-color: var(--pf-global--BorderColor--100); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 .pf-c-brand img { |                 .pf-c-brand img { | ||||||
|                     padding: 0 0.5rem; |                     padding: 0 0.5rem; | ||||||
|                     height: 42px; |                     height: 42px; | ||||||
|                 } |                 } | ||||||
|                 button.pf-c-button.sidebar-trigger { |  | ||||||
|                     background-color: transparent; |  | ||||||
|                     border-radius: 0px; |  | ||||||
|                     height: 100%; |  | ||||||
|                     color: var(--ak-dark-foreground); |  | ||||||
|                 } |  | ||||||
|             `, |             `, | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
| @ -70,32 +63,15 @@ export class SidebarBrand extends WithBrandConfig(AKElement) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     render(): TemplateResult { |     render(): TemplateResult { | ||||||
|         return html` ${window.innerWidth <= MIN_WIDTH |         return html` <a href="#/" class="pf-c-page__header-brand-link"> | ||||||
|                 ? html` |             <div class="pf-c-brand ak-brand"> | ||||||
|                       <button |                 <img | ||||||
|                           class="sidebar-trigger pf-c-button" |                     src=${themeImage(this.brand?.brandingLogo ?? DefaultBrand.brandingLogo)} | ||||||
|                           @click=${() => { |                     alt="${msg("authentik Logo")}" | ||||||
|                               this.dispatchEvent( |                     loading="lazy" | ||||||
|                                   new CustomEvent(EVENT_SIDEBAR_TOGGLE, { |                 /> | ||||||
|                                       bubbles: true, |             </div> | ||||||
|                                       composed: true, |         </a>`; | ||||||
|                                   }), |  | ||||||
|                               ); |  | ||||||
|                           }} |  | ||||||
|                       > |  | ||||||
|                           <i class="fas fa-bars"></i> |  | ||||||
|                       </button> |  | ||||||
|                   ` |  | ||||||
|                 : html``} |  | ||||||
|             <a href="#/" class="pf-c-page__header-brand-link"> |  | ||||||
|                 <div class="pf-c-brand ak-brand"> |  | ||||||
|                     <img |  | ||||||
|                         src=${themeImage(this.brand?.brandingLogo ?? DefaultBrand.brandingLogo)} |  | ||||||
|                         alt="${msg("authentik Logo")}" |  | ||||||
|                         loading="lazy" |  | ||||||
|                     /> |  | ||||||
|                 </div> |  | ||||||
|             </a>`; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	