This commit is contained in:
GH Action - Upstream Sync
2023-04-06 18:12:35 +00:00
16 changed files with 136 additions and 38 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

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

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";
@@ -421,7 +421,6 @@ export function Chat(props: {
// check if should send message
const onInputKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (shouldSubmit(e)) {
setAutoScroll(true);
onUserSubmit();
e.preventDefault();
}
@@ -508,13 +507,10 @@ export function Chat(props: {
return (
<div className={styles.chat} key={session.id}>
<div className={styles["window-header"]}>
<div
className={styles["window-header-title"]}
onClick={props?.showSideBar}
>
<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(
@@ -532,7 +528,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={props?.showSideBar}
@@ -668,7 +664,7 @@ export function Chat(props: {
onInput={(e) => onInput(e.currentTarget.value)}
value={userInput}
onKeyDown={onInputKeyDown}
onFocus={() => setAutoScroll(isMobileScreen())}
onFocus={() => setAutoScroll(true)}
onBlur={() => {
setAutoScroll(false);
setTimeout(() => setPromptHints([]), 500);

View File

@@ -93,6 +93,7 @@ function _Home() {
state.removeSession,
],
);
const chatStore = useChatStore();
const loading = !useHasHydrated();
const [showSideBar, setShowSideBar] = useState(true);
@@ -143,11 +144,7 @@ function _Home() {
<div className={styles["sidebar-action"] + " " + styles.mobile}>
<IconButton
icon={<CloseIcon />}
onClick={() => {
if (confirm(Locale.Home.DeleteChat)) {
removeSession(currentIndex);
}
}}
onClick={chatStore.deleteSession}
/>
</div>
<div className={styles["sidebar-action"]}>

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;
}
}
}
}
@@ -160,4 +176,4 @@
max-height: 50vh;
}
}
}
}

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> & {