diff --git a/modules/banner/element-web/src/Banner.tsx b/modules/banner/element-web/src/Banner.tsx index 27e9fae5b9..81193fbaa2 100644 --- a/modules/banner/element-web/src/Banner.tsx +++ b/modules/banner/element-web/src/Banner.tsx @@ -6,7 +6,7 @@ Please see LICENSE files in the repository root for full details. */ import { type FC } from "react"; -import styled, { ThemeProvider } from "styled-components"; +import styled from "styled-components"; import { type Api } from "@element-hq/element-web-module-api"; import { Heading } from "@vector-im/compound-web"; @@ -14,7 +14,6 @@ import { type ModuleConfig } from "./config"; import UniventionMenu from "./Univention/Menu"; import Menu from "./Menu"; import Logo from "./Logo.tsx"; -import { theme } from "./theme.ts"; const Root = styled.nav` height: ${({ theme }): string => theme.bannerHeight}; @@ -50,17 +49,15 @@ const Banner: FC = ({ api, logoUrl, href, menu }) => { } return ( - - - {menuJsx} - - - - - {api.config.get("brand")} - - - + + {menuJsx} + + + + + {api.config.get("brand")} + + ); }; diff --git a/modules/banner/element-web/src/config.ts b/modules/banner/element-web/src/config.ts index 8b6db1c122..1066a85bc2 100644 --- a/modules/banner/element-web/src/config.ts +++ b/modules/banner/element-web/src/config.ts @@ -5,7 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE files in the repository root for full details. */ -import { z } from "zod"; +import { z, ZodSchema, ZodTypeDef } from "zod"; + +import { Theme } from "./theme.ts"; const StaticConfig = z.object({ type: z.literal("static"), @@ -85,15 +87,25 @@ export const ModuleConfig = z.object({ */ logo_link_url: z.string().url(), + /** + * Configuration for the menu. + */ menu: z.discriminatedUnion("type", [StaticConfig, UniventionConfig]), + + /** + * Theme variable overrides, optional. + */ + theme: Theme.default({}), }); export type ModuleConfig = z.infer; +export type ConfigSchema = ZodSchema, ZodTypeDef, z.input>; + export const CONFIG_KEY = "io.element.element-web-modules.banner"; declare module "@element-hq/element-web-module-api" { export interface Config { - [CONFIG_KEY]: ModuleConfig; + [CONFIG_KEY]: ConfigSchema["_input"]; } } diff --git a/modules/banner/element-web/src/index.tsx b/modules/banner/element-web/src/index.tsx index 54dc3a0392..f6baa9c896 100644 --- a/modules/banner/element-web/src/index.tsx +++ b/modules/banner/element-web/src/index.tsx @@ -5,6 +5,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE files in the repository root for full details. */ +import { ThemeProvider } from "styled-components"; + import type { Module, Api, ModuleFactory } from "@element-hq/element-web-module-api"; import Translations from "./translations.json"; import { ModuleConfig, CONFIG_KEY } from "./config"; @@ -33,12 +35,14 @@ class BannerModule implements Module { const root = this.api.createRoot(div); root.render( - , + + + , ); } } diff --git a/modules/banner/element-web/src/theme.ts b/modules/banner/element-web/src/theme.ts index 80d2528418..aadc572c3f 100644 --- a/modules/banner/element-web/src/theme.ts +++ b/modules/banner/element-web/src/theme.ts @@ -5,26 +5,26 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE files in the repository root for full details. */ -const theme = { - textColor: "var(--cpd-color-text-primary)", - subheadingColor: "var(--cpd-color-text-secondary)", - bannerBackgroundColor: "var(--cpd-color-bg-canvas-default)", - bannerHeight: "60px", - triggerWidth: "68px", - triggerBackgroundColor: "var(--cpd-color-bg-subtle-secondary)", - triggerBackgroundColorHover: "var(--cpd-color-bg-accent-hovered)", - triggerBackgroundColorPressed: "var(--cpd-color-bg-accent-pressed)", - triggerColor: "var(--cpd-color-icon-primary)", - triggerColorContrast: "var(--cpd-color-icon-on-solid-primary)", - menuWidth: "320px", - menuBackgroundColor: "var(--cpd-color-bg-canvas-default)", - menuButtonBackgroundColorHover: "var(--cpd-color-bg-action-secondary-hovered)", - menuButtonBackgroundColorPressed: "var(--cpd-color-bg-action-secondary-pressed)", -}; +import { z } from "zod"; -type Theme = typeof theme; +export const Theme = z.object({ + textColor: z.string().default("var(--cpd-color-text-primary)"), + subheadingColor: z.string().default("var(--cpd-color-text-secondary)"), + bannerBackgroundColor: z.string().default("var(--cpd-color-bg-canvas-default)"), + bannerHeight: z.string().default("60px"), + triggerWidth: z.string().default("68px"), + triggerBackgroundColor: z.string().default("var(--cpd-color-bg-subtle-secondary)"), + triggerBackgroundColorHover: z.string().default("var(--cpd-color-bg-accent-hovered)"), + triggerBackgroundColorPressed: z.string().default("var(--cpd-color-bg-accent-pressed)"), + triggerColor: z.string().default("var(--cpd-color-icon-primary)"), + triggerColorContrast: z.string().default("var(--cpd-color-icon-on-solid-primary)"), + menuWidth: z.string().default("320px"), + menuBackgroundColor: z.string().default("var(--cpd-color-bg-canvas-default)"), + menuButtonBackgroundColorHover: z.string().default("var(--cpd-color-bg-action-secondary-hovered)"), + menuButtonBackgroundColorPressed: z.string().default("var(--cpd-color-bg-action-secondary-pressed)"), +}); -export { theme }; +export type Theme = z.infer; declare module "styled-components" { // eslint-disable-next-line @typescript-eslint/no-empty-object-type diff --git a/modules/banner/element-web/tests/banner.spec.ts b/modules/banner/element-web/tests/banner.spec.ts index ae9566ec5d..fe60dfc3a4 100644 --- a/modules/banner/element-web/tests/banner.spec.ts +++ b/modules/banner/element-web/tests/banner.spec.ts @@ -6,7 +6,7 @@ Please see LICENSE files in the repository root for full details. */ import { test as base, expect } from "../../../../playwright/element-web-test.ts"; -import { ModuleConfig } from "../src/config.ts"; +import { type ConfigSchema } from "../src/config.ts"; const test = base.extend<{ // Resolver for when to respond to the navigation.json request @@ -39,7 +39,7 @@ test.describe("Banner", () => { // We don't take a screenshot as we don't want to assert Element's styling, only our own }); - const configs: ModuleConfig[] = [ + const configs: ConfigSchema["_input"][] = [ { logo_url: "http://localhost:8080/logo.svg", logo_link_url: "https://example.com/portal", @@ -84,6 +84,10 @@ test.describe("Banner", () => { logo_url: "http://localhost:8080/opendesk/logofull.svg", ics_url: "http://localhost:8080/ics/", }, + theme: { + triggerBackgroundColorHover: "#571EFA", + triggerBackgroundColorPressed: "#4519C2", + }, }, ]; diff --git a/modules/banner/element-web/tests/snapshots/banner.spec.ts/univention-nav-hover-linux.png b/modules/banner/element-web/tests/snapshots/banner.spec.ts/univention-nav-hover-linux.png index 5cbc8775ee..a72b1cedc1 100644 Binary files a/modules/banner/element-web/tests/snapshots/banner.spec.ts/univention-nav-hover-linux.png and b/modules/banner/element-web/tests/snapshots/banner.spec.ts/univention-nav-hover-linux.png differ