chat-list.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import DeleteIcon from "../icons/delete.svg";
  2. import BotIcon from "../icons/bot.svg";
  3. import styles from "./home.module.scss";
  4. import {
  5. DragDropContext,
  6. Droppable,
  7. Draggable,
  8. OnDragEndResponder,
  9. } from "@hello-pangea/dnd";
  10. import { useChatStore } from "../store";
  11. import Locale from "../locales";
  12. import { Link, useNavigate } from "react-router-dom";
  13. import { Path } from "../constant";
  14. export function ChatItem(props: {
  15. onClick?: () => void;
  16. onDelete?: () => void;
  17. title: string;
  18. count: number;
  19. time: string;
  20. selected: boolean;
  21. id: number;
  22. index: number;
  23. narrow?: boolean;
  24. }) {
  25. return (
  26. <Draggable draggableId={`${props.id}`} index={props.index}>
  27. {(provided) => (
  28. <div
  29. className={`${styles["chat-item"]} ${
  30. props.selected && styles["chat-item-selected"]
  31. }`}
  32. onClick={props.onClick}
  33. ref={provided.innerRef}
  34. {...provided.draggableProps}
  35. {...provided.dragHandleProps}
  36. title={`${props.title}\n${Locale.ChatItem.ChatItemCount(
  37. props.count,
  38. )}`}
  39. >
  40. {props.narrow ? (
  41. <div className={styles["chat-item-narrow"]}>
  42. <div className={styles["chat-item-avatar"] + " no-dark"}>
  43. <BotIcon></BotIcon>
  44. </div>
  45. <div className={styles["chat-item-narrow-count"]}>
  46. {props.count}
  47. </div>
  48. </div>
  49. ) : (
  50. <>
  51. <div className={styles["chat-item-title"]}>{props.title}</div>
  52. <div className={styles["chat-item-info"]}>
  53. <div className={styles["chat-item-count"]}>
  54. {Locale.ChatItem.ChatItemCount(props.count)}
  55. </div>
  56. <div className={styles["chat-item-date"]}>{props.time}</div>
  57. </div>
  58. </>
  59. )}
  60. <div className={styles["chat-item-delete"]} onClick={props.onDelete}>
  61. <DeleteIcon />
  62. </div>
  63. </div>
  64. )}
  65. </Draggable>
  66. );
  67. }
  68. export function ChatList(props: { narrow?: boolean }) {
  69. const [sessions, selectedIndex, selectSession, removeSession, moveSession] =
  70. useChatStore((state) => [
  71. state.sessions,
  72. state.currentSessionIndex,
  73. state.selectSession,
  74. state.removeSession,
  75. state.moveSession,
  76. ]);
  77. const chatStore = useChatStore();
  78. const navigate = useNavigate();
  79. const onDragEnd: OnDragEndResponder = (result) => {
  80. const { destination, source } = result;
  81. if (!destination) {
  82. return;
  83. }
  84. if (
  85. destination.droppableId === source.droppableId &&
  86. destination.index === source.index
  87. ) {
  88. return;
  89. }
  90. moveSession(source.index, destination.index);
  91. };
  92. return (
  93. <DragDropContext onDragEnd={onDragEnd}>
  94. <Droppable droppableId="chat-list">
  95. {(provided) => (
  96. <div
  97. className={styles["chat-list"]}
  98. ref={provided.innerRef}
  99. {...provided.droppableProps}
  100. >
  101. {sessions.map((item, i) => (
  102. <ChatItem
  103. title={item.topic}
  104. time={item.lastUpdate}
  105. count={item.messages.length}
  106. key={item.id}
  107. id={item.id}
  108. index={i}
  109. selected={i === selectedIndex}
  110. onClick={() => {
  111. navigate(Path.Chat);
  112. selectSession(i);
  113. }}
  114. onDelete={() => {
  115. if (!props.narrow || confirm(Locale.Home.DeleteChat)) {
  116. chatStore.deleteSession(i);
  117. }
  118. }}
  119. narrow={props.narrow}
  120. />
  121. ))}
  122. {provided.placeholder}
  123. </div>
  124. )}
  125. </Droppable>
  126. </DragDropContext>
  127. );
  128. }