feat: toggle markdown or plaintext view

fixes #242
This commit is contained in:
Jing Hua 2023-04-21 17:54:08 +08:00
parent 4f23af860e
commit 14795f5dd0
5 changed files with 85 additions and 24 deletions

View file

@ -0,0 +1,17 @@
import React from 'react';
const FileTextIcon = (props: React.SVGProps<SVGSVGElement>) => {
return (
<svg
viewBox='0 0 1024 1024'
fill='currentColor'
height='1em'
width='1em'
{...props}
>
<path d='M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z' />
</svg>
);
};
export default FileTextIcon;

View file

@ -0,0 +1,24 @@
import React, { useState } from 'react';
import useStore from '@store/store';
import BaseButton from './BaseButton';
import MarkdownIcon from '@icon/MarkdownIcon';
import FileTextIcon from '@icon/FileTextIcon';
const MarkdownModeButton = () => {
const markdownMode = useStore((state) => state.markdownMode);
const setMarkdownMode = useStore((state) => state.setMarkdownMode);
return (
<BaseButton
icon={markdownMode ? <MarkdownIcon /> : <FileTextIcon />}
onClick={() => {
setMarkdownMode(!markdownMode);
}}
/>
);
};
export default MarkdownModeButton;

View file

@ -29,6 +29,8 @@ import DownButton from './Button/DownButton';
import CopyButton from './Button/CopyButton'; import CopyButton from './Button/CopyButton';
import EditButton from './Button/EditButton'; import EditButton from './Button/EditButton';
import DeleteButton from './Button/DeleteButton'; import DeleteButton from './Button/DeleteButton';
import MarkdownModeButton from './Button/MarkdownModeButton';
import CodeBlock from '../CodeBlock'; import CodeBlock from '../CodeBlock';
const ContentView = memo( const ContentView = memo(
@ -44,13 +46,16 @@ const ContentView = memo(
messageIndex: number; messageIndex: number;
}) => { }) => {
const { handleSubmit } = useSubmit(); const { handleSubmit } = useSubmit();
const [isDelete, setIsDelete] = useState<boolean>(false); const [isDelete, setIsDelete] = useState<boolean>(false);
const currentChatIndex = useStore((state) => state.currentChatIndex); const currentChatIndex = useStore((state) => state.currentChatIndex);
const setChats = useStore((state) => state.setChats); const setChats = useStore((state) => state.setChats);
const lastMessageIndex = useStore((state) => const lastMessageIndex = useStore((state) =>
state.chats ? state.chats[state.currentChatIndex].messages.length - 1 : 0 state.chats ? state.chats[state.currentChatIndex].messages.length - 1 : 0
); );
const inlineLatex = useStore((state) => state.inlineLatex); const inlineLatex = useStore((state) => state.inlineLatex);
const markdownMode = useStore((state) => state.markdownMode);
const handleDelete = () => { const handleDelete = () => {
const updatedChats: ChatInterface[] = JSON.parse( const updatedChats: ChatInterface[] = JSON.parse(
@ -101,30 +106,34 @@ const ContentView = memo(
return ( return (
<> <>
<div className='markdown prose w-full md:max-w-full break-words dark:prose-invert dark share-gpt-message'> <div className='markdown prose w-full md:max-w-full break-words dark:prose-invert dark share-gpt-message'>
<ReactMarkdown {markdownMode ? (
remarkPlugins={[ <ReactMarkdown
remarkGfm, remarkPlugins={[
[remarkMath, { singleDollarTextMath: inlineLatex }], remarkGfm,
]} [remarkMath, { singleDollarTextMath: inlineLatex }],
rehypePlugins={[ ]}
rehypeKatex, rehypePlugins={[
[ rehypeKatex,
rehypeHighlight, [
{ rehypeHighlight,
detect: true, {
ignoreMissing: true, detect: true,
subset: codeLanguageSubset, ignoreMissing: true,
}, subset: codeLanguageSubset,
], },
]} ],
linkTarget='_new' ]}
components={{ linkTarget='_new'
code, components={{
p, code,
}} p,
> }}
{content} >
</ReactMarkdown> {content}
</ReactMarkdown>
) : (
<span className='whitespace-pre-wrap'>{content}</span>
)}
</div> </div>
<div className='flex justify-end gap-2 w-full mt-2'> <div className='flex justify-end gap-2 w-full mt-2'>
{isDelete || ( {isDelete || (
@ -139,6 +148,7 @@ const ContentView = memo(
<DownButton onClick={handleMoveDown} /> <DownButton onClick={handleMoveDown} />
)} )}
<MarkdownModeButton />
<CopyButton onClick={handleCopy} /> <CopyButton onClick={handleCopy} />
<EditButton setIsEdit={setIsEdit} /> <EditButton setIsEdit={setIsEdit} />
<DeleteButton setIsDelete={setIsDelete} /> <DeleteButton setIsDelete={setIsDelete} />

View file

@ -14,6 +14,7 @@ export interface ConfigSlice {
hideSideMenu: boolean; hideSideMenu: boolean;
enterToSubmit: boolean; enterToSubmit: boolean;
inlineLatex: boolean; inlineLatex: boolean;
markdownMode: boolean;
setOpenConfig: (openConfig: boolean) => void; setOpenConfig: (openConfig: boolean) => void;
setTheme: (theme: Theme) => void; setTheme: (theme: Theme) => void;
setAutoTitle: (autoTitle: boolean) => void; setAutoTitle: (autoTitle: boolean) => void;
@ -24,6 +25,7 @@ export interface ConfigSlice {
setHideSideMenu: (hideSideMenu: boolean) => void; setHideSideMenu: (hideSideMenu: boolean) => void;
setEnterToSubmit: (enterToSubmit: boolean) => void; setEnterToSubmit: (enterToSubmit: boolean) => void;
setInlineLatex: (inlineLatex: boolean) => void; setInlineLatex: (inlineLatex: boolean) => void;
setMarkdownMode: (markdownMode: boolean) => void;
} }
export const createConfigSlice: StoreSlice<ConfigSlice> = (set, get) => ({ export const createConfigSlice: StoreSlice<ConfigSlice> = (set, get) => ({
@ -37,6 +39,7 @@ export const createConfigSlice: StoreSlice<ConfigSlice> = (set, get) => ({
defaultChatConfig: _defaultChatConfig, defaultChatConfig: _defaultChatConfig,
defaultSystemMessage: _defaultSystemMessage, defaultSystemMessage: _defaultSystemMessage,
inlineLatex: false, inlineLatex: false,
markdownMode: true,
setOpenConfig: (openConfig: boolean) => { setOpenConfig: (openConfig: boolean) => {
set((prev: ConfigSlice) => ({ set((prev: ConfigSlice) => ({
...prev, ...prev,
@ -97,4 +100,10 @@ export const createConfigSlice: StoreSlice<ConfigSlice> = (set, get) => ({
inlineLatex: inlineLatex, inlineLatex: inlineLatex,
})); }));
}, },
setMarkdownMode: (markdownMode: boolean) => {
set((prev: ConfigSlice) => ({
...prev,
markdownMode: markdownMode,
}));
},
}); });

View file

@ -56,6 +56,7 @@ export const createPartializedState = (state: StoreState) => ({
folders: state.folders, folders: state.folders,
enterToSubmit: state.enterToSubmit, enterToSubmit: state.enterToSubmit,
inlineLatex: state.inlineLatex, inlineLatex: state.inlineLatex,
markdownMode: state.markdownMode,
}); });
const useStore = create<StoreState>()( const useStore = create<StoreState>()(