merge upstream latest

This commit is contained in:
dakai
2023-04-07 07:53:04 +08:00
23 changed files with 306 additions and 69 deletions

View File

@@ -10,6 +10,14 @@
transition: all 0.3s ease;
overflow: hidden;
user-select: none;
outline: none;
border: none;
color: var(--black);
&[disabled] {
cursor: not-allowed;
opacity: 0.5;
}
}
.shadow {

View File

@@ -11,9 +11,10 @@ export function IconButton(props: {
noDark?: boolean;
className?: string;
title?: string;
disabled?: boolean;
}) {
return (
<div
<button
className={
styles["icon-button"] +
` ${props.bordered && styles.border} ${props.shadow && styles.shadow} ${
@@ -22,6 +23,7 @@ export function IconButton(props: {
}
onClick={props.onClick}
title={props.title}
disabled={props.disabled}
role="button"
>
<div
@@ -32,6 +34,6 @@ export function IconButton(props: {
{props.text && (
<div className={styles["icon-button-text"]}>{props.text}</div>
)}
</div>
</button>
);
}

View File

@@ -102,6 +102,7 @@ export function ChatList() {
state.removeSession,
state.moveSession,
]);
const chatStore = useChatStore();
const onDragEnd: OnDragEndResponder = (result: any) => {
const { destination, source } = result;
if (!destination) {
@@ -139,10 +140,7 @@ export function ChatList() {
index={i}
selected={i === selectedIndex}
onClick={() => selectSession(i)}
onDelete={() =>
(!isMobileScreen() || confirm(Locale.Home.DeleteChat)) &&
removeSession(i)
}
onDelete={chatStore.deleteSession}
/>
))}

View File

@@ -4,7 +4,7 @@ import { memo, useState, useRef, useEffect, useLayoutEffect } from "react";
import SendWhiteIcon from "../icons/send-white.svg";
import BrainIcon from "../icons/brain.svg";
import ExportIcon from "../icons/export.svg";
import MenuIcon from "../icons/menu.svg";
import ReturnIcon from "../icons/return.svg";
import CopyIcon from "../icons/copy.svg";
import DownloadIcon from "../icons/download.svg";
import LoadingIcon from "../icons/three-dots.svg";
@@ -509,7 +509,7 @@ export function Chat(props: {}) {
<div className={styles["window-header-title"]}>
<div
className={`${styles["window-header-main-title"]} ${styles["chat-body-title"]}`}
onClick={() => {
onClickCapture={() => {
const newTopic = prompt(Locale.Chat.Rename, session.topic);
if (newTopic && newTopic !== session.topic) {
chatStore.updateCurrentSession(
@@ -527,7 +527,7 @@ export function Chat(props: {}) {
<div className={styles["window-actions"]}>
<div className={styles["window-action-button"] + " " + styles.mobile}>
<IconButton
icon={<MenuIcon />}
icon={<ReturnIcon />}
bordered
title={Locale.Chat.Actions.ChatList}
onClick={() => {

View File

@@ -95,6 +95,7 @@ function _Home() {
state.removeSession,
],
);
const chatStore = useChatStore();
const loading = !useHasHydrated();
const [sidebarCollapse, setSideBarCollapse] = useChatStore((state) => [
state.sidebarCollapse,
@@ -211,11 +212,7 @@ function _Home() {
>
<IconButton
icon={<CloseIcon />}
onClick={() => {
if (confirm(Locale.Home.DeleteChat)) {
removeSession(currentIndex);
}
}}
onClick={chatStore.deleteSession}
/>
</div>

View File

@@ -0,0 +1,7 @@
.input-range {
border: var(--border-in-light);
border-radius: 10px;
padding: 5px 15px 5px 10px;
font-size: 12px;
display: flex;
}

View File

@@ -0,0 +1,37 @@
import * as React from "react";
import styles from "./input-range.module.scss";
interface InputRangeProps {
onChange: React.ChangeEventHandler<HTMLInputElement>;
title?: string;
value: number | string;
className?: string;
min: string;
max: string;
step: string;
}
export function InputRange({
onChange,
title,
value,
className,
min,
max,
step,
}: InputRangeProps) {
return (
<div className={styles["input-range"] + ` ${className ?? ""}`}>
{title || value}
<input
type="range"
title={title}
value={value}
min={min}
max={max}
step={step}
onChange={onChange}
></input>
</div>
);
}

View File

@@ -32,6 +32,7 @@ import { UPDATE_URL } from "../constant";
import { SearchService, usePromptStore } from "../store/prompt";
import { requestUsage } from "../requests";
import { ErrorBoundary } from "./error";
import { InputRange } from "./input-range";
function SettingItem(props: {
title: string;
@@ -274,8 +275,7 @@ export function Settings(props: { closeSettings: () => void }) {
title={Locale.Settings.FontSize.Title}
subTitle={Locale.Settings.FontSize.SubTitle}
>
<input
type="range"
<InputRange
title={`${config.fontSize ?? 14}px`}
value={config.fontSize}
min="12"
@@ -287,7 +287,7 @@ export function Settings(props: { closeSettings: () => void }) {
(config.fontSize = Number.parseInt(e.currentTarget.value)),
)
}
></input>
></InputRange>
</SettingItem>
<SettingItem title={Locale.Settings.TightBorder}>
@@ -407,8 +407,7 @@ export function Settings(props: { closeSettings: () => void }) {
title={Locale.Settings.HistoryCount.Title}
subTitle={Locale.Settings.HistoryCount.SubTitle}
>
<input
type="range"
<InputRange
title={config.historyMessageCount.toString()}
value={config.historyMessageCount}
min="0"
@@ -420,7 +419,7 @@ export function Settings(props: { closeSettings: () => void }) {
(config.historyMessageCount = e.target.valueAsNumber),
)
}
></input>
></InputRange>
</SettingItem>
<SettingItem
@@ -467,8 +466,7 @@ export function Settings(props: { closeSettings: () => void }) {
title={Locale.Settings.Temperature.Title}
subTitle={Locale.Settings.Temperature.SubTitle}
>
<input
type="range"
<InputRange
value={config.modelConfig.temperature?.toFixed(1)}
min="0"
max="2"
@@ -482,7 +480,7 @@ export function Settings(props: { closeSettings: () => void }) {
)),
);
}}
></input>
></InputRange>
</SettingItem>
<SettingItem
title={Locale.Settings.MaxTokens.Title}
@@ -508,8 +506,7 @@ export function Settings(props: { closeSettings: () => void }) {
title={Locale.Settings.PresencePenlty.Title}
subTitle={Locale.Settings.PresencePenlty.SubTitle}
>
<input
type="range"
<InputRange
value={config.modelConfig.presence_penalty?.toFixed(1)}
min="-2"
max="2"
@@ -523,7 +520,7 @@ export function Settings(props: { closeSettings: () => void }) {
)),
);
}}
></input>
></InputRange>
</SettingItem>
</List>
</div>

View File

@@ -135,9 +135,25 @@
box-shadow: var(--card-shadow);
border: var(--border-in-light);
color: var(--black);
padding: 10px 30px;
padding: 10px 20px;
border-radius: 50px;
margin-bottom: 20px;
display: flex;
align-items: center;
.toast-action {
padding-left: 20px;
color: var(--primary);
opacity: 0.8;
border: 0;
background: none;
cursor: pointer;
font-family: inherit;
&:hover {
opacity: 1;
}
}
}
}
@@ -149,6 +165,7 @@
background-color: var(--white);
color: var(--black);
resize: none;
min-width: 50px;
}
@media only screen and (max-width: 600px) {

View File

@@ -110,17 +110,37 @@ export function showModal(props: ModalProps) {
root.render(<Modal {...props} onClose={closeModal}></Modal>);
}
export type ToastProps = { content: string };
export type ToastProps = {
content: string;
action?: {
text: string;
onClick: () => void;
};
};
export function Toast(props: ToastProps) {
return (
<div className={styles["toast-container"]}>
<div className={styles["toast-content"]}>{props.content}</div>
<div className={styles["toast-content"]}>
<span>{props.content}</span>
{props.action && (
<button
onClick={props.action.onClick}
className={styles["toast-action"]}
>
{props.action.text}
</button>
)}
</div>
</div>
);
}
export function showToast(content: string, delay = 3000) {
export function showToast(
content: string,
action?: ToastProps["action"],
delay = 3000,
) {
const div = document.createElement("div");
div.className = styles.show;
document.body.appendChild(div);
@@ -139,7 +159,7 @@ export function showToast(content: string, delay = 3000) {
close();
}, delay);
root.render(<Toast content={content} />);
root.render(<Toast content={content} action={action} />);
}
export type InputProps = React.HTMLProps<HTMLTextAreaElement> & {