feat: add React Developer Tools extension support and optimize CodeBlock component

This commit is contained in:
MyPrototypeWhat 2025-04-01 00:55:31 +08:00 committed by 亢奋猫
parent 32e1f428e7
commit 750247aef8
4 changed files with 24 additions and 19 deletions

View File

@ -1,7 +1,7 @@
import { electronApp, optimizer } from '@electron-toolkit/utils'
import { replaceDevtoolsFont } from '@main/utils/windowUtil'
import { app, ipcMain } from 'electron'
import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer'
import installExtension, { REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS } from 'electron-devtools-installer'
import { registerIpc } from './ipc'
import { configManager } from './services/ConfigManager'
@ -48,7 +48,7 @@ if (!app.requestSingleInstanceLock()) {
replaceDevtoolsFont(mainWindow)
if (process.env.NODE_ENV === 'development') {
installExtension(REDUX_DEVTOOLS)
installExtension([REDUX_DEVTOOLS, REACT_DEVELOPER_TOOLS])
.then((name) => console.log(`Added Extension: ${name}`))
.catch((err) => console.log('An error occurred: ', err))
}

View File

@ -17,6 +17,7 @@ import {
} from '@renderer/store/assistants'
import { setDefaultModel, setTopicNamingModel, setTranslateModel } from '@renderer/store/llm'
import { Assistant, AssistantSettings, Model, Topic } from '@renderer/types'
import { useCallback } from 'react'
import { TopicManager } from './useTopic'
@ -69,7 +70,10 @@ export function useAssistant(id: string) {
updateTopic: (topic: Topic) => dispatch(updateTopic({ assistantId: assistant.id, topic })),
updateTopics: (topics: Topic[]) => dispatch(updateTopics({ assistantId: assistant.id, topics })),
removeAllTopics: () => dispatch(removeAllTopics({ assistantId: assistant.id })),
setModel: (model: Model) => dispatch(setModel({ assistantId: assistant.id, model })),
setModel: useCallback(
(model: Model) => dispatch(setModel({ assistantId: assistant.id, model })),
[dispatch, assistant.id]
),
updateAssistant: (assistant: Assistant) => dispatch(updateAssistant(assistant)),
updateAssistantSettings: (settings: Partial<AssistantSettings>) => {
dispatch(updateAssistantSettings({ assistantId: assistant.id, settings }))

View File

@ -37,12 +37,17 @@ const CodeBlock: React.FC<CodeBlockProps> = ({ children, className }) => {
const showDownloadButton = ['csv', 'json', 'txt', 'md'].includes(language)
const shouldShowExpandButtonRef = useRef(false)
useEffect(() => {
const loadHighlightedCode = async () => {
const highlightedHtml = await codeToHtml(children, language)
if (codeContentRef.current) {
codeContentRef.current.innerHTML = highlightedHtml
setShouldShowExpandButton(codeContentRef.current.scrollHeight > 350)
const isShowExpandButton = codeContentRef.current.scrollHeight > 350
if (shouldShowExpandButtonRef.current === isShowExpandButton) return
shouldShowExpandButtonRef.current = isShowExpandButton
setShouldShowExpandButton(shouldShowExpandButtonRef.current)
}
}
loadHighlightedCode()
@ -98,15 +103,13 @@ const CodeBlock: React.FC<CodeBlockProps> = ({ children, className }) => {
)}
<CodeLanguage>{'<' + language.toUpperCase() + '>'}</CodeLanguage>
</div>
</CodeHeader>
<StickyWrapper>
<HStack
position="absolute"
gap={12}
alignItems="center"
style={{ bottom: '0.2rem', right: '1rem', height: "27px" }}
>
style={{ bottom: '0.2rem', right: '1rem', height: '27px' }}>
{showDownloadButton && <DownloadButton language={language} data={children} />}
{codeWrappable && <UnwrapButton unwrapped={isUnwrapped} onClick={() => setIsUnwrapped(!isUnwrapped)} />}
<CopyButton text={children} />

View File

@ -7,7 +7,7 @@ import { useSettings } from '@renderer/hooks/useSettings'
import type { Message } from '@renderer/types'
import { escapeBrackets, removeSvgEmptyLines, withGeminiGrounding } from '@renderer/utils/formats'
import { isEmpty } from 'lodash'
import { type FC, useCallback, useMemo } from 'react'
import { type FC, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import ReactMarkdown, { type Components } from 'react-markdown'
import rehypeKatex from 'rehype-katex'
@ -37,6 +37,8 @@ interface Props {
>
}
const remarkPlugins = [remarkMath, remarkGfm, remarkCjkFriendly]
const disallowedElements = ['iframe']
const Markdown: FC<Props> = ({ message, citationsData }) => {
const { t } = useTranslation()
const { renderInputMessageAsMarkdown, mathEngine } = useSettings()
@ -55,7 +57,7 @@ const Markdown: FC<Props> = ({ message, citationsData }) => {
return hasElements ? [rehypeRaw, rehypeMath] : [rehypeMath]
}, [messageContent, rehypeMath])
const components = useCallback(() => {
const components = useMemo(() => {
const baseComponents = {
a: (props: any) => {
if (props.href && citationsData?.has(props.href)) {
@ -65,15 +67,11 @@ const Markdown: FC<Props> = ({ message, citationsData }) => {
},
code: CodeBlock,
img: ImagePreview,
pre: (props: any) => <pre style={{ overflow: 'visible' }} {...props} />
pre: (props: any) => <pre style={{ overflow: 'visible' }} {...props} />,
style: MarkdownShadowDOMRenderer as any
} as Partial<Components>
if (messageContent.includes('<style>')) {
baseComponents.style = MarkdownShadowDOMRenderer as any
}
return baseComponents
}, [messageContent, citationsData])
}, [citationsData])
if (message.role === 'user' && !renderInputMessageAsMarkdown) {
return <p style={{ marginBottom: 5, whiteSpace: 'pre-wrap' }}>{messageContent}</p>
@ -82,10 +80,10 @@ const Markdown: FC<Props> = ({ message, citationsData }) => {
return (
<ReactMarkdown
rehypePlugins={rehypePlugins}
remarkPlugins={[remarkMath, remarkGfm, remarkCjkFriendly]}
remarkPlugins={remarkPlugins}
className="markdown"
components={components()}
disallowedElements={['iframe']}
components={components}
disallowedElements={disallowedElements}
remarkRehypeOptions={{
footnoteLabel: t('common.footnotes'),
footnoteLabelTagName: 'h4',