Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/static_analysis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ jobs:
voip|element_call
error|invalid_json
error|misconfigured
welcome_to_element
welcome|title_element
devtools|settings|elementCallUrl
labs|sliding_sync_description
settings|voip|noise_suppression_description
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ test.use({

test("Shows the welcome page by default", async ({ page }) => {
await page.goto("/");
await expect(page.getByRole("heading", { name: "Welcome to Element!" })).toBeVisible();
await expect(page.getByRole("heading", { name: "Be in your element" })).toBeVisible();
await expect(page.getByRole("link", { name: "Sign in" })).toBeVisible();
});

Expand Down
2 changes: 1 addition & 1 deletion apps/web/playwright/e2e/login/login-consent.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ test.describe("Login", () => {
await page.goto("/");

// Should give us the welcome page initially
await expect(page.getByRole("heading", { name: "Welcome to Element!" })).toBeVisible();
await expect(page.getByRole("heading", { name: "Be in your element" })).toBeVisible();

// Start the login process
await expect(axe).toHaveNoViolations();
Expand Down
1 change: 1 addition & 0 deletions apps/web/res/css/_components.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
@import "./views/auth/_AuthPage.pcss";
@import "./views/auth/_CompleteSecurityBody.pcss";
@import "./views/auth/_CountryDropdown.pcss";
@import "./views/auth/_DefaultWelcome.pcss";
@import "./views/auth/_InteractiveAuthEntryComponents.pcss";
@import "./views/auth/_LanguageSelector.pcss";
@import "./views/auth/_LoginWithQR.pcss";
Expand Down
43 changes: 43 additions & 0 deletions apps/web/res/css/views/auth/_DefaultWelcome.pcss
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Copyright 2026 Element Creations Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/

.mx_DefaultWelcome {
text-align: center;

.mx_DefaultWelcome_logo img {
height: 48px;
aspect-ratio: auto;
display: block;
margin: 0 auto;
}

h1 {
margin: var(--cpd-space-4x) 0 var(--cpd-space-2x);
}

p {
color: var(--cpd-color-text-secondary);
margin-top: var(--cpd-space-2x);
}

.mx_DefaultWelcome_buttons {
margin: var(--cpd-space-6x) 0 var(--cpd-space-1x);
padding-bottom: var(--cpd-space-4x);
border-bottom: 1px solid var(--cpd-color-separator-primary);

a {
width: 380px;
margin-bottom: var(--cpd-space-4x);
}
}
}

.mx_WelcomePage_registrationDisabled {
.mx_DefaultWelcome_buttons_register {
display: none;
}
}
6 changes: 5 additions & 1 deletion apps/web/res/css/views/auth/_Welcome.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Please see LICENSE files in the repository root for full details.
display: flex;
flex-direction: column;
align-items: center;
background-color: var(--cpd-color-bg-canvas-default);
box-sizing: border-box;
padding: var(--cpd-space-11x) var(--cpd-space-12x) var(--cpd-space-4x);

&.mx_WelcomePage_registrationDisabled {
.mx_ButtonCreateAccount {
display: none;
Expand All @@ -18,7 +22,7 @@ Please see LICENSE files in the repository root for full details.

.mx_Welcome .mx_AuthBody_language {
width: 160px;
margin-bottom: 10px;
margin: var(--cpd-space-1x) 0;
}

/* Invert image colours in dark mode. */
Expand Down
191 changes: 0 additions & 191 deletions apps/web/res/welcome.html

This file was deleted.

3 changes: 0 additions & 3 deletions apps/web/res/welcome/images/icon-create-account.svg

This file was deleted.

16 changes: 0 additions & 16 deletions apps/web/res/welcome/images/icon-help.svg

This file was deleted.

4 changes: 0 additions & 4 deletions apps/web/res/welcome/images/icon-room-directory.svg

This file was deleted.

4 changes: 0 additions & 4 deletions apps/web/res/welcome/images/icon-sign-in.svg

This file was deleted.

10 changes: 10 additions & 0 deletions apps/web/src/@types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,13 @@ export type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[k
export type Assignable<Object, Item> = {
[Key in keyof Object]: Object[Key] extends Item ? Key : never;
}[keyof Object];

/**
* Like `Partial` but for applied to all nested objects.
* Based on https://dev.to/perennialautodidact/adventures-in-typescript-deeppartial-2f2a
*/
export type DeepPartial<T> = T extends object
? {
[P in keyof T]?: DeepPartial<T[P]>;
}
: T;
5 changes: 3 additions & 2 deletions apps/web/src/IConfigOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ export interface IConfigOptions {
disable_3pid_login?: boolean;

brand: string;
branding?: {
welcome_background_url?: string | string[]; // chosen at random if array
branding: {
welcome_background_url: string | string[]; // chosen at random if array
logo_link_url: string;
auth_header_logo_url?: string;
auth_footer_links?: { text: string; url: string }[];
};
Expand Down
11 changes: 8 additions & 3 deletions apps/web/src/SdkConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ import { mergeWith } from "lodash";
import { SnakedObject } from "./utils/SnakedObject";
import { type IConfigOptions } from "./IConfigOptions";
import { isObject, objectClone } from "./utils/objects";
import { type DeepReadonly, type Defaultize } from "./@types/common";
import { type DeepPartial, type DeepReadonly, type Defaultize } from "./@types/common";

// see element-web config.md for docs, or the IConfigOptions interface for dev docs
export const DEFAULTS: DeepReadonly<IConfigOptions> = {
brand: "Element",
branding: {
logo_link_url: "https://element.io",
auth_header_logo_url: "themes/element/img/logos/element-logo.svg",
welcome_background_url: "themes/element/img/backgrounds/lake.jpg",
},
help_url: "https://element.io/help",
help_encryption_url: "https://element.io/help#encryption",
help_key_storage_url: "https://element.io/help#encryption5",
Expand Down Expand Up @@ -70,7 +75,7 @@ export type ConfigOptions = Defaultize<IConfigOptions, typeof DEFAULTS>;

function mergeConfig(
config: DeepReadonly<IConfigOptions>,
changes: DeepReadonly<Partial<IConfigOptions>>,
changes: DeepReadonly<DeepPartial<IConfigOptions>>,
): DeepReadonly<IConfigOptions> {
// return { ...config, ...changes };
return mergeWith(objectClone(config), changes, (objValue, srcValue) => {
Expand Down Expand Up @@ -136,7 +141,7 @@ export default class SdkConfig {
SdkConfig.setInstance(mergeConfig(DEFAULTS, {})); // safe to cast - defaults will be applied
}

public static add(cfg: Partial<ConfigOptions>): void {
public static add(cfg: DeepPartial<ConfigOptions>): void {
SdkConfig.put(mergeConfig(SdkConfig.get(), cfg));
}
}
18 changes: 18 additions & 0 deletions apps/web/src/branding.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
Copyright 2026 Element Creations Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/

import SdkConfig from "./SdkConfig.ts";

/**
* Returns whether the app is currently branded.
* This is currently a naive check of whether the `brand` config starts with the substring `Element`,
* which correctly covers `Element` (release), `Element Nightly` & `Element Pro`.
*/
export const isElementBranded = (): boolean => {
const brand = SdkConfig.get("brand");
return brand.startsWith("Element");
};
Loading
Loading