From a4c32ee05bbf16e2a4fdcf8a26a7e796dc56fd82 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Wed, 13 May 2026 18:58:26 +0800 Subject: [PATCH] feat: add mobile terminal font selection --- app/contexts/TerminalCustomizationContext.tsx | 14 +- app/tabs/sessions/terminal/Terminal.tsx | 2 +- app/tabs/settings/TerminalCustomization.tsx | 146 +++++++++++++----- 3 files changed, 118 insertions(+), 44 deletions(-) diff --git a/app/contexts/TerminalCustomizationContext.tsx b/app/contexts/TerminalCustomizationContext.tsx index 2b2c17e..1e65280 100644 --- a/app/contexts/TerminalCustomizationContext.tsx +++ b/app/contexts/TerminalCustomizationContext.tsx @@ -22,6 +22,7 @@ interface TerminalCustomizationContextType { resetConfig: () => Promise; updateFontSize: (fontSize: number) => Promise; + updateFontFamily: (fontFamily: string) => Promise; resetToDefault: () => Promise; } @@ -42,7 +43,10 @@ export const TerminalCustomizationProvider: React.FC<{ const stored = await AsyncStorage.getItem(STORAGE_KEY); if (stored) { const parsed = JSON.parse(stored) as Partial; - setConfig(parsed); + setConfig({ + ...getDefaultConfig(), + ...parsed, + }); } } catch (error) { console.error("Failed to load terminal configuration:", error); @@ -85,6 +89,13 @@ export const TerminalCustomizationProvider: React.FC<{ [updateConfig], ); + const updateFontFamily = useCallback( + async (fontFamily: string) => { + await updateConfig({ fontFamily }); + }, + [updateConfig], + ); + const resetToDefault = useCallback(async () => { await resetConfig(); }, [resetConfig]); @@ -95,6 +106,7 @@ export const TerminalCustomizationProvider: React.FC<{ updateConfig, resetConfig, updateFontSize, + updateFontFamily, resetToDefault, }; diff --git a/app/tabs/sessions/terminal/Terminal.tsx b/app/tabs/sessions/terminal/Terminal.tsx index 3c84ab3..707646e 100644 --- a/app/tabs/sessions/terminal/Terminal.tsx +++ b/app/tabs/sessions/terminal/Terminal.tsx @@ -272,7 +272,7 @@ const TerminalComponent = forwardRef( } .xterm .xterm-screen { - font-family: 'Caskaydia Cove Nerd Font Mono', 'SF Mono', Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace !important; + font-family: ${fontFamily} !important; font-variant-ligatures: contextual; } diff --git a/app/tabs/settings/TerminalCustomization.tsx b/app/tabs/settings/TerminalCustomization.tsx index 1170107..1427682 100644 --- a/app/tabs/settings/TerminalCustomization.tsx +++ b/app/tabs/settings/TerminalCustomization.tsx @@ -14,6 +14,7 @@ import { useRouter } from "expo-router"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useTerminalCustomization } from "@/app/contexts/TerminalCustomizationContext"; import { showToast } from "@/app/utils/toast"; +import { TERMINAL_FONTS } from "@/constants/terminal-themes"; const FONT_SIZE_OPTIONS = [ { label: "Extra Small", value: 12 }, @@ -27,7 +28,8 @@ const FONT_SIZE_OPTIONS = [ export default function TerminalCustomization() { const router = useRouter(); const insets = useSafeAreaInsets(); - const { config, updateFontSize, resetToDefault } = useTerminalCustomization(); + const { config, updateFontFamily, updateFontSize, resetToDefault } = + useTerminalCustomization(); const [showResetConfirm, setShowResetConfirm] = useState(false); const [customFontSize, setCustomFontSize] = useState(""); const [showCustomInput, setShowCustomInput] = useState(false); @@ -40,17 +42,26 @@ export default function TerminalCustomization() { try { await updateFontSize(fontSize); showToast.success(`Font size updated to ${fontSize}px`); - } catch (error) { + } catch { showToast.error("Failed to update font size"); } }; + const handleFontFamilyChange = async (fontFamily: string, label: string) => { + try { + await updateFontFamily(fontFamily); + showToast.success(`Font updated to ${label}`); + } catch { + showToast.error("Failed to update font"); + } + }; + const handleReset = async () => { try { await resetToDefault(); showToast.success("Terminal settings reset to default"); setShowResetConfirm(false); - } catch (error) { + } catch { showToast.error("Failed to reset settings"); } }; @@ -66,7 +77,7 @@ export default function TerminalCustomization() { showToast.success(`Font size updated to ${fontSize}px`); setShowCustomInput(false); setCustomFontSize(""); - } catch (error) { + } catch { showToast.error("Failed to update font size"); } }; @@ -74,16 +85,16 @@ export default function TerminalCustomization() { return ( router.back()}> - + ← Back - + Terminal Customization @@ -94,18 +105,69 @@ export default function TerminalCustomization() { className="flex-1 px-4 py-4" contentContainerStyle={{ paddingBottom: Math.max(insets.bottom, 16) }} > - + Terminal Settings - + Customize terminal appearance and behavior - + Font + + Select the terminal font family. Nerd Font support depends on the + selected font being available to the WebView. + + + {TERMINAL_FONTS.map((option) => { + const isActive = config.fontFamily === option.value; + return ( + + handleFontFamilyChange(option.value, option.label) + } + className={`rounded-lg border p-4 ${ + isActive + ? "border-green-500 bg-green-900/20" + : "border-[#303032] bg-[#1a1a1a]" + }`} + > + + + + {option.label} + + + Aa Bb Cc 123  + + + {isActive && ( + + + ACTIVE + + + )} + + + ); + })} + + + + + Font Size - + Base font size for terminal text. The actual size will be adjusted based on your screen width. This number will override the font size you configured on a host in the Termix Web UI. @@ -115,10 +177,10 @@ export default function TerminalCustomization() { handleFontSizeChange(option.value)} - className={`p-4 rounded-lg border ${ + className={`rounded-lg border p-4 ${ config.fontSize === option.value - ? "bg-green-900/20 border-green-500" - : "bg-[#1a1a1a] border-[#303032]" + ? "border-green-500 bg-green-900/20" + : "border-[#303032] bg-[#1a1a1a]" }`} > @@ -132,13 +194,13 @@ export default function TerminalCustomization() { > {option.label} - + {option.value}px base size {config.fontSize === option.value && ( - - + + ACTIVE @@ -149,10 +211,10 @@ export default function TerminalCustomization() { setShowCustomInput(true)} - className={`p-4 rounded-lg border ${ + className={`rounded-lg border p-4 ${ isCustomFontSize - ? "bg-green-900/20 border-green-500" - : "bg-[#1a1a1a] border-[#303032]" + ? "border-green-500 bg-green-900/20" + : "border-[#303032] bg-[#1a1a1a]" }`} > @@ -164,15 +226,15 @@ export default function TerminalCustomization() { > Custom - + {isCustomFontSize ? `${config.fontSize}px base size` : "Enter any custom size"} {isCustomFontSize && ( - - + + ACTIVE @@ -184,9 +246,9 @@ export default function TerminalCustomization() { setShowResetConfirm(true)} - className="bg-red-900/20 border border-red-700 rounded-lg p-3" + className="rounded-lg border border-red-700 bg-red-900/20 p-3" > - + Reset to Default @@ -207,17 +269,17 @@ export default function TerminalCustomization() { className="flex-1" > { setShowCustomInput(false); setCustomFontSize(""); }} > - - + + Custom Font Size - + Enter your preferred font size for the terminal. - + { setShowCustomInput(false); setCustomFontSize(""); }} - className="flex-1 bg-[#27272a] border border-[#3f3f46] rounded-lg p-3" + className="flex-1 rounded-lg border border-[#3f3f46] bg-[#27272a] p-3" > - + Cancel - + Apply @@ -272,30 +334,30 @@ export default function TerminalCustomization() { supportedOrientations={["portrait", "landscape"]} > setShowResetConfirm(false)} > - - + + Confirm Reset - + This will reset all terminal customizations to default settings. setShowResetConfirm(false)} - className="flex-1 bg-[#27272a] border border-[#3f3f46] rounded-lg p-3" + className="flex-1 rounded-lg border border-[#3f3f46] bg-[#27272a] p-3" > - + Cancel - + Reset