diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-family.tsx b/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-family.tsx index 14bc5efacd..74ad96e6c3 100644 --- a/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-family.tsx +++ b/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-family.tsx @@ -2,7 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import React from "react"; +import React, { useEffect } from "react"; import { SubTitle } from "../../../../../../renderer/components/layout/sub-title"; import { withInjectables } from "@ogre-tools/injectable-react"; import type { UserStore } from "../../../../../../common/user-store"; @@ -13,26 +13,35 @@ import { Select } from "../../../../../../renderer/components/select"; import type { Logger } from "../../../../../../common/logger"; import { action } from "mobx"; import loggerInjectable from "../../../../../../common/logger.injectable"; +import { + preloadAllTerminalFontsInjectable, + terminalFontsInjectable, +} from "../../../../../../renderer/components/dock/terminal/terminal-fonts.injectable"; interface Dependencies { userStore: UserStore; logger: Logger; + terminalFonts: Map; + preloadFonts: () => Promise; } const NonInjectedTerminalFontFamily = observer( - ({ userStore, logger }: Dependencies) => { + ({ userStore, logger, terminalFonts, preloadFonts }: Dependencies) => { + useEffect(() => { + preloadFonts(); // preload all fonts to show preview in select-box + }, []); - // fonts must be declared in `fonts.scss` and at `template.html` (if early-preloading required) - const supportedCustomFonts: SelectOption[] = [ - "RobotoMono", "Anonymous Pro", "IBM Plex Mono", "JetBrains Mono", "Red Hat Mono", - "Source Code Pro", "Space Mono", "Ubuntu Mono", - ].map(customFont => { + const bundledFonts: SelectOption[] = Array.from(terminalFonts.keys()).map(font => { const { fontFamily, fontSize } = userStore.terminalConfig; return { - label: {customFont}, - value: customFont, - isSelected: fontFamily === customFont, + label: ( + + {font} + + ), + value: font, + isSelected: fontFamily === font, }; }); @@ -50,7 +59,7 @@ const NonInjectedTerminalFontFamily = observer( themeName="lens" controlShouldRenderValue value={userStore.terminalConfig.fontFamily} - options={supportedCustomFonts} + options={bundledFonts} onChange={onFontFamilyChange as any} /> @@ -65,6 +74,8 @@ export const TerminalFontFamily = withInjectables( getProps: (di) => ({ userStore: di.inject(userStoreInjectable), logger: di.inject(loggerInjectable), + terminalFonts: di.inject(terminalFontsInjectable), + preloadFonts: di.inject(preloadAllTerminalFontsInjectable), }), }, ); diff --git a/src/renderer/components/app.scss b/src/renderer/components/app.scss index f44d1ee165..b8dd5007b1 100755 --- a/src/renderer/components/app.scss +++ b/src/renderer/components/app.scss @@ -232,22 +232,6 @@ iframe { } } -#fonts-preloading { - > span { - position: absolute; - visibility: hidden; - height: 0; - - &:before { - width: 0; - display: block; - overflow: hidden; - content: "text-example"; // some text required to start applying/rendering font in document - font-family: inherit; // font-family must be specified via style="" (see: template.html) - } - } -} - // app's common loading indicator, displaying on the route transitions #loading { position: absolute; diff --git a/src/renderer/components/dock/terminal/create-terminal.injectable.ts b/src/renderer/components/dock/terminal/create-terminal.injectable.ts index 27c7c0664a..851044a33c 100644 --- a/src/renderer/components/dock/terminal/create-terminal.injectable.ts +++ b/src/renderer/components/dock/terminal/create-terminal.injectable.ts @@ -9,11 +9,13 @@ import type { TabId } from "../dock/store"; import type { TerminalApi } from "../../../api/terminal-api"; import terminalSpawningPoolInjectable from "./terminal-spawning-pool.injectable"; import terminalConfigInjectable from "../../../../common/user-store/terminal-config.injectable"; -import terminalCopyOnSelectInjectable from "../../../../common/user-store/terminal-copy-on-select.injectable"; +import terminalCopyOnSelectInjectable + from "../../../../common/user-store/terminal-copy-on-select.injectable"; import isMacInjectable from "../../../../common/vars/is-mac.injectable"; import openLinkInBrowserInjectable from "../../../../common/utils/open-link-in-browser.injectable"; import xtermColorThemeInjectable from "../../../themes/terminal-colors.injectable"; import loggerInjectable from "../../../../common/logger.injectable"; +import { preloadTerminalFontInjectable } from "./terminal-fonts.injectable"; export type CreateTerminal = (tabId: TabId, api: TerminalApi) => Terminal; @@ -28,6 +30,7 @@ const createTerminalInjectable = getInjectable({ openLinkInBrowser: di.inject(openLinkInBrowserInjectable), xtermColorTheme: di.inject(xtermColorThemeInjectable), logger: di.inject(loggerInjectable), + preloadFont: di.inject(preloadTerminalFontInjectable), }; return (tabId, api) => new Terminal(dependencies, { tabId, api }); diff --git a/src/renderer/components/dock/terminal/terminal-fonts.injectable.ts b/src/renderer/components/dock/terminal/terminal-fonts.injectable.ts new file mode 100644 index 0000000000..a0fd3ac897 --- /dev/null +++ b/src/renderer/components/dock/terminal/terminal-fonts.injectable.ts @@ -0,0 +1,71 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getInjectable } from "@ogre-tools/injectable"; +import RobotoMono from "../../../fonts/Roboto-Mono-nerd.ttf"; // patched font with icons +import AnonymousPro from "../../../fonts/AnonymousPro-Regular.ttf"; +import IBMPlexMono from "../../../fonts/IBMPlexMono-Regular.ttf"; +import JetBrainsMono from "../../../fonts/JetBrainsMono-Regular.ttf"; +import RedHatMono from "../../../fonts/RedHatMono-Regular.ttf"; +import SourceCodePro from "../../../fonts/SourceCodePro-Regular.ttf"; +import SpaceMono from "../../../fonts/SpaceMono-Regular.ttf"; +import UbuntuMono from "../../../fonts/UbuntuMono-Regular.ttf"; + +export const terminalFontsInjectable = getInjectable({ + id: "terminalFontsInjectable", + + instantiate() { + return new Map([ + ["RobotoMono", RobotoMono], + ["Anonymous Pro", AnonymousPro], + ["IBM Plex Mono", IBMPlexMono], + ["JetBrains Mono", JetBrainsMono], + ["Red Hat Mono", RedHatMono], + ["Source Code Pro", SourceCodePro], + ["Space Mono", SpaceMono], + ["Ubuntu Mono", UbuntuMono], + ]); + }, +}); + + +export const preloadTerminalFontInjectable = getInjectable({ + id: "preloadTerminalFontInjectable", + + instantiate(di) { + const terminalFonts = di.inject(terminalFontsInjectable); + + return async function (fontFamily: string): Promise { + const fontBundledPath = terminalFonts.get(fontFamily); + const fontLoaded = document.fonts.check(`10px ${fontFamily}`); + + if (fontLoaded || !fontBundledPath) return; + + const font = new FontFace(fontFamily, `url(${fontBundledPath})`); + + document.fonts.add(font); + await font.load(); + }; + }, + + causesSideEffects: true, +}); + +export const preloadAllTerminalFontsInjectable = getInjectable({ + id: "preloadAllTerminalFontsInjectable", + + instantiate(di) { + const terminalFonts = di.inject(terminalFontsInjectable); + const preloadFont = di.inject(preloadTerminalFontInjectable); + + return async function (): Promise { + return Promise.allSettled( + Array.from(terminalFonts.keys()).map(preloadFont), + ); + }; + }, + + causesSideEffects: true, +}); diff --git a/src/renderer/components/dock/terminal/terminal.ts b/src/renderer/components/dock/terminal/terminal.ts index 5f49882f1c..40c624a79d 100644 --- a/src/renderer/components/dock/terminal/terminal.ts +++ b/src/renderer/components/dock/terminal/terminal.ts @@ -28,6 +28,7 @@ export interface TerminalDependencies { readonly xtermColorTheme: IComputedValue>; readonly logger: Logger; openLinkInBrowser: OpenLinkInBrowser; + preloadFont: (fontFamily: string) => Promise; } export interface TerminalArguments { @@ -53,7 +54,8 @@ export class Terminal { return this.elem.querySelector(".xterm-viewport")!; } - attachTo(parentElem: HTMLElement) { + async attachTo(parentElem: HTMLElement) { + await this.dependencies.preloadFont(this.fontFamily); assert(this.elem, "Terminal should always be mounted somewhere"); parentElem.appendChild(this.elem); this.onActivate(); @@ -206,9 +208,10 @@ export class Terminal { this.fit(); }; - setFontFamily = (fontFamily: string) => { + setFontFamily = async (fontFamily: string) => { this.dependencies.logger.info(`[TERMINAL]: set fontFamily to ${fontFamily}`); + await this.dependencies.preloadFont(fontFamily); this.xterm.options.fontFamily = fontFamily; this.fit(); diff --git a/src/renderer/components/dock/terminal/view.tsx b/src/renderer/components/dock/terminal/view.tsx index b85824cc30..ed824d8156 100644 --- a/src/renderer/components/dock/terminal/view.tsx +++ b/src/renderer/components/dock/terminal/view.tsx @@ -34,14 +34,14 @@ class NonInjectedTerminalWindow extends React.Component resized @@ -51,7 +51,7 @@ class NonInjectedTerminalWindow extends React.Component
-
- - - - - - - - - -