mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-11-25 18:26:48 +08:00
merge upstream latest
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import { useDebounce, useDebouncedCallback } from "use-debounce";
|
||||
import { memo, useState, useRef, useEffect, useLayoutEffect } from "react";
|
||||
|
||||
import SendWhiteIcon from "../icons/send-white.svg";
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
getEmojiUrl,
|
||||
isMobileScreen,
|
||||
selectOrCopy,
|
||||
autoGrowTextArea,
|
||||
} from "../utils";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
@@ -39,7 +40,7 @@ import { IconButton } from "./button";
|
||||
import styles from "./home.module.scss";
|
||||
import chatStyle from "./chat.module.scss";
|
||||
|
||||
import { Input, Modal, showModal, showToast } from "./ui-lib";
|
||||
import { Input, Modal, showModal } from "./ui-lib";
|
||||
|
||||
const Markdown = dynamic(
|
||||
async () => memo((await import("./markdown")).Markdown),
|
||||
@@ -382,6 +383,27 @@ export function Chat(props: {}) {
|
||||
dom.scrollTop = dom.scrollHeight - dom.offsetHeight + paddingBottomNum;
|
||||
};
|
||||
|
||||
// auto grow input
|
||||
const [inputRows, setInputRows] = useState(2);
|
||||
const measure = useDebouncedCallback(
|
||||
() => {
|
||||
const rows = inputRef.current ? autoGrowTextArea(inputRef.current) : 1;
|
||||
const inputRows = Math.min(
|
||||
5,
|
||||
Math.max(2 + Number(!isMobileScreen()), rows),
|
||||
);
|
||||
setInputRows(inputRows);
|
||||
},
|
||||
100,
|
||||
{
|
||||
leading: true,
|
||||
trailing: true,
|
||||
},
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(measure, [userInput]);
|
||||
|
||||
// only search prompts when user input is short
|
||||
const SEARCH_TEXT_LIMIT = 30;
|
||||
const onInput = (text: string) => {
|
||||
@@ -396,9 +418,6 @@ export function Chat(props: {}) {
|
||||
// check if need to trigger auto completion
|
||||
if (text.startsWith("/")) {
|
||||
let searchText = text.slice(1);
|
||||
if (searchText.length === 0) {
|
||||
searchText = " ";
|
||||
}
|
||||
onSearch(searchText);
|
||||
}
|
||||
}
|
||||
@@ -669,7 +688,6 @@ export function Chat(props: {}) {
|
||||
ref={inputRef}
|
||||
className={styles["chat-input"]}
|
||||
placeholder={Locale.Chat.Input(submitKey)}
|
||||
rows={2}
|
||||
onInput={(e) => onInput(e.currentTarget.value)}
|
||||
value={userInput}
|
||||
onKeyDown={onInputKeyDown}
|
||||
@@ -679,6 +697,7 @@ export function Chat(props: {}) {
|
||||
setTimeout(() => setPromptHints([]), 500);
|
||||
}}
|
||||
autoFocus={sidebarCollapse}
|
||||
rows={inputRows}
|
||||
/>
|
||||
<IconButton
|
||||
icon={<SendWhiteIcon />}
|
||||
|
||||
@@ -522,17 +522,11 @@
|
||||
background-color: var(--white);
|
||||
color: var(--black);
|
||||
font-family: inherit;
|
||||
padding: 10px 14px 50px;
|
||||
padding: 10px 90px 10px 14px;
|
||||
resize: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.chat-input {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-input:focus {
|
||||
border: 1px solid var(--primary);
|
||||
}
|
||||
@@ -543,7 +537,17 @@
|
||||
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
bottom: 30px;
|
||||
bottom: 32px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.chat-input {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.chat-input-send {
|
||||
bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.export-content {
|
||||
|
||||
@@ -67,7 +67,7 @@ export function Markdown(props: { content: string }) {
|
||||
components={{
|
||||
pre: PreCode,
|
||||
}}
|
||||
linkTarget={'_blank'}
|
||||
linkTarget={"_blank"}
|
||||
>
|
||||
{props.content}
|
||||
</ReactMarkdown>
|
||||
|
||||
@@ -156,7 +156,14 @@ export function Settings(props: { closeSettings: () => void }) {
|
||||
<div className={styles["window-action-button"]}>
|
||||
<IconButton
|
||||
icon={<ClearIcon />}
|
||||
onClick={clearSessions}
|
||||
onClick={() => {
|
||||
const confirmed = window.confirm(
|
||||
`${Locale.Settings.Actions.ConfirmClearAll.Confirm}`,
|
||||
);
|
||||
if (confirmed) {
|
||||
clearSessions();
|
||||
}
|
||||
}}
|
||||
bordered
|
||||
title={Locale.Settings.Actions.ClearAll}
|
||||
/>
|
||||
@@ -164,7 +171,14 @@ export function Settings(props: { closeSettings: () => void }) {
|
||||
<div className={styles["window-action-button"]}>
|
||||
<IconButton
|
||||
icon={<ResetIcon />}
|
||||
onClick={resetConfig}
|
||||
onClick={() => {
|
||||
const confirmed = window.confirm(
|
||||
`${Locale.Settings.Actions.ConfirmResetAll.Confirm}`,
|
||||
);
|
||||
if (confirmed) {
|
||||
resetConfig();
|
||||
}
|
||||
}}
|
||||
bordered
|
||||
title={Locale.Settings.Actions.ResetAll}
|
||||
/>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
.popover {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.popover-content {
|
||||
|
||||
Reference in New Issue
Block a user