Replace require calls for image uris with imports (#33847)

* Replace `require` calls for image uris with imports

In prep for vitest

* Fix copyright
This commit is contained in:
Michael Telatynski
2026-06-15 17:09:51 +01:00
committed by GitHub
parent 2f4e6a4ec4
commit 86a89c2aa5
8 changed files with 43 additions and 30 deletions
+11
View File
@@ -0,0 +1,11 @@
/*
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.
*/
declare module "*.png" {
const path: string;
export default path;
}
+2 -2
View File
@@ -13,6 +13,7 @@ import { SnakedObject } from "./utils/SnakedObject";
import { type IConfigOptions } from "./IConfigOptions";
import { isObject, objectClone } from "./utils/objects";
import { type DeepPartial, type DeepReadonly, type Defaultize } from "./@types/common";
import ElementDesktopLogoSvg from "../res/img/element-desktop-logo.svg";
// see element-web config.md for docs, or the IConfigOptions interface for dev docs
export const DEFAULTS: DeepReadonly<IConfigOptions> = {
@@ -44,8 +45,7 @@ export const DEFAULTS: DeepReadonly<IConfigOptions> = {
// be preferred over their config.
desktopBuilds: {
available: true,
// eslint-disable-next-line @typescript-eslint/no-require-imports
logo: require("../res/img/element-desktop-logo.svg").default,
logo: ElementDesktopLogoSvg,
url: "https://element.io/get-started",
},
@@ -6,13 +6,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/
// We're importing via require specifically so the svg becomes a URI rather than a DOM element.
// eslint-disable-next-line @typescript-eslint/no-require-imports
const matrixSvg = require("../../../res/img/matrix.svg").default;
import MatrixSvg from "../../../res/img/matrix.svg";
/**
* Intended to replace $matrixLogo in the welcome page.
*/
export const MATRIX_LOGO_HTML = `<a href="https://matrix.org" target="_blank" rel="noreferrer noopener">
<img class="mx_WelcomePage_logo" width="79" height="34" alt="Matrix" style="padding-left: 1px;vertical-align: middle" src="${matrixSvg}"/>
<img class="mx_WelcomePage_logo" width="79" height="34" alt="Matrix" style="padding-left: 1px;vertical-align: middle" src="${MatrixSvg}"/>
</a>`;
@@ -13,6 +13,11 @@ import classNames from "classnames";
import { type IApp, isAppWidget } from "../../../stores/WidgetStore";
import BaseAvatar, { type BaseAvatarType } from "./BaseAvatar";
import { mediaFromMxc } from "../../../customisations/Media";
import DefaultAppSvg from "../../../../res/img/element-icons/room/default_app.svg";
import DefaultVideoSvg from "../../../../res/img/element-icons/room/default_video.svg";
import DefaultCalSvg from "../../../../res/img/element-icons/room/default_cal.svg";
import DefaultDocSvg from "../../../../res/img/element-icons/room/default_doc.svg";
import DefaultClockSvg from "../../../../res/img/element-icons/room/default_clock.svg";
interface IProps extends Omit<ComponentProps<BaseAvatarType>, "name" | "url" | "urls"> {
app: IApp | IWidget;
@@ -20,19 +25,17 @@ interface IProps extends Omit<ComponentProps<BaseAvatarType>, "name" | "url" | "
}
const WidgetAvatar: React.FC<IProps> = ({ app, className, size = "20px", ...props }) => {
/* eslint-disable @typescript-eslint/no-require-imports */
let iconUrls = [require("../../../../res/img/element-icons/room/default_app.svg").default];
let iconUrl = DefaultAppSvg;
// heuristics for some better icons until Widgets support their own icons
if (app.type.includes("jitsi")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_video.svg").default];
iconUrl = DefaultVideoSvg;
} else if (app.type.includes("meeting") || app.type.includes("calendar")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_cal.svg").default];
iconUrl = DefaultCalSvg;
} else if (app.type.includes("pad") || app.type.includes("doc") || app.type.includes("calc")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_doc.svg").default];
iconUrl = DefaultDocSvg;
} else if (app.type.includes("clock")) {
iconUrls = [require("../../../../res/img/element-icons/room/default_clock.svg").default];
iconUrl = DefaultClockSvg;
}
/* eslint-enable @typescript-eslint/no-require-imports */
return (
<BaseAvatar
@@ -43,7 +46,7 @@ const WidgetAvatar: React.FC<IProps> = ({ app, className, size = "20px", ...prop
className={classNames("mx_WidgetAvatar", className)}
// MSC2765
url={isAppWidget(app) && app.avatar_url ? mediaFromMxc(app.avatar_url).getSquareThumbnailHttp(20) : null}
urls={iconUrls}
urls={[iconUrl]}
size={size}
/>
);
@@ -21,36 +21,39 @@ import { UIFeature } from "../../../settings/UIFeature";
import BaseDialog from "./BaseDialog";
import { type XOR } from "../../../@types/common";
import { useSettingValue } from "../../../hooks/useSettings.ts";
import FacebookIcon from "../../../../res/img/social/facebook.png";
import TwitterIcon from "../../../../res/img/social/twitter-2.png";
import LinkedInIcon from "../../../../res/img/social/linkedin.png";
import RedditIcon from "../../../../res/img/social/reddit.png";
import EmailIcon from "../../../../res/img/social/email-1.png";
/* eslint-disable @typescript-eslint/no-require-imports */
const SOCIALS = [
{
name: "Facebook",
img: require("../../../../res/img/social/facebook.png"),
img: FacebookIcon,
url: (url: string) => `https://www.facebook.com/sharer/sharer.php?u=${url}`,
},
{
name: "Twitter",
img: require("../../../../res/img/social/twitter-2.png"),
img: TwitterIcon,
url: (url: string) => `https://twitter.com/home?status=${url}`,
},
{
name: "LinkedIn",
img: require("../../../../res/img/social/linkedin.png"),
img: LinkedInIcon,
url: (url: string) => `https://www.linkedin.com/shareArticle?mini=true&url=${url}`,
},
{
name: "Reddit",
img: require("../../../../res/img/social/reddit.png"),
img: RedditIcon,
url: (url: string) => `https://www.reddit.com/submit?url=${url}`,
},
{
name: "email",
img: require("../../../../res/img/social/email-1.png"),
img: EmailIcon,
url: (url: string) => `mailto:?body=${url}`,
},
];
/* eslint-enable @typescript-eslint/no-require-imports */
interface BaseProps {
/**
@@ -26,6 +26,7 @@ import type ScalarAuthClient from "../../../ScalarAuthClient";
import GenericElementContextMenu from "../context_menus/GenericElementContextMenu";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
import StickerpackPlaceholder from "../../../../res/img/stickerpack-placeholder.png";
// This should be below the dialog level (4000), but above the rest of the UI (1000-2000).
// We sit in a context menu, so this should be given to the context menu.
@@ -200,13 +201,11 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
};
private defaultStickerpickerContent(): JSX.Element {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const imgSrc = require("../../../../res/img/stickerpack-placeholder.png");
return (
<AccessibleButton onClick={this.launchManageIntegrations} className="mx_Stickers_contentPlaceholder">
<p>{_t("stickers|empty")}</p>
<p className="mx_Stickers_addLink">{_t("stickers|empty_add_prompt")}</p>
<img src={imgSrc} alt="" />
<img src={StickerpackPlaceholder} alt="" />
</AccessibleButton>
);
}
+2 -2
View File
@@ -55,6 +55,7 @@ import BlockInvitesConfigController from "./controllers/BlockInvitesConfigContro
import RequiresSettingsController from "./controllers/RequiresSettingsController.ts";
import { type OrderedCustomSections, type CustomSectionsData } from "../stores/room-list-v3/section.ts";
import { type NotificationSound } from "../Notifier.ts";
import VideoRoomsBetaImage from "../../res/img/betas/video_rooms.png";
export const defaultWatchManager = new WatchManager();
@@ -413,8 +414,7 @@ export const SETTINGS: Settings = {
),
feedbackLabel: "video-room-feedback",
feedbackSubheading: _td("labs|video_rooms_feedbackSubheading"),
// eslint-disable-next-line @typescript-eslint/no-require-imports
image: require("../../res/img/betas/video_rooms.png"),
image: VideoRoomsBetaImage,
requiresRefresh: true,
},
},
@@ -16,6 +16,8 @@ import {
type FileBodyViewSnapshot,
type FileBodyViewModel as FileBodyViewModelInterface,
} from "@element-hq/web-shared-components";
// eslint-disable-next-line no-restricted-imports
import DownloadSvg from "@vector-im/compound-design-tokens/icons/download.svg";
import Modal from "../../Modal";
import { _t } from "../../languageHandler";
@@ -41,10 +43,7 @@ const downloadIconCache = { url: "" };
async function cacheDownloadIcon(): Promise<string> {
if (downloadIconCache.url) return downloadIconCache.url;
// eslint-disable-next-line @typescript-eslint/no-require-imports
const svg = await fetch(require("@vector-im/compound-design-tokens/icons/download.svg").default).then((r) =>
r.text(),
);
const svg = await fetch(DownloadSvg).then((r) => r.text());
downloadIconCache.url = "data:image/svg+xml;base64," + window.btoa(svg);
return downloadIconCache.url;
}