Merge branch 'Yidadaa:main' into main

This commit is contained in:
Huang Jianhui
2023-04-22 21:17:08 +08:00
committed by GitHub
21 changed files with 224 additions and 214 deletions

View File

@@ -32,6 +32,7 @@ import {
useAccessStore,
Theme,
ModelType,
useAppConfig,
} from "../store";
import {
@@ -69,7 +70,7 @@ const Emoji = dynamic(async () => (await import("emoji-picker-react")).Emoji, {
});
export function Avatar(props: { role: Message["role"]; model?: ModelType }) {
const config = useChatStore((state) => state.config);
const config = useAppConfig();
if (props.role !== "user") {
return (
@@ -285,7 +286,7 @@ function PromptToast(props: {
}
function useSubmitHandler() {
const config = useChatStore((state) => state.config);
const config = useAppConfig();
const submitKey = config.submitKey;
const shouldSubmit = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
@@ -361,16 +362,16 @@ export function ChatActions(props: {
scrollToBottom: () => void;
hitBottom: boolean;
}) {
const chatStore = useChatStore();
const config = useAppConfig();
// switch themes
const theme = chatStore.config.theme;
const theme = 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));
config.update((config) => (config.theme = nextTheme));
}
// stop all responses
@@ -428,7 +429,8 @@ export function Chat() {
state.currentSession(),
state.currentSessionIndex,
]);
const fontSize = useChatStore((state) => state.config.fontSize);
const config = useAppConfig();
const fontSize = config.fontSize;
const inputRef = useRef<HTMLTextAreaElement>(null);
const [userInput, setUserInput] = useState("");
@@ -492,7 +494,7 @@ export function Chat() {
// clear search results
if (n === 0) {
setPromptHints([]);
} else if (!chatStore.config.disablePromptHint && n < SEARCH_TEXT_LIMIT) {
} else if (!config.disablePromptHint && n < SEARCH_TEXT_LIMIT) {
// check if need to trigger auto completion
if (text.startsWith("/")) {
let searchText = text.slice(1);
@@ -543,7 +545,7 @@ export function Chat() {
}
};
const findLastUesrIndex = (messageId: number) => {
const findLastUserIndex = (messageId: number) => {
// find last user input message and resend
let lastUserMessageIndex: number | null = null;
for (let i = 0; i < session.messages.length; i += 1) {
@@ -566,14 +568,14 @@ export function Chat() {
};
const onDelete = (botMessageId: number) => {
const userIndex = findLastUesrIndex(botMessageId);
const userIndex = findLastUserIndex(botMessageId);
if (userIndex === null) return;
deleteMessage(userIndex);
};
const onResend = (botMessageId: number) => {
// find last user input message and resend
const userIndex = findLastUesrIndex(botMessageId);
const userIndex = findLastUserIndex(botMessageId);
if (userIndex === null) return;
setIsLoading(true);
@@ -583,8 +585,6 @@ export function Chat() {
inputRef.current?.focus();
};
const config = useChatStore((state) => state.config);
const context: RenderMessage[] = session.context.slice();
const accessStore = useAccessStore();
@@ -692,10 +692,10 @@ export function Chat() {
{!isMobileScreen && (
<div className={styles["window-action-button"]}>
<IconButton
icon={chatStore.config.tightBorder ? <MinIcon /> : <MaxIcon />}
icon={config.tightBorder ? <MinIcon /> : <MaxIcon />}
bordered
onClick={() => {
chatStore.updateConfig(
config.update(
(config) => (config.tightBorder = !config.tightBorder),
);
}}

View File

@@ -313,6 +313,10 @@
.chat-message {
display: flex;
flex-direction: row;
&:last-child {
animation: slide-in ease 0.3s;
}
}
.chat-message-user {
@@ -325,7 +329,6 @@
display: flex;
flex-direction: column;
align-items: flex-start;
animation: slide-in ease 0.3s;
&:hover {
.chat-message-top-actions {

View File

@@ -2,14 +2,13 @@
require("../polyfill");
import { useState, useEffect } from "react";
import { useState, useEffect, StyleHTMLAttributes } from "react";
import styles from "./home.module.scss";
import BotIcon from "../icons/bot.svg";
import LoadingIcon from "../icons/three-dots.svg";
import { useChatStore } from "../store";
import { getCSSVar, useMobileScreen } from "../utils";
import { Chat } from "./chat";
@@ -23,6 +22,8 @@ import {
Route,
useLocation,
} from "react-router-dom";
import { SideBar } from "./sidebar";
import { useAppConfig } from "../store/config";
export function Loading(props: { noLogo?: boolean }) {
return (
@@ -37,12 +38,8 @@ const Settings = dynamic(async () => (await import("./settings")).Settings, {
loading: () => <Loading noLogo />,
});
const SideBar = dynamic(async () => (await import("./sidebar")).SideBar, {
loading: () => <Loading noLogo />,
});
export function useSwitchTheme() {
const config = useChatStore((state) => state.config);
const config = useAppConfig();
useEffect(() => {
document.body.classList.remove("light");
@@ -83,7 +80,7 @@ const useHasHydrated = () => {
};
function WideScreen() {
const config = useChatStore((state) => state.config);
const config = useAppConfig();
return (
<div

View File

@@ -23,6 +23,7 @@ import {
useUpdateStore,
useAccessStore,
ModalConfigValidator,
useAppConfig,
} from "../store";
import { Avatar } from "./chat";
@@ -180,14 +181,13 @@ function PasswordInput(props: HTMLProps<HTMLInputElement>) {
export function Settings() {
const navigate = useNavigate();
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
const [config, updateConfig, resetConfig, clearAllData, clearSessions] =
useChatStore((state) => [
state.config,
state.updateConfig,
state.resetConfig,
state.clearAllData,
state.clearSessions,
]);
const config = useAppConfig();
const updateConfig = config.update;
const resetConfig = config.reset;
const [clearAllData, clearSessions] = useChatStore((state) => [
state.clearAllData,
state.clearSessions,
]);
const updateStore = useUpdateStore();
const [checkingUpdate, setCheckingUpdate] = useState(false);
@@ -645,7 +645,7 @@ export function Settings() {
value={config.modelConfig.presence_penalty?.toFixed(1)}
min="-2"
max="2"
step="0.5"
step="0.1"
onChange={(e) => {
updateConfig(
(config) =>

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useRef } from "react";
import { useEffect, useRef } from "react";
import styles from "./home.module.scss";
@@ -10,7 +10,7 @@ import AddIcon from "../icons/add.svg";
import CloseIcon from "../icons/close.svg";
import Locale from "../locales";
import { useChatStore } from "../store";
import { useAppConfig, useChatStore } from "../store";
import {
MAX_SIDEBAR_WIDTH,
@@ -20,16 +20,20 @@ import {
REPO_URL,
} from "../constant";
import { HashRouter as Router, Link, useNavigate } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom";
import { useMobileScreen } from "../utils";
import { ChatList } from "./chat-list";
import dynamic from "next/dynamic";
const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
loading: () => null,
});
function useDragSideBar() {
const limit = (x: number) => Math.min(MAX_SIDEBAR_WIDTH, x);
const chatStore = useChatStore();
const config = useAppConfig();
const startX = useRef(0);
const startDragWidth = useRef(chatStore.config.sidebarWidth ?? 300);
const startDragWidth = useRef(config.sidebarWidth ?? 300);
const lastUpdateTime = useRef(Date.now());
const handleMouseMove = useRef((e: MouseEvent) => {
@@ -39,11 +43,11 @@ function useDragSideBar() {
lastUpdateTime.current = Date.now();
const d = e.clientX - startX.current;
const nextWidth = limit(startDragWidth.current + d);
chatStore.updateConfig((config) => (config.sidebarWidth = nextWidth));
config.update((config) => (config.sidebarWidth = nextWidth));
});
const handleMouseUp = useRef(() => {
startDragWidth.current = chatStore.config.sidebarWidth ?? 300;
startDragWidth.current = config.sidebarWidth ?? 300;
window.removeEventListener("mousemove", handleMouseMove.current);
window.removeEventListener("mouseup", handleMouseUp.current);
});
@@ -56,15 +60,15 @@ function useDragSideBar() {
};
const isMobileScreen = useMobileScreen();
const shouldNarrow =
!isMobileScreen && chatStore.config.sidebarWidth < MIN_SIDEBAR_WIDTH;
!isMobileScreen && config.sidebarWidth < MIN_SIDEBAR_WIDTH;
useEffect(() => {
const barWidth = shouldNarrow
? NARROW_SIDEBAR_WIDTH
: limit(chatStore.config.sidebarWidth ?? 300);
: limit(config.sidebarWidth ?? 300);
const sideBarWidth = isMobileScreen ? "100vw" : `${barWidth}px`;
document.documentElement.style.setProperty("--sidebar-width", sideBarWidth);
}, [chatStore.config.sidebarWidth, isMobileScreen, shouldNarrow]);
}, [config.sidebarWidth, isMobileScreen, shouldNarrow]);
return {
onDragMouseDown,

View File

@@ -2,7 +2,7 @@ import styles from "./ui-lib.module.scss";
import LoadingIcon from "../icons/three-dots.svg";
import CloseIcon from "../icons/close.svg";
import { createRoot } from "react-dom/client";
import React from "react";
import React, { useEffect } from "react";
export function Popover(props: {
children: JSX.Element;
@@ -64,6 +64,21 @@ interface ModalProps {
onClose?: () => void;
}
export function Modal(props: ModalProps) {
useEffect(() => {
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") {
props.onClose?.();
}
};
window.addEventListener("keydown", onKeyDown);
return () => {
window.removeEventListener("keydown", onKeyDown);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div className={styles["modal-container"]}>
<div className={styles["modal-header"]}>