mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +01:00
Add 'scrollable' prop to Markdown component for better control over scrolling behavior (#964)
The scrollable prop controls if ScrollbarOverlay is added to the Markdown component.
This commit is contained in:
parent
f1fe401dbe
commit
28ca193c19
@ -7,6 +7,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -17,6 +18,10 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
|
|
||||||
|
&.non-scrollable {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
margin-top: 0 !important;
|
margin-top: 0 !important;
|
||||||
|
@ -178,9 +178,19 @@ type MarkdownProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
onClickExecute?: (cmd: string) => void;
|
onClickExecute?: (cmd: string) => void;
|
||||||
resolveOpts?: MarkdownResolveOpts;
|
resolveOpts?: MarkdownResolveOpts;
|
||||||
|
scrollable?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Markdown = ({ text, textAtom, showTocAtom, style, className, resolveOpts, onClickExecute }: MarkdownProps) => {
|
const Markdown = ({
|
||||||
|
text,
|
||||||
|
textAtom,
|
||||||
|
showTocAtom,
|
||||||
|
style,
|
||||||
|
className,
|
||||||
|
resolveOpts,
|
||||||
|
scrollable = true,
|
||||||
|
onClickExecute,
|
||||||
|
}: MarkdownProps) => {
|
||||||
const textAtomValue = useAtomValueSafe(textAtom);
|
const textAtomValue = useAtomValueSafe(textAtom);
|
||||||
const tocRef = useRef<TocItem[]>([]);
|
const tocRef = useRef<TocItem[]>([]);
|
||||||
const showToc = useAtomValueSafe(showTocAtom) ?? false;
|
const showToc = useAtomValueSafe(showTocAtom) ?? false;
|
||||||
@ -240,8 +250,8 @@ const Markdown = ({ text, textAtom, showTocAtom, style, className, resolveOpts,
|
|||||||
|
|
||||||
text = textAtomValue ?? text;
|
text = textAtomValue ?? text;
|
||||||
|
|
||||||
return (
|
const ScrollableMarkdown = () => {
|
||||||
<div className={clsx("markdown", className)} style={style}>
|
return (
|
||||||
<OverlayScrollbarsComponent
|
<OverlayScrollbarsComponent
|
||||||
ref={contentsOsRef}
|
ref={contentsOsRef}
|
||||||
className="content"
|
className="content"
|
||||||
@ -274,6 +284,45 @@ const Markdown = ({ text, textAtom, showTocAtom, style, className, resolveOpts,
|
|||||||
{text}
|
{text}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
</OverlayScrollbarsComponent>
|
</OverlayScrollbarsComponent>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const NonScrollableMarkdown = () => {
|
||||||
|
return (
|
||||||
|
<div className="content non-scrollable">
|
||||||
|
<ReactMarkdown
|
||||||
|
remarkPlugins={[remarkGfm, [RemarkFlexibleToc, { tocRef: tocRef.current }]]}
|
||||||
|
rehypePlugins={[
|
||||||
|
rehypeRaw,
|
||||||
|
rehypeHighlight,
|
||||||
|
() =>
|
||||||
|
rehypeSanitize({
|
||||||
|
...defaultSchema,
|
||||||
|
attributes: {
|
||||||
|
...defaultSchema.attributes,
|
||||||
|
span: [
|
||||||
|
...(defaultSchema.attributes?.span || []),
|
||||||
|
// Allow all class names starting with `hljs-`.
|
||||||
|
["className", /^hljs-./],
|
||||||
|
// Alternatively, to allow only certain class names:
|
||||||
|
// ['className', 'hljs-number', 'hljs-title', 'hljs-variable']
|
||||||
|
],
|
||||||
|
},
|
||||||
|
tagNames: [...(defaultSchema.tagNames || []), "span"],
|
||||||
|
}),
|
||||||
|
() => rehypeSlug({ prefix: idPrefix }),
|
||||||
|
]}
|
||||||
|
components={markdownComponents}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</ReactMarkdown>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx("markdown", className)} style={style}>
|
||||||
|
{scrollable ? <ScrollableMarkdown /> : <NonScrollableMarkdown />}
|
||||||
{toc && (
|
{toc && (
|
||||||
<OverlayScrollbarsComponent className="toc" options={{ scrollbars: { autoHide: "leave" } }}>
|
<OverlayScrollbarsComponent className="toc" options={{ scrollbars: { autoHide: "leave" } }}>
|
||||||
<div className="toc-inner">
|
<div className="toc-inner">
|
||||||
|
@ -14,7 +14,6 @@ import { atom, Atom, PrimitiveAtom, useAtomValue, useSetAtom, WritableAtom } fro
|
|||||||
import type { OverlayScrollbars } from "overlayscrollbars";
|
import type { OverlayScrollbars } from "overlayscrollbars";
|
||||||
import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react";
|
import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react";
|
||||||
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
||||||
import tinycolor from "tinycolor2";
|
|
||||||
import "./waveai.less";
|
import "./waveai.less";
|
||||||
|
|
||||||
interface ChatMessageType {
|
interface ChatMessageType {
|
||||||
@ -263,11 +262,8 @@ function makeWaveAiViewModel(blockId): WaveAiModel {
|
|||||||
|
|
||||||
const ChatItem = ({ chatItem }: ChatItemProps) => {
|
const ChatItem = ({ chatItem }: ChatItemProps) => {
|
||||||
const { isAssistant, text, isError } = chatItem;
|
const { isAssistant, text, isError } = chatItem;
|
||||||
const senderClassName = isAssistant ? "chat-msg-assistant" : "chat-msg-user";
|
|
||||||
const msgClassName = `chat-msg ${senderClassName}`;
|
|
||||||
const cssVar = "--panel-bg-color";
|
const cssVar = "--panel-bg-color";
|
||||||
const panelBgColor = getComputedStyle(document.documentElement).getPropertyValue(cssVar).trim();
|
const panelBgColor = getComputedStyle(document.documentElement).getPropertyValue(cssVar).trim();
|
||||||
const color = tinycolor(panelBgColor);
|
|
||||||
|
|
||||||
const renderError = (err: string): React.JSX.Element => <div className="chat-msg-error">{err}</div>;
|
const renderError = (err: string): React.JSX.Element => <div className="chat-msg-error">{err}</div>;
|
||||||
|
|
||||||
@ -284,7 +280,7 @@ const ChatItem = ({ chatItem }: ChatItemProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="chat-msg chat-msg-assistant">
|
<div className="chat-msg chat-msg-assistant">
|
||||||
<Markdown text={text} />
|
<Markdown text={text} scrollable={false} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@ -299,7 +295,7 @@ const ChatItem = ({ chatItem }: ChatItemProps) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="chat-msg chat-msg-user">
|
<div className="chat-msg chat-msg-user">
|
||||||
<Markdown className="msg-text" text={text} />
|
<Markdown className="msg-text" text={text} scrollable={false} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user