feat(terminal): add Nerd Font support for Powerline themes (#29)

This commit is contained in:
Begonia, HE
2026-01-08 10:55:03 +08:00
committed by GitHub
parent 2646df346e
commit 146cbf8db0
4 changed files with 101 additions and 5 deletions
+3
View File
@@ -98,6 +98,7 @@
"@tanstack/react-query": "^5.90.12",
"@tanstack/react-query-devtools": "^5.91.1",
"@tanstack/react-router": "^1.143.6",
"@xterm/addon-canvas": "^0.7.0",
"@xterm/addon-fit": "^0.11.0",
"@xterm/addon-web-links": "^0.12.0",
"@xterm/xterm": "^6.0.0",
@@ -1032,6 +1033,8 @@
"@vueuse/shared": ["@vueuse/shared@12.8.2", "", { "dependencies": { "vue": "^3.5.13" } }, "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w=="],
"@xterm/addon-canvas": ["@xterm/addon-canvas@0.7.0", "", { "peerDependencies": { "@xterm/xterm": "^5.0.0" } }, "sha512-LF5LYcfvefJuJ7QotNRdRSPc9YASAVDeoT5uyXS/nZshZXjYplGXRECBGiznwvhNL2I8bq1Lf5MzRwstsYQ2Iw=="],
"@xterm/addon-fit": ["@xterm/addon-fit@0.11.0", "", {}, "sha512-jYcgT6xtVYhnhgxh3QgYDnnNMYTcf8ElbxxFzX0IZo+vabQqSPAjC3c1wJrKB5E19VwQei89QCiZZP86DCPF7g=="],
"@xterm/addon-web-links": ["@xterm/addon-web-links@0.12.0", "", {}, "sha512-4Smom3RPyVp7ZMYOYDoC/9eGJJJqYhnPLGGqJ6wOBfB8VxPViJNSKdgRYb8NpaM6YSelEKbA2SStD7lGyqaobw=="],
+1
View File
@@ -21,6 +21,7 @@
"@tanstack/react-query": "^5.90.12",
"@tanstack/react-query-devtools": "^5.91.1",
"@tanstack/react-router": "^1.143.6",
"@xterm/addon-canvas": "^0.7.0",
"@xterm/addon-fit": "^0.11.0",
"@xterm/addon-web-links": "^0.12.0",
"@xterm/xterm": "^6.0.0",
+16 -5
View File
@@ -1,8 +1,10 @@
import { useEffect, useRef } from 'react'
import { useEffect, useRef, useState } from 'react'
import { Terminal } from '@xterm/xterm'
import { FitAddon } from '@xterm/addon-fit'
import { WebLinksAddon } from '@xterm/addon-web-links'
import { CanvasAddon } from '@xterm/addon-canvas'
import '@xterm/xterm/css/xterm.css'
import { createFontProvider, type ITerminalFontProvider } from '@/lib/terminalFont'
function resolveThemeColors(): { background: string; foreground: string; selectionBackground: string } {
const styles = getComputedStyle(document.documentElement)
@@ -20,6 +22,12 @@ export function TerminalView(props: {
const containerRef = useRef<HTMLDivElement | null>(null)
const onMountRef = useRef(props.onMount)
const onResizeRef = useRef(props.onResize)
const [fontProvider, setFontProvider] = useState<ITerminalFontProvider | null>(null)
// Initialize font provider
useEffect(() => {
createFontProvider('default').then(setFontProvider)
}, [])
useEffect(() => {
onMountRef.current = props.onMount
@@ -31,14 +39,14 @@ export function TerminalView(props: {
useEffect(() => {
const container = containerRef.current
if (!container) {
if (!container || !fontProvider) {
return
}
const { background, foreground, selectionBackground } = resolveThemeColors()
const terminal = new Terminal({
cursorBlink: true,
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
fontFamily: fontProvider.getFontFamily(),
fontSize: 13,
theme: {
background,
@@ -46,13 +54,16 @@ export function TerminalView(props: {
cursor: foreground,
selectionBackground
},
convertEol: true
convertEol: true,
customGlyphs: true
})
const fitAddon = new FitAddon()
const webLinksAddon = new WebLinksAddon()
const canvasAddon = new CanvasAddon()
terminal.loadAddon(fitAddon)
terminal.loadAddon(webLinksAddon)
terminal.loadAddon(canvasAddon)
terminal.open(container)
const resizeTerminal = () => {
@@ -72,7 +83,7 @@ export function TerminalView(props: {
observer.disconnect()
terminal.dispose()
}
}, [])
}, [fontProvider])
return (
<div
+81
View File
@@ -0,0 +1,81 @@
/**
* Terminal Font Provider
*
* Provides font configuration for terminal rendering with Nerd Font support.
* Follows SOLID principles for easy extensibility.
*/
/**
* Terminal font provider interface
*/
export interface ITerminalFontProvider {
/**
* Get CSS fontFamily string for terminal
*/
getFontFamily(): string
/**
* Optional async initialization (for future smart detection)
*/
initialize?(): Promise<void>
}
/**
* Default font provider with hardcoded Nerd Font fallback list
*
* Includes common Nerd Fonts and system fallbacks.
* Zero runtime overhead - uses browser's native font fallback mechanism.
*/
export class DefaultFontProvider implements ITerminalFontProvider {
private static readonly NERD_FONTS = [
// Common Nerd Fonts (prioritized by popularity)
'JetBrainsMono Nerd Font',
'JetBrainsMonoNerdFont',
'FiraCode Nerd Font',
'FiraCodeNerdFont',
'Hack Nerd Font',
'HackNerdFont',
'MapleMono NF',
'Maple Mono NF',
'Iosevka Nerd Font',
'IosevkaNerdFont',
'CaskaydiaCove Nerd Font',
'MesloLGS Nerd Font',
'SourceCodePro Nerd Font',
'UbuntuMono Nerd Font'
]
private static readonly SYSTEM_FALLBACKS = [
'ui-monospace',
'SFMono-Regular',
'Menlo',
'Monaco',
'Consolas',
'"Liberation Mono"',
'"Courier New"',
'monospace'
]
getFontFamily(): string {
return [
...DefaultFontProvider.NERD_FONTS.map(f => `"${f}"`),
...DefaultFontProvider.SYSTEM_FALLBACKS
].join(', ')
}
}
/**
* Factory function to create font provider
*
* @param mode - Provider mode (currently only 'default', extensible for future)
* @returns Font provider instance
*/
export async function createFontProvider(
mode: 'default' = 'default'
): Promise<ITerminalFontProvider> {
switch (mode) {
case 'default':
default:
return new DefaultFontProvider()
}
}