web: fix theme not applying to document correctly (#10721)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L.
2024-08-01 15:08:09 +02:00
committed by GitHub
parent 63ff967d79
commit bd8d35bf3f
2 changed files with 27 additions and 12 deletions

View File

@ -126,7 +126,7 @@ export class AKElement extends LitElement {
ev?.matches || this._mediaMatcher?.matches ev?.matches || this._mediaMatcher?.matches
? UiThemeEnum.Light ? UiThemeEnum.Light
: UiThemeEnum.Dark; : UiThemeEnum.Dark;
this._activateTheme(root, theme); this._activateTheme(theme, root);
}; };
this._mediaMatcherHandler(undefined); this._mediaMatcherHandler(undefined);
this._mediaMatcher.addEventListener("change", this._mediaMatcherHandler); this._mediaMatcher.addEventListener("change", this._mediaMatcherHandler);
@ -138,7 +138,7 @@ export class AKElement extends LitElement {
this._mediaMatcher.removeEventListener("change", this._mediaMatcherHandler); this._mediaMatcher.removeEventListener("change", this._mediaMatcherHandler);
this._mediaMatcher = undefined; this._mediaMatcher = undefined;
} }
this._activateTheme(root, theme); this._activateTheme(theme, root);
} }
static themeToStylesheet(theme?: UiThemeEnum): CSSStyleSheet | undefined { static themeToStylesheet(theme?: UiThemeEnum): CSSStyleSheet | undefined {
@ -148,7 +148,11 @@ export class AKElement extends LitElement {
return undefined; return undefined;
} }
_activateTheme(root: DocumentOrShadowRoot, theme: UiThemeEnum) { /**
* Directly activate a given theme, accepts multiple document/ShadowDOMs to apply the stylesheet
* to. The stylesheets are applied to each DOM in order. Does nothing if the given theme is already active.
*/
_activateTheme(theme: UiThemeEnum, ...roots: DocumentOrShadowRoot[]) {
if (theme === this._activeTheme) { if (theme === this._activeTheme) {
return; return;
} }
@ -163,12 +167,19 @@ export class AKElement extends LitElement {
this.setAttribute("theme", theme); this.setAttribute("theme", theme);
const stylesheet = AKElement.themeToStylesheet(theme); const stylesheet = AKElement.themeToStylesheet(theme);
const oldStylesheet = AKElement.themeToStylesheet(this._activeTheme); const oldStylesheet = AKElement.themeToStylesheet(this._activeTheme);
roots.forEach((root) => {
if (stylesheet) { if (stylesheet) {
root.adoptedStyleSheets = [...root.adoptedStyleSheets, ensureCSSStyleSheet(stylesheet)]; root.adoptedStyleSheets = [
...root.adoptedStyleSheets,
ensureCSSStyleSheet(stylesheet),
];
} }
if (oldStylesheet) { if (oldStylesheet) {
root.adoptedStyleSheets = root.adoptedStyleSheets.filter((v) => v !== oldStylesheet); root.adoptedStyleSheets = root.adoptedStyleSheets.filter(
(v) => v !== oldStylesheet,
);
} }
});
this._activeTheme = theme; this._activeTheme = theme;
this.requestUpdate(); this.requestUpdate();
} }

View File

@ -50,15 +50,19 @@ export class Interface extends AKElement implements AkInterface {
this.dataset.akInterfaceRoot = "true"; this.dataset.akInterfaceRoot = "true";
} }
_activateTheme(root: DocumentOrShadowRoot, theme: UiThemeEnum): void { _activateTheme(theme: UiThemeEnum, ...roots: DocumentOrShadowRoot[]): void {
if (theme === this._activeTheme) { if (theme === this._activeTheme) {
return; return;
} }
console.debug( console.debug(
`authentik/interface[${rootInterface()?.tagName.toLowerCase()}]: Enabling theme ${theme}`, `authentik/interface[${rootInterface()?.tagName.toLowerCase()}]: Enabling theme ${theme}`,
); );
super._activateTheme(document as unknown as DocumentOrShadowRoot, theme); // Special case for root interfaces, as they need to modify the global document CSS too
super._activateTheme(root, theme); // Instead of calling ._activateTheme() twice, we insert the root document in the call
// since multiple calls to ._activateTheme() would not do anything after the first call
// as the theme is already enabled.
roots.unshift(document as unknown as DocumentOrShadowRoot);
super._activateTheme(theme, ...roots);
} }
async getTheme(): Promise<UiThemeEnum> { async getTheme(): Promise<UiThemeEnum> {