Browse Source

feat: close #680 lazy load markdown dom

Yidadaa 1 year ago
parent
commit
d790b0b372
3 changed files with 59 additions and 43 deletions
  1. 12 16
      app/components/chat.tsx
  2. 42 19
      app/components/markdown.tsx
  3. 5 8
      app/global.d.ts

+ 12 - 16
app/components/chat.tsx

@@ -672,22 +672,18 @@ export function Chat(props: {
                         </div>
                       </div>
                     )}
-                  {(message.preview || message.content.length === 0) &&
-                  !isUser ? (
-                    <LoadingIcon />
-                  ) : (
-                    <div
-                      className="markdown-body"
-                      style={{ fontSize: `${fontSize}px` }}
-                      onContextMenu={(e) => onRightClick(e, message)}
-                      onDoubleClickCapture={() => {
-                        if (!isMobileScreen()) return;
-                        setUserInput(message.content);
-                      }}
-                    >
-                      <Markdown content={message.content} />
-                    </div>
-                  )}
+                  <Markdown
+                    content={message.content}
+                    loading={
+                      (message.preview || message.content.length === 0) &&
+                      !isUser
+                    }
+                    onContextMenu={(e) => onRightClick(e, message)}
+                    onDoubleClickCapture={() => {
+                      if (!isMobileScreen()) return;
+                      setUserInput(message.content);
+                    }}
+                  />
                 </div>
                 {!isUser && !message.preview && (
                   <div className={styles["chat-message-actions"]}>

+ 42 - 19
app/components/markdown.tsx

@@ -8,6 +8,8 @@ import RehypeHighlight from "rehype-highlight";
 import { useRef, useState, RefObject, useEffect } from "react";
 import { copyToClipboard } from "../utils";
 
+import LoadingIcon from "../icons/three-dots.svg";
+
 export function PreCode(props: { children: any }) {
   const ref = useRef<HTMLPreElement>(null);
 
@@ -50,26 +52,47 @@ const useLazyLoad = (ref: RefObject<Element>): boolean => {
   return isIntersecting;
 };
 
-export function Markdown(props: { content: string }) {
+export function Markdown(
+  props: {
+    content: string;
+    loading?: boolean;
+    fontSize?: number;
+  } & React.DOMAttributes<HTMLDivElement>,
+) {
+  const mdRef = useRef(null);
+  const shouldRender = useLazyLoad(mdRef);
+  const shouldLoading = props.loading || !shouldRender;
+
   return (
-    <ReactMarkdown
-      remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
-      rehypePlugins={[
-        RehypeKatex,
-        [
-          RehypeHighlight,
-          {
-            detect: false,
-            ignoreMissing: true,
-          },
-        ],
-      ]}
-      components={{
-        pre: PreCode,
-      }}
-      linkTarget={"_blank"}
+    <div
+      className="markdown-body"
+      style={{ fontSize: `${props.fontSize ?? 14}px` }}
+      {...props}
+      ref={mdRef}
     >
-      {props.content}
-    </ReactMarkdown>
+      {shouldLoading ? (
+        <LoadingIcon />
+      ) : (
+        <ReactMarkdown
+          remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
+          rehypePlugins={[
+            RehypeKatex,
+            [
+              RehypeHighlight,
+              {
+                detect: false,
+                ignoreMissing: true,
+              },
+            ],
+          ]}
+          components={{
+            pre: PreCode,
+          }}
+          linkTarget={"_blank"}
+        >
+          {props.content}
+        </ReactMarkdown>
+      )}
+    </div>
   );
 }

+ 5 - 8
app/global.d.ts

@@ -3,12 +3,9 @@ declare module "*.png";
 declare module "*.woff2";
 declare module "*.woff";
 declare module "*.ttf";
-declare module "*.scss";
-
-declare module "*.svg" {
-  import React = require("react");
-
-  export const ReactComponent: React.SFC<React.SVGProps<SVGSVGElement>>;
-  const src: string;
-  export default src;
+declare module "*.scss" {
+  const content: Record<string, string>;
+  export default content;
 }
+
+declare module "*.svg";