mirror of
http://112.124.100.131/huang.ze/ebiz-dify-ai.git
synced 2025-12-10 19:36:53 +08:00
Feat: web app dark mode (#14732)
This commit is contained in:
@@ -7,11 +7,14 @@ import RehypeKatex from 'rehype-katex'
|
||||
import RemarkGfm from 'remark-gfm'
|
||||
import RehypeRaw from 'rehype-raw'
|
||||
import SyntaxHighlighter from 'react-syntax-highlighter'
|
||||
import { atelierHeathLight } from 'react-syntax-highlighter/dist/esm/styles/hljs'
|
||||
import {
|
||||
atelierHeathDark,
|
||||
atelierHeathLight,
|
||||
} from 'react-syntax-highlighter/dist/esm/styles/hljs'
|
||||
import { Component, memo, useMemo, useRef, useState } from 'react'
|
||||
import { flow } from 'lodash-es'
|
||||
import cn from '@/utils/classnames'
|
||||
import CopyBtn from '@/app/components/base/copy-btn'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import CopyIcon from '@/app/components/base/copy-icon'
|
||||
import SVGBtn from '@/app/components/base/svg'
|
||||
import Flowchart from '@/app/components/base/mermaid'
|
||||
import ImageGallery from '@/app/components/base/image-gallery'
|
||||
@@ -22,6 +25,9 @@ import SVGRenderer from '@/app/components/base/svg-gallery'
|
||||
import MarkdownButton from '@/app/components/base/markdown-blocks/button'
|
||||
import MarkdownForm from '@/app/components/base/markdown-blocks/form'
|
||||
import ThinkBlock from '@/app/components/base/markdown-blocks/think-block'
|
||||
import { Theme } from '@/types/app'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
// Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD
|
||||
const capitalizationLanguageNameMap: Record<string, string> = {
|
||||
@@ -100,7 +106,8 @@ export function PreCode(props: { children: any }) {
|
||||
// visit https://reactjs.org/docs/error-decoder.html?invariant=185 for the full message
|
||||
// or use the non-minified dev environment for full errors and additional helpful warnings.
|
||||
|
||||
const CodeBlock: any = memo(({ inline, className, children, ...props }) => {
|
||||
const CodeBlock: any = memo(({ inline, className, children, ...props }: any) => {
|
||||
const { theme } = useAppContext()
|
||||
const [isSVG, setIsSVG] = useState(true)
|
||||
const match = /language-(\w+)/.exec(className || '')
|
||||
const language = match?.[1]
|
||||
@@ -140,10 +147,12 @@ const CodeBlock: any = memo(({ inline, className, children, ...props }) => {
|
||||
return (
|
||||
<SyntaxHighlighter
|
||||
{...props}
|
||||
style={atelierHeathLight}
|
||||
style={theme === Theme.light ? atelierHeathLight : atelierHeathDark}
|
||||
customStyle={{
|
||||
paddingLeft: 12,
|
||||
backgroundColor: '#fff',
|
||||
borderBottomLeftRadius: '10px',
|
||||
borderBottomRightRadius: '10px',
|
||||
backgroundColor: 'var(--color-components-input-bg-normal)',
|
||||
}}
|
||||
language={match?.[1]}
|
||||
showLineNumbers
|
||||
@@ -159,21 +168,14 @@ const CodeBlock: any = memo(({ inline, className, children, ...props }) => {
|
||||
return <code {...props} className={className}>{children}</code>
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className='flex justify-between h-8 items-center p-1 pl-3 border-b'
|
||||
style={{
|
||||
borderColor: 'rgba(0, 0, 0, 0.05)',
|
||||
}}
|
||||
>
|
||||
<div className='text-[13px] text-gray-500 font-normal'>{languageShowName}</div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div className='relative'>
|
||||
<div className='bg-components-input-bg-normal rounded-t-[10px] flex justify-between h-8 items-center p-1 pl-3 border-b border-divider-subtle'>
|
||||
<div className='system-xs-semibold-uppercase text-text-secondary'>{languageShowName}</div>
|
||||
<div className='flex items-center gap-1'>
|
||||
{(['mermaid', 'svg']).includes(language!) && <SVGBtn isSVG={isSVG} setIsSVG={setIsSVG} />}
|
||||
<CopyBtn
|
||||
className='mr-1'
|
||||
value={String(children).replace(/\n$/, '')}
|
||||
isPlain
|
||||
/>
|
||||
<ActionButton>
|
||||
<CopyIcon content={String(children).replace(/\n$/, '')}/>
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
{renderCodeContent}
|
||||
@@ -182,16 +184,16 @@ const CodeBlock: any = memo(({ inline, className, children, ...props }) => {
|
||||
})
|
||||
CodeBlock.displayName = 'CodeBlock'
|
||||
|
||||
const VideoBlock: any = memo(({ node }) => {
|
||||
const srcs = node.children.filter(child => 'properties' in child).map(child => (child as any).properties.src)
|
||||
const VideoBlock: any = memo(({ node }: any) => {
|
||||
const srcs = node.children.filter((child: any) => 'properties' in child).map((child: any) => (child as any).properties.src)
|
||||
if (srcs.length === 0)
|
||||
return null
|
||||
return <VideoGallery key={srcs.join()} srcs={srcs} />
|
||||
})
|
||||
VideoBlock.displayName = 'VideoBlock'
|
||||
|
||||
const AudioBlock: any = memo(({ node }) => {
|
||||
const srcs = node.children.filter(child => 'properties' in child).map(child => (child as any).properties.src)
|
||||
const AudioBlock: any = memo(({ node }: any) => {
|
||||
const srcs = node.children.filter((child: any) => 'properties' in child).map((child: any) => (child as any).properties.src)
|
||||
if (srcs.length === 0)
|
||||
return null
|
||||
return <AudioGallery key={srcs.join()} srcs={srcs} />
|
||||
@@ -243,7 +245,7 @@ export function Markdown(props: { content: string; className?: string }) {
|
||||
preprocessLaTeX,
|
||||
])(props.content)
|
||||
return (
|
||||
<div className={cn(props.className, 'markdown-body')}>
|
||||
<div className={cn('markdown-body', '!text-text-primary', props.className)}>
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[
|
||||
RemarkGfm,
|
||||
@@ -282,7 +284,7 @@ export function Markdown(props: { content: string; className?: string }) {
|
||||
p: Paragraph,
|
||||
button: MarkdownButton,
|
||||
form: MarkdownForm,
|
||||
script: ScriptBlock,
|
||||
script: ScriptBlock as any,
|
||||
details: ThinkBlock,
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user