mirror of
https://github.com/NovaOSS/nova-betterchat.git
synced 2024-11-25 22:23:59 +01:00
parent
4f23af860e
commit
14795f5dd0
17
src/assets/icons/FileTextIcon.tsx
Normal file
17
src/assets/icons/FileTextIcon.tsx
Normal 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;
|
|
@ -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;
|
|
@ -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,6 +106,7 @@ 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'>
|
||||||
|
{markdownMode ? (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
remarkPlugins={[
|
remarkPlugins={[
|
||||||
remarkGfm,
|
remarkGfm,
|
||||||
|
@ -125,6 +131,9 @@ const ContentView = memo(
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</ReactMarkdown>
|
</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} />
|
||||||
|
|
|
@ -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,
|
||||||
|
}));
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -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>()(
|
||||||
|
|
Loading…
Reference in a new issue