1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Cleanup loading terminal fonts (#6937)

* Cleanup loading terminal fonts

- Make list of possible fonts fully OCP
- Only mark the loading of a font as 'causesSideEffects'
- Make a view model for the terminal font preferences component
- Move the TTF files next to where they are registered to help with finding them

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Cleanup formatting and change model to presenter

Signed-off-by: Sebastian Malton <sebastian@malton.name>

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-01-17 05:11:52 -08:00 committed by GitHub
parent cf27605a21
commit e635d82ea5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 298 additions and 140 deletions

View File

@ -5,66 +5,30 @@
import React from "react";
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
import { withInjectables } from "@ogre-tools/injectable-react";
import type { UserStore } from "../../../../../../common/user-store";
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
import { observer } from "mobx-react";
import type { SelectOption } from "../../../../../../renderer/components/select";
import { Select } from "../../../../../../renderer/components/select";
import type { Logger } from "../../../../../../common/logger";
import { action } from "mobx";
import loggerInjectable from "../../../../../../common/logger.injectable";
import {
terminalFontsInjectable,
} from "../../../../../../renderer/components/dock/terminal/terminal-fonts.injectable";
import type { TerminalFontPreferencePresenter } from "./terminal-font-options.injectable";
import terminalFontPreferencePresenterInjectable from "./terminal-font-options.injectable";
interface Dependencies {
userStore: UserStore;
logger: Logger;
terminalFonts: Map<string, string>;
model: TerminalFontPreferencePresenter;
}
const NonInjectedTerminalFontFamily = observer(
({ userStore, logger, terminalFonts }: Dependencies) => {
const bundledFonts: SelectOption<string>[] = Array.from(terminalFonts.keys()).map(font => {
const { fontFamily, fontSize } = userStore.terminalConfig;
return {
label: (
<span style={{ fontFamily: `${font}, var(--font-terminal)`, fontSize }}>
{font}
</span>
),
value: font,
isSelected: fontFamily === font,
};
});
const onFontFamilyChange = action(({ value: fontFamily }: SelectOption<string>) => {
logger.info(`setting terminal font to ${fontFamily}`);
userStore.terminalConfig.fontFamily = fontFamily; // save to external storage
});
return (
const NonInjectedTerminalFontFamily = observer(({ model }: Dependencies) => (
<section>
<SubTitle title="Font family" />
<Select
themeName="lens"
controlShouldRenderValue
value={userStore.terminalConfig.fontFamily}
options={bundledFonts}
onChange={onFontFamilyChange as any}
value={model.current.get()}
options={model.options.get()}
onChange={model.onSelection}
/>
</section>
);
},
);
));
export const TerminalFontFamily = withInjectables<Dependencies>(NonInjectedTerminalFontFamily, {
getProps: (di) => ({
userStore: di.inject(userStoreInjectable),
logger: di.inject(loggerInjectable),
terminalFonts: di.inject(terminalFontsInjectable),
model: di.inject(terminalFontPreferencePresenterInjectable),
}),
});

View File

@ -0,0 +1,50 @@
/**
* 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 type { IComputedValue } from "mobx";
import { action, computed } from "mobx";
import React from "react";
import type { SingleValue } from "react-select";
import userStoreInjectable from "../../../../../../common/user-store/user-store.injectable";
import { defaultTerminalFontFamily } from "../../../../../../common/vars";
import type { SelectOption } from "../../../../../../renderer/components/select";
import { terminalFontInjectionToken } from "../../../../../terminal/renderer/fonts/token";
export interface TerminalFontPreferencePresenter {
readonly options: IComputedValue<SelectOption<string>[]>;
readonly current: IComputedValue<string>;
onSelection: (selection: SingleValue<SelectOption<string>>) => void;
}
const terminalFontPreferencePresenterInjectable = getInjectable({
id: "terminal-font-preference-presenter",
instantiate: (di): TerminalFontPreferencePresenter => {
const userStore = di.inject(userStoreInjectable);
const terminalFonts = di.injectMany(terminalFontInjectionToken);
return {
options: computed(() => terminalFonts.map(font => ({
label: (
<span
style={{
fontFamily: `${font.name}, var(--font-terminal)`,
fontSize: userStore.terminalConfig.fontSize,
}}
>
{font.name}
</span>
),
value: font.name,
isSelected: userStore.terminalConfig.fontFamily === font.name,
}))),
current: computed(() => userStore.terminalConfig.fontFamily),
onSelection: action(selection => {
userStore.terminalConfig.fontFamily = selection?.value ?? defaultTerminalFontFamily;
}),
};
},
});
export default terminalFontPreferencePresenterInjectable;

View File

@ -0,0 +1,18 @@
/**
* 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 { terminalFontInjectionToken } from "./token";
import AnonymousPro from "./AnonymousPro-Regular.ttf";
const anonymousProTerminalFontInjectable = getInjectable({
id: "anonymous-pro-terminal-font",
instantiate: () => ({
name:"Anonymous Pro",
url: AnonymousPro,
}),
injectionToken: terminalFontInjectionToken,
});
export default anonymousProTerminalFontInjectable;

View File

@ -0,0 +1,13 @@
/**
* 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 { terminalFontInjectionToken } from "./token";
const terminalFontsInjectable = getInjectable({
id: "terminal-fonts",
instantiate: (di) => di.injectMany(terminalFontInjectionToken),
});
export default terminalFontsInjectable;

View File

@ -0,0 +1,18 @@
/**
* 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 { terminalFontInjectionToken } from "./token";
import IBMPlexMono from "./IBMPlexMono-Regular.ttf";
const ibmPlexMonoTerminalFontInjectable = getInjectable({
id: "ibm-plex-mono-terminal-font",
instantiate: () => ({
name: "IBM Plex Mono",
url: IBMPlexMono,
}),
injectionToken: terminalFontInjectionToken,
});
export default ibmPlexMonoTerminalFontInjectable;

View File

@ -0,0 +1,18 @@
/**
* 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 { terminalFontInjectionToken } from "./token";
import JetBrainsMono from "./JetBrainsMono-Regular.ttf";
const jetbrainsMonoTerminalFontInjectable = getInjectable({
id: "jetbrains-mono-terminal-font",
instantiate: () => ({
name: "JetBrains Mono",
url: JetBrainsMono,
}),
injectionToken: terminalFontInjectionToken,
});
export default jetbrainsMonoTerminalFontInjectable;

View File

@ -2,13 +2,8 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getGlobalOverride } from "../../../../common/test-utils/get-global-override";
import { preloadAllTerminalFontsInjectable } from "./terminal-fonts.injectable";
export default getGlobalOverride(preloadAllTerminalFontsInjectable, () => {
return {
id: "",
async run() {
},
};
});
import { getGlobalOverride } from "../../../../common/test-utils/get-global-override";
import loadTerminalFontInjectable from "./load-font.injectable";
export default getGlobalOverride(loadTerminalFontInjectable, () => async () => {});

View File

@ -0,0 +1,27 @@
/**
* 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 type { TerminalFont } from "./token";
export type LoadTerminalFont = (font: TerminalFont) => Promise<void>;
const loadTerminalFontInjectable = getInjectable({
id: "load-terminal-font",
instantiate: (): LoadTerminalFont => async (font) => {
const fontLoaded = document.fonts.check(`10px ${font.name}`);
if (fontLoaded) {
return;
}
const fontFace = new FontFace(font.name, `url(${font.url})`);
document.fonts.add(fontFace);
await fontFace.load();
},
causesSideEffects: true,
});
export default loadTerminalFontInjectable;

View File

@ -0,0 +1,24 @@
/**
* 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 { beforeFrameStartsFirstInjectionToken } from "../../../../renderer/before-frame-starts/tokens";
import terminalFontsInjectable from "./fonts.injectable";
import loadTerminalFontInjectable from "./load-font.injectable";
const preloadTerminalFontsInjectable = getInjectable({
id: "preload-terminal-fonts",
instantiate: (di) => ({
id: "preload-terminal-fonts",
run: async () => {
const terminalFonts = di.inject(terminalFontsInjectable);
const loadTerminalFont = di.inject(loadTerminalFontInjectable);
await Promise.allSettled(terminalFonts.map(loadTerminalFont));
},
}),
injectionToken: beforeFrameStartsFirstInjectionToken,
});
export default preloadTerminalFontsInjectable;

View File

@ -0,0 +1,18 @@
/**
* 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 { terminalFontInjectionToken } from "./token";
import RedHatMono from "./RedHatMono-Regular.ttf";
const redHatMonoTerminalFontInjectable = getInjectable({
id: "red-hat-mono-terminal-font",
instantiate: () => ({
name: "Red Hat Mono",
url: RedHatMono,
}),
injectionToken: terminalFontInjectionToken,
});
export default redHatMonoTerminalFontInjectable;

View File

@ -0,0 +1,18 @@
/**
* 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 { terminalFontInjectionToken } from "./token";
import RobotoMono from "./Roboto-Mono.ttf"; // patched font with icons
const robotoMonoTerminalFontInjectable = getInjectable({
id: "roboto-mono-terminal-font",
instantiate: () => ({
name: "RobotoMono",
url: RobotoMono,
}),
injectionToken: terminalFontInjectionToken,
});
export default robotoMonoTerminalFontInjectable;

View File

@ -0,0 +1,18 @@
/**
* 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 { terminalFontInjectionToken } from "./token";
import SourceCodePro from "./SourceCodePro-Regular.ttf";
const sourceCodeProTerminalFontInjectable = getInjectable({
id: "source-code-pro-terminal-font",
instantiate: () => ({
name: "Source Code Pro",
url: SourceCodePro,
}),
injectionToken: terminalFontInjectionToken,
});
export default sourceCodeProTerminalFontInjectable;

View File

@ -0,0 +1,18 @@
/**
* 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 { terminalFontInjectionToken } from "./token";
import SpaceMono from "./SpaceMono-Regular.ttf";
const spaceMonoTerminalFontInjectable = getInjectable({
id: "space-mono-terminal-font",
instantiate: () => ({
name: "Space Mono",
url: SpaceMono,
}),
injectionToken: terminalFontInjectionToken,
});
export default spaceMonoTerminalFontInjectable;

View File

@ -0,0 +1,15 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
export interface TerminalFont {
name: string;
url: string;
}
export const terminalFontInjectionToken = getInjectionToken<TerminalFont>({
id: "terminal-font-token",
});

View File

@ -0,0 +1,18 @@
/**
* 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 { terminalFontInjectionToken } from "./token";
import UbuntuMono from "./UbuntuMono-Regular.ttf";
const ubunutuMonoTerminalFontInjectable = getInjectable({
id: "ubunutu-mono-terminal-font",
instantiate: () => ({
name: "Ubuntu Mono",
url: UbuntuMono,
}),
injectionToken: terminalFontInjectionToken,
});
export default ubunutuMonoTerminalFontInjectable;

View File

@ -1,78 +0,0 @@
/**
* 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 { beforeFrameStartsFirstInjectionToken } from "../../../before-frame-starts/tokens";
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<void> {
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 {
id: "preload-all-terminal-fonts",
async run() {
await Promise.allSettled(
Array.from(terminalFonts.keys()).map(preloadFont),
);
},
};
},
injectionToken: beforeFrameStartsFirstInjectionToken,
causesSideEffects: true,
});

6
types/mocks.d.ts vendored
View File

@ -32,4 +32,8 @@ declare module "*.png";
declare module "*.eot";
declare module "*.woff";
declare module "*.woff2";
declare module "*.ttf";
declare module "*.ttf" {
const content: string;
export = content;
}