mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-25 12:48:53 +01:00
style: temporarily remove scrolling, add better styling
This commit is contained in:
parent
e026fc7009
commit
ee126a2350
4 changed files with 63 additions and 65 deletions
|
|
@ -32,6 +32,7 @@ const ArtifactButton = ({ artifact }: { artifact: Artifact | null }) => {
|
|||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<br />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as Tabs from '@radix-ui/react-tabs';
|
||||
import { getFileExtension } from '~/utils/artifacts';
|
||||
import useArtifacts from '~/hooks/Artifacts/useArtifacts';
|
||||
import { CodeMarkdown, CopyCodeButton } from './Code';
|
||||
import { getFileExtension } from '~/utils/artifacts';
|
||||
import { ArtifactPreview } from './ArtifactPreview';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
|
|
@ -10,7 +10,6 @@ export default function Artifacts() {
|
|||
isVisible,
|
||||
activeTab,
|
||||
setActiveTab,
|
||||
isSubmitting,
|
||||
currentIndex,
|
||||
cycleArtifact,
|
||||
currentArtifact,
|
||||
|
|
@ -80,19 +79,13 @@ export default function Artifacts() {
|
|||
{/* Content */}
|
||||
<Tabs.Content
|
||||
value="code"
|
||||
className={cn(
|
||||
'flex-grow overflow-auto bg-gray-900',
|
||||
isSubmitting ? 'submitting' : '',
|
||||
isSubmitting && (currentArtifact.content?.length ?? 0) > 0 ? 'result-streaming' : '',
|
||||
)}
|
||||
className={cn('flex-grow overflow-x-auto overflow-y-scroll bg-gray-900 p-4')}
|
||||
>
|
||||
<CodeMarkdown
|
||||
showCursor={isSubmitting}
|
||||
content={`\`\`\`${getFileExtension(currentArtifact.type)}\n${
|
||||
currentArtifact.content ?? ''
|
||||
}\`\`\``}
|
||||
/>
|
||||
{/* hidden div to scroll to could go here */}
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="preview" className="flex-grow overflow-auto bg-white">
|
||||
<ArtifactPreview artifact={currentArtifact} />
|
||||
|
|
|
|||
|
|
@ -1,36 +1,13 @@
|
|||
import React, { useRef, RefObject, memo, useState } from 'react';
|
||||
import React, { memo, useState } from 'react';
|
||||
import rehypeKatex from 'rehype-katex';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import rehypeHighlight from 'rehype-highlight';
|
||||
import copy from 'copy-to-clipboard';
|
||||
import { handleDoubleClick, cn, langSubset } from '~/utils';
|
||||
import { handleDoubleClick, langSubset } from '~/utils';
|
||||
import Clipboard from '~/components/svg/Clipboard';
|
||||
import CheckMark from '~/components/svg/CheckMark';
|
||||
import useLocalize from '~/hooks/useLocalize';
|
||||
|
||||
type CodeBarProps = {
|
||||
lang: string;
|
||||
codeRef: RefObject<HTMLElement>;
|
||||
};
|
||||
|
||||
type CodeBlockProps = Pick<CodeBarProps, 'lang'> & {
|
||||
codeChildren: React.ReactNode;
|
||||
classProp?: string;
|
||||
};
|
||||
|
||||
const CodeBlock: React.FC<CodeBlockProps> = ({ lang, codeChildren, classProp = '' }) => {
|
||||
const codeRef = useRef<HTMLElement>(null);
|
||||
return (
|
||||
<div className="w-full rounded-md bg-gray-900 text-xs text-white/80">
|
||||
<div className={cn(classProp, 'overflow-y-auto p-4')}>
|
||||
<code ref={codeRef} className={`hljs language-${lang} !whitespace-pre`}>
|
||||
{codeChildren}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type TCodeProps = {
|
||||
inline: boolean;
|
||||
className?: string;
|
||||
|
|
@ -49,41 +26,38 @@ export const code: React.ElementType = memo(({ inline, className, children }: TC
|
|||
);
|
||||
}
|
||||
|
||||
return <CodeBlock lang={lang ?? 'text'} codeChildren={children} />;
|
||||
return <code className={`hljs language-${lang} !whitespace-pre`}>{children}</code>;
|
||||
});
|
||||
|
||||
const cursor = ' ';
|
||||
export const CodeMarkdown = memo(
|
||||
({ content = '', showCursor }: { content: string; showCursor?: boolean }) => {
|
||||
const currentContent = content;
|
||||
const rehypePlugins = [
|
||||
[rehypeKatex, { output: 'mathml' }],
|
||||
[
|
||||
rehypeHighlight,
|
||||
{
|
||||
detect: true,
|
||||
ignoreMissing: true,
|
||||
subset: langSubset,
|
||||
},
|
||||
],
|
||||
];
|
||||
export const CodeMarkdown = memo(({ content = '' }: { content: string }) => {
|
||||
const currentContent = content;
|
||||
const rehypePlugins = [
|
||||
[rehypeKatex, { output: 'mathml' }],
|
||||
[
|
||||
rehypeHighlight,
|
||||
{
|
||||
detect: true,
|
||||
ignoreMissing: true,
|
||||
subset: langSubset,
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
return (
|
||||
<ReactMarkdown
|
||||
/* @ts-ignore */
|
||||
rehypePlugins={rehypePlugins}
|
||||
// linkTarget="_new"
|
||||
components={
|
||||
{ code } as {
|
||||
[key: string]: React.ElementType;
|
||||
}
|
||||
return (
|
||||
<ReactMarkdown
|
||||
/* @ts-ignore */
|
||||
rehypePlugins={rehypePlugins}
|
||||
// linkTarget="_new"
|
||||
components={
|
||||
{ code } as {
|
||||
[key: string]: React.ElementType;
|
||||
}
|
||||
>
|
||||
{showCursor === true ? currentContent + cursor : currentContent}
|
||||
</ReactMarkdown>
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
>
|
||||
{currentContent}
|
||||
</ReactMarkdown>
|
||||
);
|
||||
});
|
||||
|
||||
export const CopyCodeButton: React.FC<{ content: string }> = ({ content }) => {
|
||||
const localize = useLocalize();
|
||||
|
|
|
|||
30
client/src/hooks/Artifacts/useAutoScroll.ts
Normal file
30
client/src/hooks/Artifacts/useAutoScroll.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { useState, useRef, useCallback, useEffect } from 'react';
|
||||
import { useChatContext } from '~/Providers';
|
||||
|
||||
export default function useAutoScroll() {
|
||||
const { isSubmitting } = useChatContext();
|
||||
const [showScrollButton, setShowScrollButton] = useState(false);
|
||||
const scrollableRef = useRef<HTMLDivElement | null>(null);
|
||||
const contentEndRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const scrollToBottom = useCallback(() => {
|
||||
if (scrollableRef.current) {
|
||||
scrollableRef.current.scrollTop = scrollableRef.current.scrollHeight;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleScroll = useCallback(() => {
|
||||
if (scrollableRef.current) {
|
||||
const { scrollTop, scrollHeight, clientHeight } = scrollableRef.current;
|
||||
setShowScrollButton(scrollHeight - scrollTop - clientHeight > 100);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isSubmitting) {
|
||||
scrollToBottom();
|
||||
}
|
||||
}, [isSubmitting, scrollToBottom]);
|
||||
|
||||
return { scrollableRef, contentEndRef, handleScroll, scrollToBottom, showScrollButton };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue