From 8ccd9595f5ca31a370813c720d4a171ee543c399 Mon Sep 17 00:00:00 2001 From: lone-cloud Date: Fri, 22 Aug 2025 22:00:42 -0700 Subject: [PATCH] fix some dark mode issues, still battling the terminal to display wget progress displays --- package.json | 1 - src/components/DownloadCard.tsx | 10 +- .../screens/Interface/TerminalTab.tsx | 119 ++++++------------ src/components/settings/AppearanceTab.tsx | 17 +-- yarn.lock | 19 --- 5 files changed, 52 insertions(+), 114 deletions(-) diff --git a/package.json b/package.json index 89cbc55..74e54ec 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,6 @@ "dependencies": { "@mantine/core": "^8.2.7", "@mantine/hooks": "^8.2.7", - "ansi-to-html": "^0.7.2", "execa": "^9.6.0", "got": "^14.4.7", "lucide-react": "^0.541.0", diff --git a/src/components/DownloadCard.tsx b/src/components/DownloadCard.tsx index 3104b1f..d0458ed 100644 --- a/src/components/DownloadCard.tsx +++ b/src/components/DownloadCard.tsx @@ -8,6 +8,7 @@ import { Loader, Progress, rem, + useComputedColorScheme, } from '@mantine/core'; import { Download } from 'lucide-react'; import { MouseEvent } from 'react'; @@ -46,6 +47,10 @@ export const DownloadCard = ({ onMakeCurrent, onUpdate, }: DownloadCardProps) => { + const computedColorScheme = useComputedColorScheme('light', { + getInitialValueInEffect: false, + }); + const isDark = computedColorScheme === 'dark'; const renderActionButton = () => { if (hasUpdate && onUpdate) { return ( @@ -107,9 +112,8 @@ export const DownloadCard = ({ radius="sm" padding="sm" {...(isCurrent && { - c: 'blue', - bg: 'blue.0', - bd: '2px solid blue', + bg: isDark ? 'dark.6' : 'gray.0', + bd: `2px solid var(--mantine-color-${isDark ? 'blue-4' : 'blue-6'})`, })} > diff --git a/src/components/screens/Interface/TerminalTab.tsx b/src/components/screens/Interface/TerminalTab.tsx index 944613c..c5b1ea8 100644 --- a/src/components/screens/Interface/TerminalTab.tsx +++ b/src/components/screens/Interface/TerminalTab.tsx @@ -1,13 +1,12 @@ -import { useState, useEffect, useRef, useCallback } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { Box, ScrollArea, Text, ActionIcon, - useMantineColorScheme, + useComputedColorScheme, } from '@mantine/core'; import { ChevronDown } from 'lucide-react'; -import Convert from 'ansi-to-html'; import styles from '@/styles/layout.module.css'; import { UI } from '@/constants'; @@ -39,19 +38,20 @@ const handleCarriageReturns = ( } else { const lines = result.split('\n'); if (lines.length > 0) { - const lastLineIndex = lines.length - 1; const restOfData = newData.slice(i + 1); - const nextCrOrLfIndex = restOfData.search(/[\r\n]/); + const nextNewlinePos = restOfData.indexOf('\n'); + const replacementText = + nextNewlinePos === -1 + ? restOfData + : restOfData.slice(0, nextNewlinePos); - if (nextCrOrLfIndex === -1) { - lines[lastLineIndex] = restOfData; - result = lines.join('\n'); - break; - } else { - const replacement = restOfData.slice(0, nextCrOrLfIndex); - lines[lastLineIndex] = replacement; - result = lines.join('\n'); - i += 1 + nextCrOrLfIndex; + lines[lines.length - 1] = replacementText; + result = lines.join('\n'); + + i += 1 + replacementText.length; + if (nextNewlinePos !== -1) { + result += '\n'; + i += 1; } } else { i++; @@ -64,64 +64,24 @@ const handleCarriageReturns = ( } return result; - } catch { + } catch (error) { + window.electronAPI.logs.logError('Terminal CR Error', error as Error); return prevContent + newData; } }; export const TerminalTab = ({ onServerReady }: TerminalTabProps) => { - const { colorScheme } = useMantineColorScheme(); + const computedColorScheme = useComputedColorScheme('light', { + getInitialValueInEffect: false, + }); const [terminalContent, setTerminalContent] = useState(''); - const [formattedContent, setFormattedContent] = useState(''); const [isUserScrolling, setIsUserScrolling] = useState(false); const [shouldAutoScroll, setShouldAutoScroll] = useState(true); const scrollAreaRef = useRef(null); const viewportRef = useRef(null); const lastScrollTop = useRef(0); - const updateTimeoutRef = useRef(null); - const pendingContentRef = useRef(''); - const debouncedUpdateContent = useCallback((newContent: string) => { - pendingContentRef.current = newContent; - - if (updateTimeoutRef.current) { - clearTimeout(updateTimeoutRef.current); - } - - updateTimeoutRef.current = window.setTimeout(() => { - setTerminalContent(pendingContentRef.current); - updateTimeoutRef.current = null; - }, 16); - }, []); - - const converter = useRef( - new Convert({ - fg: colorScheme === 'dark' ? '#ffffff' : '#000000', - bg: colorScheme === 'dark' ? '#1a1b1e' : '#ffffff', - newline: false, - escapeXML: true, - stream: false, - }) - ); - - useEffect(() => { - converter.current = new Convert({ - fg: colorScheme === 'dark' ? '#ffffff' : '#000000', - bg: colorScheme === 'dark' ? '#1a1b1e' : '#ffffff', - newline: false, - escapeXML: true, - stream: false, - }); - if (terminalContent) { - setFormattedContent(converter.current.toHtml(terminalContent)); - } - }, [colorScheme, terminalContent]); - - useEffect(() => { - if (terminalContent) { - setFormattedContent(converter.current.toHtml(terminalContent)); - } - }, [terminalContent]); + const isDark = computedColorScheme === 'dark'; const handleScroll = ({ y }: { y: number }) => { if (!viewportRef.current) return; @@ -145,7 +105,7 @@ export const TerminalTab = ({ onServerReady }: TerminalTabProps) => { const viewport = viewportRef.current; viewport.scrollTop = viewport.scrollHeight; } - }, [formattedContent, shouldAutoScroll, isUserScrolling]); + }, [terminalContent, shouldAutoScroll, isUserScrolling]); useEffect(() => { const cleanup = window.electronAPI.kobold.onKoboldOutput((data: string) => { @@ -165,19 +125,12 @@ export const TerminalTab = ({ onServerReady }: TerminalTabProps) => { } } - const newContent = handleCarriageReturns(prev, newData); - - if (newData.includes('\r') && !newData.includes('\n')) { - debouncedUpdateContent(newContent); - return prev; - } - - return newContent; + return handleCarriageReturns(prev, newData); }); }); return cleanup; - }, [onServerReady, debouncedUpdateContent]); + }, [onServerReady]); const scrollToBottom = () => { if (viewportRef.current) { @@ -194,10 +147,9 @@ export const TerminalTab = ({ onServerReady }: TerminalTabProps) => { height: `calc(100vh - ${UI.HEADER_HEIGHT}px)`, display: 'flex', flexDirection: 'column', - backgroundColor: - colorScheme === 'dark' - ? 'var(--mantine-color-dark-filled)' - : 'var(--mantine-color-gray-0)', + backgroundColor: isDark + ? 'var(--mantine-color-dark-filled)' + : 'var(--mantine-color-gray-0)', borderRadius: 'inherit', position: 'relative', }} @@ -219,18 +171,19 @@ export const TerminalTab = ({ onServerReady }: TerminalTabProps) => {
+ > + {terminalContent} +
)} diff --git a/src/components/settings/AppearanceTab.tsx b/src/components/settings/AppearanceTab.tsx index 2376758..41f7368 100644 --- a/src/components/settings/AppearanceTab.tsx +++ b/src/components/settings/AppearanceTab.tsx @@ -1,9 +1,13 @@ import { Stack, Text, Group, SegmentedControl, rem } from '@mantine/core'; -import { useMantineColorScheme } from '@mantine/core'; +import { useMantineColorScheme, useComputedColorScheme } from '@mantine/core'; import { Sun, Moon, Monitor } from 'lucide-react'; export const AppearanceTab = () => { const { colorScheme, setColorScheme } = useMantineColorScheme(); + const computedColorScheme = useComputedColorScheme('light', { + getInitialValueInEffect: false, + }); + const isDark = computedColorScheme === 'dark'; return ( @@ -22,14 +26,11 @@ export const AppearanceTab = () => { } styles={(theme) => ({ indicator: { - backgroundColor: - colorScheme === 'dark' - ? theme.colors.dark[5] - : theme.colors.gray[2], + backgroundColor: isDark + ? theme.colors.dark[5] + : theme.colors.gray[2], border: `1px solid ${ - colorScheme === 'dark' - ? theme.colors.dark[4] - : theme.colors.gray[4] + isDark ? theme.colors.dark[4] : theme.colors.gray[4] }`, }, })} diff --git a/yarn.lock b/yarn.lock index c5d9dd8..a22aea9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2233,17 +2233,6 @@ __metadata: languageName: node linkType: hard -"ansi-to-html@npm:^0.7.2": - version: 0.7.2 - resolution: "ansi-to-html@npm:0.7.2" - dependencies: - entities: "npm:^2.2.0" - bin: - ansi-to-html: bin/ansi-to-html - checksum: 10c0/031da78f716e7c6b0e391c64f7bc5e95f2d37123dcc3237d8c592dc35830dd0da05e0c3f3e3f8179856cfe5fd85c689d2ad85024b71b50014da9ef6e8fa021cf - languageName: node - linkType: hard - "app-builder-bin@npm:5.0.0-alpha.12": version: 5.0.0-alpha.12 resolution: "app-builder-bin@npm:5.0.0-alpha.12" @@ -3603,13 +3592,6 @@ __metadata: languageName: node linkType: hard -"entities@npm:^2.2.0": - version: 2.2.0 - resolution: "entities@npm:2.2.0" - checksum: 10c0/7fba6af1f116300d2ba1c5673fc218af1961b20908638391b4e1e6d5850314ee2ac3ec22d741b3a8060479911c99305164aed19b6254bde75e7e6b1b2c3f3aa3 - languageName: node - linkType: hard - "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -4409,7 +4391,6 @@ __metadata: "@typescript-eslint/eslint-plugin": "npm:^8.40.0" "@typescript-eslint/parser": "npm:^8.40.0" "@vitejs/plugin-react": "npm:^5.0.1" - ansi-to-html: "npm:^0.7.2" cross-env: "npm:^10.0.0" cspell: "npm:^9.2.0" electron: "npm:^37.3.1"