Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions web/src/admin/AdminInterface/AboutModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { globalAK } from "#common/global";
import { ModalButton } from "#elements/buttons/ModalButton";
import { WithBrandConfig } from "#elements/mixins/branding";
import { WithLicenseSummary } from "#elements/mixins/license";
import { renderImage } from "#elements/utils/images";
import { ThemedImage } from "#elements/utils/images";

import { AdminApi, CapabilitiesEnum, LicenseSummaryStatusEnum } from "@goauthentik/api";

Expand Down Expand Up @@ -95,11 +95,12 @@ export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton))
aria-labelledby="modal-title"
>
<div class="pf-c-about-modal-box__brand">
${renderImage(
this.brandingFavicon,
msg("authentik Logo"),
"pf-c-about-modal-box__brand-image",
)}
${ThemedImage({
src: this.brandingFavicon,
alt: msg("authentik Logo"),
className: "pf-c-about-modal-box__brand-image",
theme: this.activeTheme,
})}
</div>
<div class="pf-c-about-modal-box__close">
<button class="pf-c-button pf-m-plain" type="button" @click=${this.close}>
Expand Down
2 changes: 1 addition & 1 deletion web/src/common/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ export function applyBackgroundImageProperty(
/**
* Returns the root interface element of the page.
*
* @todo Can this be handled with a Lit Mixin?
* @deprecated Use context controllers to access the interface root instead.
*/
export function rootInterface<T extends HTMLElement = HTMLElement>(): T {
const element = document.body.querySelector<T>("[data-test-id=interface-root]");
Expand Down
8 changes: 6 additions & 2 deletions web/src/components/ak-page-navbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { AKElement } from "#elements/Base";
import { WithBrandConfig } from "#elements/mixins/branding";
import { WithSession } from "#elements/mixins/session";
import { isAdminRoute } from "#elements/router/utils";
import { renderImage } from "#elements/utils/images";
import { ThemedImage } from "#elements/utils/images";

import { msg } from "@lit/localize";
import { css, CSSResult, html, nothing, TemplateResult } from "lit";
Expand Down Expand Up @@ -377,7 +377,11 @@ export class AKPageNavbar
<aside role="presentation" class="brand ${this.open ? "" : "pf-m-collapsed"}">
<a aria-label="${msg("Home")}" href="#/">
<div class="logo">
${renderImage(this.brandingLogo, msg("authentik Logo"), "")}
${ThemedImage({
src: this.brandingLogo,
alt: msg("authentik Logo"),
theme: this.activeTheme,
})}
</div>
</a>
</aside>
Expand Down
62 changes: 26 additions & 36 deletions web/src/elements/utils/images.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,48 @@
import { resolveUITheme, rootInterface } from "#common/theme";
import { ResolvedUITheme } from "#common/theme";

import type { AKElement } from "#elements/Base";
import type { SlottedTemplateResult } from "#elements/types";
import type { LitFC } from "#elements/types";
import { ifPresent } from "#elements/utils/attributes";

import { spread } from "@open-wc/lit-helpers";
import { ImgHTMLAttributes } from "react";

import { html, nothing } from "lit";

export const FontAwesomeProtocol = "fa://";

export function themeImage(rawPath: string) {
const enabledTheme = rootInterface<AKElement>()?.activeTheme || resolveUITheme();
export function themeImage(rawPath: string, theme: ResolvedUITheme) {
return rawPath.replaceAll("%(theme)s", theme);
}

return rawPath.replaceAll("%(theme)s", enabledTheme);
export interface ThemedImageProps extends ImgHTMLAttributes<HTMLImageElement> {
/**
* The image path, which can be:
* - A regular URL
* - A Font Awesome icon (fa://icon-name)
* - A themed image path with %(theme)s placeholder
*/
src: string;
theme: ResolvedUITheme;
}

/**
* Renders an image that can be a regular URL, Font Awesome icon (fa://), or themed image
*
* @param imagePath - URL, fa:// icon, or path with %(theme)s placeholder
* @param alt - Alt text for the image
* @param className - CSS classes to apply
* @returns TemplateResult with either <img> or <i> element
*/
export function renderImage(
imagePath: string,
alt?: string,
className?: string,
): SlottedTemplateResult {
if (!imagePath) {
export const ThemedImage: LitFC<ThemedImageProps> = ({ src, className, theme, ...props }) => {
if (!src) {
return nothing;
}

// Handle Font Awesome icons (same logic as ak-app-icon)
if (imagePath.startsWith(FontAwesomeProtocol)) {
const classes = [
className,
"font-awesome",
"fas",
imagePath.slice(FontAwesomeProtocol.length),
]
if (src.startsWith(FontAwesomeProtocol)) {
const classes = [className, "font-awesome", "fas", src.slice(FontAwesomeProtocol.length)]
.filter(Boolean)
.join(" ");
return html`<i
part="icon font-awesome"
role="img"
aria-label=${ifPresent(alt)}
class=${classes}
></i>`;

return html`<i part="icon font-awesome" role="img" class=${classes} ${spread(props)}></i>`;
}

const src = themeImage(imagePath);
const themedSrc = themeImage(src, theme);

return html`<img src=${src} alt=${ifPresent(alt)} class=${ifPresent(className)} />`;
}
return html`<img src=${themedSrc} class=${ifPresent(className)} ${spread(props)} />`;
};

export function isDefaultAvatar(path?: string | null): boolean {
return !!path?.endsWith("user_default.png");
Expand Down
9 changes: 7 additions & 2 deletions web/src/flow/FlowExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { WithBrandConfig } from "#elements/mixins/branding";
import { WithCapabilitiesConfig } from "#elements/mixins/capabilities";
import { LitPropertyRecord } from "#elements/types";
import { exportParts } from "#elements/utils/attributes";
import { renderImage } from "#elements/utils/images";
import { ThemedImage } from "#elements/utils/images";

import { AKFlowAdvanceEvent, AKFlowInspectorChangeEvent } from "#flow/events";
import { BaseStage, StageHost, SubmitOptions } from "#flow/stages/base";
Expand Down Expand Up @@ -489,7 +489,12 @@ export class FlowExecutor
part="main"
>
<div class="pf-c-login__main-header pf-c-brand" part="branding">
${renderImage(this.brandingLogo, msg("authentik Logo"), "branding-logo")}
${ThemedImage({
src: this.brandingLogo,
alt: msg("authentik Logo"),
className: "branding-logo",
theme: this.activeTheme,
})}
</div>
${this.loading && this.challenge
? html`<ak-loading-overlay></ak-loading-overlay>`
Expand Down
9 changes: 7 additions & 2 deletions web/src/standalone/api-browser/index.entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getCookie } from "#common/utils";

import { Interface } from "#elements/Interface";
import { WithBrandConfig } from "#elements/mixins/branding";
import { renderImage } from "#elements/utils/images";
import { ThemedImage } from "#elements/utils/images";

import { msg } from "@lit/localize";
import { CSSResult, html, TemplateResult } from "lit";
Expand Down Expand Up @@ -101,7 +101,12 @@ export class APIBrowser extends WithBrandConfig(Interface) {
show-method-in-nav-bar="as-colored-text"
>
<div slot="nav-logo">
${renderImage(this.brandingLogo, msg("authentik Logo"), "logo")}
${ThemedImage({
src: this.brandingLogo,
alt: msg("authentik Logo"),
className: "logo",
theme: this.activeTheme,
})}
</div>
</rapi-doc>
`;
Expand Down
3 changes: 1 addition & 2 deletions web/src/styles/authentik/components/Login/login.css
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,7 @@

.branding-logo {
display: block;
width: clamp(75%, calc(var(--ak-login--MaxWidth) / 2), 90%);
min-height: 4rem;
max-width: clamp(75%, calc(var(--ak-login--MaxWidth) / 2), 90%);
}

/* Ensure Font Awesome logos scale similarly to image logos */
Expand Down
9 changes: 7 additions & 2 deletions web/src/user/index.entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
renderNotificationDrawerPanel,
} from "#elements/notifications/utils";
import { ifPresent } from "#elements/utils/attributes";
import { renderImage } from "#elements/utils/images";
import { ThemedImage } from "#elements/utils/images";

import Styles from "#user/index.entrypoint.css";
import { ROUTES } from "#user/Routes";
Expand Down Expand Up @@ -150,7 +150,12 @@ class UserInterface extends WithBrandConfig(WithSession(AuthenticatedInterface))
<header part="page__header" class="pf-c-page__header">
<div part="brand" class="pf-c-page__header-brand">
<a href="#/" class="pf-c-page__header-brand-link">
${renderImage(this.brandingLogo, this.brandingTitle, "pf-c-brand")}
${ThemedImage({
src: this.brandingLogo,
alt: this.brandingTitle,
className: "pf-c-brand",
theme: this.activeTheme,
})}
</a>
</div>
<ak-nav-buttons>${this.renderAdminInterfaceLink()}</ak-nav-buttons>
Expand Down
Loading