From 8363cdd9faee5ad56e90586e51f582061d506404 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Thu, 13 Apr 2023 02:07:24 +0800 Subject: [PATCH] feat: close #680 lazy rendering markdown --- app/components/chat.module.scss | 24 +++++++++ app/components/chat.tsx | 87 ++++++++++++++++++++++++++++++--- app/components/home.module.scss | 9 +++- app/components/home.tsx | 6 +-- app/components/markdown.tsx | 42 ++++++++++++++-- app/icons/auto.svg | 1 + app/icons/bottom.svg | 1 + app/icons/dark.svg | 1 + app/icons/light.svg | 1 + app/styles/globals.scss | 12 +++-- app/utils.ts | 4 ++ 11 files changed, 168 insertions(+), 20 deletions(-) create mode 100644 app/icons/auto.svg create mode 100644 app/icons/bottom.svg create mode 100644 app/icons/dark.svg create mode 100644 app/icons/light.svg diff --git a/app/components/chat.module.scss b/app/components/chat.module.scss index f57e6c10..7cd2889f 100644 --- a/app/components/chat.module.scss +++ b/app/components/chat.module.scss @@ -1,5 +1,29 @@ @import "../styles/animation.scss"; +.chat-input-actions { + display: flex; + flex-wrap: wrap; + + .chat-input-action { + display: inline-flex; + border-radius: 20px; + font-size: 12px; + background-color: var(--white); + color: var(--black); + border: var(--border-in-light); + padding: 4px 10px; + animation: slide-in ease 0.3s; + box-shadow: var(--card-shadow); + transition: all ease 0.3s; + margin-bottom: 10px; + align-items: center; + + &:not(:last-child) { + margin-right: 5px; + } + } +} + .prompt-toast { position: absolute; bottom: -50px; diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 71c8de43..b9ae1392 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -14,6 +14,11 @@ import DeleteIcon from "../icons/delete.svg"; import MaxIcon from "../icons/max.svg"; import MinIcon from "../icons/min.svg"; +import LightIcon from "../icons/light.svg"; +import DarkIcon from "../icons/dark.svg"; +import AutoIcon from "../icons/auto.svg"; +import BottomIcon from "../icons/bottom.svg"; + import { Message, SubmitKey, @@ -22,6 +27,7 @@ import { ROLES, createMessage, useAccessStore, + Theme, } from "../store"; import { @@ -31,6 +37,7 @@ import { isMobileScreen, selectOrCopy, autoGrowTextArea, + getCSSVar, } from "../utils"; import dynamic from "next/dynamic"; @@ -60,7 +67,11 @@ export function Avatar(props: { role: Message["role"] }) { const config = useChatStore((state) => state.config); if (props.role !== "user") { - return ; + return ( +
+ +
+ ); } return ( @@ -316,22 +327,78 @@ function useScrollToBottom() { // for auto-scroll const scrollRef = useRef(null); const [autoScroll, setAutoScroll] = useState(true); + const scrollToBottom = () => { + const dom = scrollRef.current; + if (dom) { + setTimeout(() => (dom.scrollTop = dom.scrollHeight), 1); + } + }; // auto scroll useLayoutEffect(() => { - const dom = scrollRef.current; - if (dom && autoScroll) { - setTimeout(() => (dom.scrollTop = dom.scrollHeight), 1); - } + autoScroll && scrollToBottom(); }); return { scrollRef, autoScroll, setAutoScroll, + scrollToBottom, }; } +export function ChatActions(props: { + showPromptModal: () => void; + scrollToBottom: () => void; + hitBottom: boolean; +}) { + const chatStore = useChatStore(); + + const theme = chatStore.config.theme; + + function nextTheme() { + const themes = [Theme.Auto, Theme.Light, Theme.Dark]; + const themeIndex = themes.indexOf(theme); + const nextIndex = (themeIndex + 1) % themes.length; + const nextTheme = themes[nextIndex]; + chatStore.updateConfig((config) => (config.theme = nextTheme)); + } + + return ( +
+ {!props.hitBottom && ( +
+ +
+ )} + {props.hitBottom && ( +
+ +
+ )} + +
+ {theme === Theme.Auto ? ( + + ) : theme === Theme.Light ? ( + + ) : theme === Theme.Dark ? ( + + ) : null} +
+
+ ); +} + export function Chat(props: { showSideBar?: () => void; sideBarShowing?: boolean; @@ -350,7 +417,7 @@ export function Chat(props: { const [beforeInput, setBeforeInput] = useState(""); const [isLoading, setIsLoading] = useState(false); const { submitKey, shouldSubmit } = useSubmitHandler(); - const { scrollRef, setAutoScroll } = useScrollToBottom(); + const { scrollRef, setAutoScroll, scrollToBottom } = useScrollToBottom(); const [hitBottom, setHitBottom] = useState(false); const onChatBodyScroll = (e: HTMLElement) => { @@ -683,6 +750,8 @@ export function Chat(props: { if (!isMobileScreen()) return; setUserInput(message.content); }} + fontSize={fontSize} + parentRef={scrollRef} /> {!isUser && !message.preview && ( @@ -700,6 +769,12 @@ export function Chat(props: {
+ + setShowPromptModal(true)} + scrollToBottom={scrollToBottom} + hitBottom={hitBottom} + />