123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- import DeleteIcon from "../icons/delete.svg";
- import BotIcon from "../icons/bot.svg";
- import styles from "./home.module.scss";
- import {
- DragDropContext,
- Droppable,
- Draggable,
- OnDragEndResponder,
- } from "@hello-pangea/dnd";
- import { useChatStore } from "../store";
- import Locale from "../locales";
- import { Link, useNavigate } from "react-router-dom";
- import { Path } from "../constant";
- import { MaskAvatar } from "./mask";
- import { Mask } from "../store/mask";
- import { useRef, useEffect } from "react";
- import { showConfirm } from "./ui-lib";
- import { useMobileScreen } from "../utils";
- export function ChatItem(props: {
- onClick?: () => void;
- onDelete?: () => void;
- title: string;
- count: number;
- time: string;
- selected: boolean;
- id: string;
- index: number;
- narrow?: boolean;
- mask: Mask;
- }) {
- const draggableRef = useRef<HTMLDivElement | null>(null);
- useEffect(() => {
- if (props.selected && draggableRef.current) {
- draggableRef.current?.scrollIntoView({
- block: "center",
- });
- }
- }, [props.selected]);
- return (
- <Draggable draggableId={`${props.id}`} index={props.index}>
- {(provided) => (
- <div
- className={`${styles["chat-item"]} ${
- props.selected && styles["chat-item-selected"]
- }`}
- onClick={props.onClick}
- ref={(ele) => {
- draggableRef.current = ele;
- provided.innerRef(ele);
- }}
- {...provided.draggableProps}
- {...provided.dragHandleProps}
- title={`${props.title}\n${Locale.ChatItem.ChatItemCount(
- props.count,
- )}`}
- >
- {props.narrow ? (
- <div className={styles["chat-item-narrow"]}>
- <div className={styles["chat-item-avatar"] + " no-dark"}>
- <MaskAvatar
- avatar={props.mask.avatar}
- model={props.mask.modelConfig.model}
- />
- </div>
- <div className={styles["chat-item-narrow-count"]}>
- {props.count}
- </div>
- </div>
- ) : (
- <>
- <div className={styles["chat-item-title"]}>{props.title}</div>
- <div className={styles["chat-item-info"]}>
- <div className={styles["chat-item-count"]}>
- {Locale.ChatItem.ChatItemCount(props.count)}
- </div>
- <div className={styles["chat-item-date"]}>{props.time}</div>
- </div>
- </>
- )}
- <div
- className={styles["chat-item-delete"]}
- onClickCapture={(e) => {
- props.onDelete?.();
- e.preventDefault();
- e.stopPropagation();
- }}
- >
- <DeleteIcon />
- </div>
- </div>
- )}
- </Draggable>
- );
- }
- export function ChatList(props: { narrow?: boolean }) {
- const [sessions, selectedIndex, selectSession, moveSession] = useChatStore(
- (state) => [
- state.sessions,
- state.currentSessionIndex,
- state.selectSession,
- state.moveSession,
- ],
- );
- const chatStore = useChatStore();
- const navigate = useNavigate();
- const isMobileScreen = useMobileScreen();
- const onDragEnd: OnDragEndResponder = (result) => {
- const { destination, source } = result;
- if (!destination) {
- return;
- }
- if (
- destination.droppableId === source.droppableId &&
- destination.index === source.index
- ) {
- return;
- }
- moveSession(source.index, destination.index);
- };
- return (
- <DragDropContext onDragEnd={onDragEnd}>
- <Droppable droppableId="chat-list">
- {(provided) => (
- <div
- className={styles["chat-list"]}
- ref={provided.innerRef}
- {...provided.droppableProps}
- >
- {sessions.map((item, i) => (
- <ChatItem
- title={item.topic}
- time={new Date(item.lastUpdate).toLocaleString()}
- count={item.messages.length}
- key={item.id}
- id={item.id}
- index={i}
- selected={i === selectedIndex}
- onClick={() => {
- navigate(Path.Chat);
- selectSession(i);
- }}
- onDelete={async () => {
- if (
- (!props.narrow && !isMobileScreen) ||
- (await showConfirm(Locale.Home.DeleteChat))
- ) {
- chatStore.deleteSession(i);
- }
- }}
- narrow={props.narrow}
- mask={item.mask}
- />
- ))}
- {provided.placeholder}
- </div>
- )}
- </Droppable>
- </DragDropContext>
- );
- }
|