diff --git a/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal-preference-item.injectable.ts
new file mode 100644
index 0000000000..61dcc3dd40
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * 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 { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { CopyPasteFromTerminal } from "./copy-paste-from-terminal";
+
+const copyPasteFromTerminalPreferenceItemInjectable = getInjectable({
+ id: "copy-paste-from-terminal-preference-item",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "copy-paste-from-terminal-preference-item",
+ parentId: "terminal-page",
+ orderNumber: 20,
+ Component: CopyPasteFromTerminal,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default copyPasteFromTerminalPreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx b/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx
new file mode 100644
index 0000000000..50a63d2c66
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/copy-paste-from-terminal/copy-paste-from-terminal.tsx
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+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 { Switch } from "../../../../../../renderer/components/switch";
+
+interface Dependencies {
+ userStore: UserStore;
+}
+
+const NonInjectedCopyPasteFromTerminal = observer(
+ ({ userStore }: Dependencies) => {
+
+ return (
+
+
+ userStore.terminalCopyOnSelect = !userStore.terminalCopyOnSelect}
+ >
+ Copy on select and paste on right-click
+
+
+ );
+ },
+);
+
+export const CopyPasteFromTerminal = withInjectables(
+ NonInjectedCopyPasteFromTerminal,
+
+ {
+ getProps: (di) => ({
+ userStore: di.inject(userStoreInjectable),
+ }),
+ },
+);
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-family-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-family-preference-item.injectable.ts
new file mode 100644
index 0000000000..7d016f8603
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-family-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * 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 { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { TerminalFontFamily } from "./terminal-font-family";
+
+const terminalFontFamilyPreferenceItemInjectable = getInjectable({
+ id: "terminal-font-family-preference-item",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "terminal-font-family-preference-item",
+ parentId: "terminal-page",
+ orderNumber: 40,
+ Component: TerminalFontFamily,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default terminalFontFamilyPreferenceItemInjectable;
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
new file mode 100644
index 0000000000..14bc5efacd
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-font-family/terminal-font-family.tsx
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+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";
+
+interface Dependencies {
+ userStore: UserStore;
+ logger: Logger;
+}
+
+const NonInjectedTerminalFontFamily = observer(
+ ({ userStore, logger }: Dependencies) => {
+
+ // 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 { fontFamily, fontSize } = userStore.terminalConfig;
+
+ return {
+ label: {customFont},
+ value: customFont,
+ isSelected: fontFamily === customFont,
+ };
+ });
+
+ const onFontFamilyChange = action(({ value: fontFamily }: SelectOption) => {
+ logger.info(`setting terminal font to ${fontFamily}`);
+
+ userStore.terminalConfig.fontFamily = fontFamily; // save to external storage
+ });
+
+
+ return (
+
+ );
+ },
+);
+
+export const TerminalFontFamily = withInjectables(
+ NonInjectedTerminalFontFamily,
+
+ {
+ getProps: (di) => ({
+ userStore: di.inject(userStoreInjectable),
+ logger: di.inject(loggerInjectable),
+ }),
+ },
+);
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size-preference-item.injectable.ts
new file mode 100644
index 0000000000..cb72fa8b55
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * 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 { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { TerminalFontSize } from "./terminal-font-size";
+
+const terminalFontSizePreferenceItemInjectable = getInjectable({
+ id: "terminal-font-size-preference-item",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "terminal-font-size-preference-item",
+ parentId: "terminal-page",
+ orderNumber: 30,
+ Component: TerminalFontSize,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default terminalFontSizePreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx b/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx
new file mode 100644
index 0000000000..8fb1cfa63b
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-font-size/terminal-font-size.tsx
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+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 { Input } from "../../../../../../renderer/components/input";
+
+interface Dependencies {
+ userStore: UserStore;
+}
+
+const NonInjectedTerminalFontSize = observer(
+ ({ userStore }: Dependencies) => {
+
+ return (
+
+
+ userStore.terminalConfig.fontSize = Number(value)}
+ />
+
+ );
+ },
+);
+
+export const TerminalFontSize = withInjectables(
+ NonInjectedTerminalFontSize,
+
+ {
+ getProps: (di) => ({
+ userStore: di.inject(userStoreInjectable),
+ }),
+ },
+);
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-page-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/terminal/terminal-page-preference-item.injectable.ts
new file mode 100644
index 0000000000..93c9b3892e
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-page-preference-item.injectable.ts
@@ -0,0 +1,25 @@
+/**
+ * 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 { preferenceItemInjectionToken } from "../preference-item-injection-token";
+import { TerminalPage } from "./terminal-page";
+import { HorizontalLine } from "../../../../../renderer/components/+preferences/horizontal-line/horizontal-line";
+
+const terminalPagePreferenceItemInjectable = getInjectable({
+ id: "terminal-preference-page",
+
+ instantiate: () => ({
+ kind: "page" as const,
+ id: "terminal-page",
+ parentId: "terminal-tab",
+ orderNumber: 0,
+ Component: TerminalPage,
+ childrenSeparator: HorizontalLine,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default terminalPagePreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-page.tsx b/src/features/preferences/renderer/preference-items/terminal/terminal-page.tsx
new file mode 100644
index 0000000000..a58be193ab
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-page.tsx
@@ -0,0 +1,14 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import React from "react";
+import type { PreferenceItemComponent } from "../preference-item-injection-token";
+
+export const TerminalPage: PreferenceItemComponent = ({ children }) => (
+
+
Terminal
+
+ {children}
+
+);
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-preference-tab.injectable.ts b/src/features/preferences/renderer/preference-items/terminal/terminal-preference-tab.injectable.ts
new file mode 100644
index 0000000000..4654e54c90
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-preference-tab.injectable.ts
@@ -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 { preferenceItemInjectionToken } from "../preference-item-injection-token";
+
+const terminalPreferenceTabInjectable = getInjectable({
+ id: "terminal-preference-tab",
+
+ instantiate: () => ({
+ kind: "tab" as const,
+ id: "terminal-tab",
+ pathId: "terminal",
+ parentId: "preference-tabs" as const,
+ testId: "terminal-preferences-page",
+ label: "Terminal",
+ orderNumber: 20,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default terminalPreferenceTabInjectable;
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path-preference-item.injectable.ts
new file mode 100644
index 0000000000..ef0cd88fa7
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * 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 { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { TerminalShellPath } from "./terminal-shell-path";
+
+const terminalShellPathPreferenceItemInjectable = getInjectable({
+ id: "terminal-shell-path-preference-item",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "terminal-shell-path",
+ parentId: "terminal-page",
+ orderNumber: 10,
+ Component: TerminalShellPath,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default terminalShellPathPreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx b/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx
new file mode 100644
index 0000000000..df8529c994
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-shell-path/terminal-shell-path.tsx
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+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 { Input } from "../../../../../../renderer/components/input";
+import defaultShellInjectable from "../../../../../../renderer/components/+preferences/default-shell.injectable";
+
+interface Dependencies {
+ userStore: UserStore;
+ defaultShell: string;
+}
+
+const NonInjectedTerminalShellPath = observer(
+ ({ userStore, defaultShell }: Dependencies) => {
+
+ return (
+
+
+ userStore.shell = value}
+ />
+
+
+ );
+ },
+);
+
+export const TerminalShellPath = withInjectables(
+ NonInjectedTerminalShellPath,
+
+ {
+ getProps: (di) => ({
+ userStore: di.inject(userStoreInjectable),
+ defaultShell: di.inject(defaultShellInjectable),
+ }),
+ },
+);
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme-preference-item.injectable.ts b/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme-preference-item.injectable.ts
new file mode 100644
index 0000000000..d292be0747
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme-preference-item.injectable.ts
@@ -0,0 +1,23 @@
+/**
+ * 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 { preferenceItemInjectionToken } from "../../preference-item-injection-token";
+import { TerminalTheme } from "./terminal-theme";
+
+const terminalThemePreferenceItemInjectable = getInjectable({
+ id: "terminal-theme",
+
+ instantiate: () => ({
+ kind: "item" as const,
+ id: "terminal-theme",
+ parentId: "terminal-page",
+ orderNumber: 30,
+ Component: TerminalTheme,
+ }),
+
+ injectionToken: preferenceItemInjectionToken,
+});
+
+export default terminalThemePreferenceItemInjectable;
diff --git a/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx b/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx
new file mode 100644
index 0000000000..c7819bacec
--- /dev/null
+++ b/src/features/preferences/renderer/preference-items/terminal/terminal-theme/terminal-theme.tsx
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+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 { Select } from "../../../../../../renderer/components/select";
+import themeStoreInjectable from "../../../../../../renderer/themes/store.injectable";
+import type { ThemeStore } from "../../../../../../renderer/themes/store";
+
+interface Dependencies {
+ userStore: UserStore;
+ themeStore: ThemeStore;
+}
+
+const NonInjectedTerminalTheme = observer(
+ ({ userStore, themeStore }: Dependencies) => {
+
+ const themeOptions = [
+ {
+ value: "", // TODO: replace with a sentinal value that isn't string (and serialize it differently)
+ label: "Match Lens Theme",
+ },
+ ...Array.from(themeStore.themes, ([themeId, { name }]) => ({
+ value: themeId,
+ label: name,
+ })),
+ ];
+
+ return (
+
+
+
+ );
+ },
+);
+
+export const TerminalTheme = withInjectables(
+ NonInjectedTerminalTheme,
+
+ {
+ getProps: (di) => ({
+ userStore: di.inject(userStoreInjectable),
+ themeStore: di.inject(themeStoreInjectable),
+ }),
+ },
+);