diff --git a/docs/url_params.md b/docs/url_params.md index 7b80690a4..789e3f3ce 100644 --- a/docs/url_params.md +++ b/docs/url_params.md @@ -67,6 +67,7 @@ These parameters are relevant to both [widget](./embedded_standalone.md) and [st | `showControls` | `true` or `false` | No, defaults to `true` | No, defaults to `true` | Displays controls like mute, screen-share, invite, and hangup buttons during a call. | | `skipLobby` (deprecated: use `intent` instead) | `true` or `false` | No. If `intent` is explicitly `start_call` then defaults to `true`. Otherwise defaults to `false` | No, defaults to `false` | Skips the lobby to join a call directly, can be combined with preload in widget. When `true` the audio and video inputs will be muted by default. (This means there currently is no way to start without muted video if one wants to skip the lobby. Also not in widget mode.) | | `theme` | One of: `light`, `dark`, `light-high-contrast`, `dark-high-contrast` | No, defaults to `dark` | No, defaults to `dark` | UI theme to use. | +| `background` | One of: `solid`, `gradient` | No, defaults to `gradient` | No, defaults to `gradient` | Visual style of the page background. | | `viaServers` | Comma separated list of [Matrix Server Names](https://spec.matrix.org/v1.12/appendices/#server-name) | Not applicable | No | Homeserver for joining a room, non-empty value required for rooms not on the user’s default homeserver. | | `sendNotificationType` | `ring` or `notification` | No | No | Will send a "ring" or "notification" `m.rtc.notification` event if the user is the first one in the call. | | `autoLeave` | `true` or `false` | No, defaults to `false` | No, defaults to `false` | Whether the app should automatically leave the call when there is no one left in the call. | diff --git a/locales/en/app.json b/locales/en/app.json index 8656502cf..3ff956a6a 100644 --- a/locales/en/app.json +++ b/locales/en/app.json @@ -205,6 +205,7 @@ "blur_not_supported_by_browser": "(Background blur is not supported by this device.)", "developer_tab_title": "Developer", "devices": { + "activating": "Activating…", "camera": "Camera", "camera_numbered": "Camera {{n}}", "change_device_button": "Change audio device", diff --git a/playwright/spa-helpers.ts b/playwright/spa-helpers.ts index 46c414c97..24869141f 100644 --- a/playwright/spa-helpers.ts +++ b/playwright/spa-helpers.ts @@ -125,21 +125,10 @@ async function expectVideoTilesCount(page: Page, count: number): Promise { }); // There should be `count` video elements, visible and autoplaying - await expect(page.locator("video")).toHaveCount(count); - - await expect(async () => { - const videoBlockCount = await page - .locator("video") - .evaluateAll( - (videos: Element[]) => - videos.filter( - (v: Element) => window.getComputedStyle(v).display === "block", - ).length, - ); - expect(videoBlockCount).toBe(count); - }).toPass({ - timeout: 10000, - }); + await expect(page.locator("video").filter({ visible: true })).toHaveCount( + count, + { timeout: 10000 }, + ); } export const SpaHelpers = { diff --git a/playwright/widget/test-helpers.ts b/playwright/widget/test-helpers.ts index b2a238f81..3f0bbeed4 100644 --- a/playwright/widget/test-helpers.ts +++ b/playwright/widget/test-helpers.ts @@ -385,25 +385,9 @@ export class TestHelpers { frame: FrameLocator, count: number, ): Promise { - // XXX we need to be better at our HTML markup and accessibility, it would make - // this kind of stuff way easier to test if we could look out for aria attributes. - await expect - .poll( - async () => { - return await frame - .locator("video") - .evaluateAll( - (videos: Element[]) => - videos.filter( - (v: Element) => - window.getComputedStyle(v).display === "block", - ).length, - ); - }, - { - timeout: 10000, - }, - ) - .toBe(count); + await expect(frame.locator("video").filter({ visible: true })).toHaveCount( + count, + { timeout: 10000 }, + ); } } diff --git a/src/App.tsx b/src/App.tsx index b87f587ca..8f6ef21a1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -30,7 +30,7 @@ import { useTheme } from "./useTheme"; import { ProcessorProvider } from "./livekit/TrackProcessorContext"; import { type AppViewModel } from "./state/AppViewModel"; import { MediaDevicesContext } from "./MediaDevicesContext"; -import { getUrlParams, HeaderStyle } from "./UrlParams"; +import { getUrlParams, HeaderStyle, useUrlParams } from "./UrlParams"; import { AppBar } from "./AppBar"; const SentryRoute = Sentry.withSentryReactRouterV7Routing(Route); @@ -41,19 +41,17 @@ interface SimpleProviderProps { const BackgroundProvider: FC = ({ children }) => { const { pathname } = useLocation(); + const { background } = useUrlParams(); useEffect(() => { - let backgroundImage = ""; - if (!["/login", "/register"].includes(pathname) && !widget) { - backgroundImage = "var(--background-gradient)"; - } + document + .getElementsByTagName("body")[0] + .setAttribute("data-background", background); + }, [pathname, background]); - document.getElementsByTagName("body")[0].style.backgroundImage = - backgroundImage; - }, [pathname]); - - return <>{children}; + return children; }; + const ThemeProvider: FC = ({ children }) => { useTheme(); return children; diff --git a/src/UrlParams.ts b/src/UrlParams.ts index 773aa4121..805cab710 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -45,6 +45,11 @@ export enum HeaderStyle { AppBar = "app_bar", } +export enum BackgroundStyle { + Solid = "solid", + Gradient = "gradient", +} + /** * The UrlProperties are used to pass required data to the widget. * Those are different in different rooms, users, devices. They do not configure the behavior of the @@ -145,6 +150,10 @@ export interface UrlProperties { * can be "light", "dark", "light-high-contrast" or "dark-high-contrast". */ theme: string | null; + /** + * The visual style of the page background. + */ + background: BackgroundStyle; } /** @@ -452,6 +461,9 @@ export const computeUrlParams = (search = "", hash = ""): UrlParams => { fonts: parser.getAllParams("font"), fontScale: Number.isNaN(fontScale) ? null : fontScale, theme: parser.getParam("theme"), + background: + parser.getEnumParam("background", BackgroundStyle) ?? + BackgroundStyle.Gradient, viaServers: !isWidget ? parser.getParam("viaServers") : null, homeserver: !isWidget ? parser.getParam("homeserver") : null, posthogApiHost: parser.getParam("posthogApiHost"), diff --git a/src/__snapshots__/AppBar.test.tsx.snap b/src/__snapshots__/AppBar.test.tsx.snap index 482189481..99b322ac3 100644 --- a/src/__snapshots__/AppBar.test.tsx.snap +++ b/src/__snapshots__/AppBar.test.tsx.snap @@ -3,12 +3,12 @@ exports[`AppBar > renders 1`] = `
@@ -46,12 +46,12 @@ exports[`AppBar > renders 1`] = ` exports[`AppBar > renders with title and subtitle 1`] = `

Title

Subtitle
diff --git a/src/__snapshots__/Modal.test.tsx.snap b/src/__snapshots__/Modal.test.tsx.snap index 648bdfd50..4753701eb 100644 --- a/src/__snapshots__/Modal.test.tsx.snap +++ b/src/__snapshots__/Modal.test.tsx.snap @@ -3,7 +3,7 @@ exports[`the content is rendered when the modal is open 1`] = `