mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-08 01:06:58 +08:00
feat: select model done
This commit is contained in:
@@ -7,6 +7,7 @@ import LogIcon from "@/app/icons/logIcon.svg";
|
||||
import GobackIcon from "@/app/icons/goback.svg";
|
||||
import ShareIcon from "@/app/icons/shareIcon.svg";
|
||||
import BottomArrow from "@/app/icons/bottomArrow.svg";
|
||||
import ModelSelect from "./ModelSelect";
|
||||
|
||||
export interface ChatHeaderProps {
|
||||
isMobileScreen: boolean;
|
||||
@@ -70,13 +71,7 @@ export default function ChatHeader(props: ChatHeaderProps) {
|
||||
`}
|
||||
>
|
||||
{isMobileScreen ? (
|
||||
<div
|
||||
className="flex items-center gap-1 cursor-pointer"
|
||||
onClick={() => {}}
|
||||
>
|
||||
{currentModel}
|
||||
<BottomArrow />
|
||||
</div>
|
||||
<ModelSelect />
|
||||
) : (
|
||||
Locale.Chat.SubTitle(session.messages.length)
|
||||
)}
|
||||
|
@@ -3,14 +3,16 @@ import React, { useMemo, useRef } from "react";
|
||||
import useRelativePosition, {
|
||||
Orientation,
|
||||
} from "@/app/hooks/useRelativePosition";
|
||||
|
||||
import Selected from "@/app/icons/selectedIcon.svg";
|
||||
import Locale from "@/app/locales";
|
||||
import { useChatStore } from "@/app/store/chat";
|
||||
import { useAllModels } from "@/app/utils/hooks";
|
||||
import { ModelType, useAppConfig } from "@/app/store/config";
|
||||
import { showToast } from "@/app/components/ui-lib";
|
||||
import BottomArrow from "@/app/icons/downArrowLgIcon.svg";
|
||||
import BottomArrowMobile from "@/app/icons/bottomArrow.svg";
|
||||
import Modal, { TriggerProps } from "@/app/components/Modal";
|
||||
|
||||
import Selected from "@/app/icons/selectedIcon.svg";
|
||||
|
||||
const ModelSelect = () => {
|
||||
const config = useAppConfig();
|
||||
@@ -60,15 +62,14 @@ const ModelSelect = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const content = (
|
||||
<div
|
||||
className={` flex flex-col gap-1 overflow-y-auto overflow-x-hidden relative h-[100%]`}
|
||||
>
|
||||
const content: TriggerProps["content"] = ({ close }) => (
|
||||
<div className={`flex flex-col gap-1 overflow-x-hidden relative`}>
|
||||
{models?.map((o) => (
|
||||
<div
|
||||
key={o.displayName}
|
||||
className={`flex items-center px-3 py-2 gap-3 rounded-action-btn hover:bg-select-option-hovered cursor-pointer`}
|
||||
onClick={() => {
|
||||
close();
|
||||
chatStore.updateCurrentSession((session) => {
|
||||
session.mask.modelConfig.model = o.name as ModelType;
|
||||
session.mask.syncGlobalConfig = false;
|
||||
@@ -90,39 +91,41 @@ const ModelSelect = () => {
|
||||
|
||||
if (isMobileScreen) {
|
||||
return (
|
||||
<Popover
|
||||
content={content}
|
||||
trigger="click"
|
||||
noArrow
|
||||
placement={
|
||||
position?.poi.relativePosition[1] !== Orientation.bottom ? "lb" : "lt"
|
||||
}
|
||||
popoverClassName="border border-select-popover rounded-lg shadow-select-popover-shadow w-actions-popover bg-select-popover-panel max-h-chat-actions-select-model-popover"
|
||||
onShow={(e) => {
|
||||
<Modal.Trigger
|
||||
content={(e) => (
|
||||
<div className="h-[100%] overflow-y-auto" ref={contentRef}>
|
||||
{content(e)}
|
||||
</div>
|
||||
)}
|
||||
type="bottom-drawer"
|
||||
onOpen={(e) => {
|
||||
if (e) {
|
||||
autoScrollToSelectedModal();
|
||||
getRelativePosition(rootRef.current!, "");
|
||||
}
|
||||
}}
|
||||
getPopoverPanelRef={(ref) => (contentRef.current = ref.current)}
|
||||
title={Locale.Chat.SelectModel}
|
||||
headerBordered
|
||||
noFooter
|
||||
modelClassName="h-model-bottom-drawer"
|
||||
>
|
||||
<div className="flex items-center gap-1 cursor-pointer" ref={rootRef}>
|
||||
{currentModel}
|
||||
<BottomArrowMobile />
|
||||
</div>
|
||||
</Popover>
|
||||
</Modal.Trigger>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover
|
||||
content={content}
|
||||
content={content({ close: () => {} })}
|
||||
trigger="click"
|
||||
noArrow
|
||||
placement={
|
||||
position?.poi.relativePosition[1] !== Orientation.bottom ? "lb" : "lt"
|
||||
}
|
||||
popoverClassName="border border-select-popover rounded-lg shadow-select-popover-shadow w-actions-popover bg-select-popover-panel max-h-chat-actions-select-model-popover"
|
||||
popoverClassName="border border-select-popover rounded-lg shadow-select-popover-shadow w-actions-popover bg-select-popover-panel max-h-chat-actions-select-model-popover !py-0"
|
||||
onShow={(e) => {
|
||||
if (e) {
|
||||
autoScrollToSelectedModal();
|
||||
@@ -135,7 +138,7 @@ const ModelSelect = () => {
|
||||
className="flex items-center justify-center gap-1 cursor-pointer rounded-chat-model-select pl-3 pr-2.5 py-2 font-common leading-4 bg-chat-actions-select-model hover:bg-chat-actions-select-model-hover"
|
||||
ref={rootRef}
|
||||
>
|
||||
<div className="line-clamp-1 max-w-chat-actions-select-model">
|
||||
<div className="line-clamp-1 max-w-chat-actions-select-model text-sm-title">
|
||||
{currentModel}
|
||||
</div>
|
||||
<BottomArrow />
|
||||
|
124
app/containers/Chat/components/SessionItem.tsx
Normal file
124
app/containers/Chat/components/SessionItem.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import { Draggable } from "@hello-pangea/dnd";
|
||||
|
||||
import Locale from "@/app/locales";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { Path } from "@/app/constant";
|
||||
import { Mask } from "@/app/store/mask";
|
||||
import { useRef, useEffect } from "react";
|
||||
|
||||
import DeleteChatIcon from "@/app/icons/deleteChatIcon.svg";
|
||||
|
||||
import { getTime } from "@/app/utils";
|
||||
import DeleteIcon from "@/app/icons/deleteIcon.svg";
|
||||
import LogIcon from "@/app/icons/logIcon.svg";
|
||||
|
||||
import HoverPopover from "@/app/components/HoverPopover";
|
||||
|
||||
export default function SessionItem(props: {
|
||||
onClick?: () => void;
|
||||
onDelete?: () => void;
|
||||
title: string;
|
||||
count: number;
|
||||
time: string;
|
||||
selected: boolean;
|
||||
id: string;
|
||||
index: number;
|
||||
narrow?: boolean;
|
||||
mask: Mask;
|
||||
isMobileScreen: boolean;
|
||||
}) {
|
||||
const draggableRef = useRef<HTMLDivElement | null>(null);
|
||||
useEffect(() => {
|
||||
if (props.selected && draggableRef.current) {
|
||||
draggableRef.current?.scrollIntoView({
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
}, [props.selected]);
|
||||
|
||||
const { pathname: currentPath } = useLocation();
|
||||
|
||||
return (
|
||||
<Draggable draggableId={`${props.id}`} index={props.index}>
|
||||
{(provided) => (
|
||||
<div
|
||||
className={`
|
||||
group/chat-menu-list relative flex p-3 items-center gap-2 self-stretch rounded-md mb-2
|
||||
border
|
||||
bg-chat-menu-session-unselected border-chat-menu-session-unselected cursor-pointer
|
||||
${
|
||||
props.selected &&
|
||||
(currentPath === Path.Chat || currentPath === Path.Home)
|
||||
? `!bg-chat-menu-session-selected !border-chat-menu-session-selected`
|
||||
: `hover:bg-chat-menu-session-hovered hover:chat-menu-session-hovered`
|
||||
}
|
||||
`}
|
||||
onClick={props.onClick}
|
||||
// ref={(ele) => {
|
||||
// draggableRef.current = ele;
|
||||
// provided.innerRef(ele);
|
||||
// }}
|
||||
// {...provided.draggableProps}
|
||||
// {...provided.dragHandleProps}
|
||||
title={`${props.title}\n${Locale.ChatItem.ChatItemCount(
|
||||
props.count,
|
||||
)}`}
|
||||
>
|
||||
<div className=" flex-shrink-0">
|
||||
<LogIcon />
|
||||
</div>
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className={`flex justify-between items-center`}>
|
||||
<div
|
||||
className={` text-text-chat-menu-item-title text-sm-title line-clamp-1 flex-1`}
|
||||
>
|
||||
{props.title}
|
||||
</div>
|
||||
<div
|
||||
className={`text-text-chat-menu-item-time text-sm group-hover/chat-menu-list:opacity-0 pl-3`}
|
||||
>
|
||||
{getTime(props.time)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`text-text-chat-menu-item-description text-sm`}>
|
||||
{Locale.ChatItem.ChatItemCount(props.count)}
|
||||
</div>
|
||||
</div>
|
||||
<HoverPopover
|
||||
content={
|
||||
<div
|
||||
className={`flex items-center gap-3 p-3 rounded-action-btn leading-6 cursor-pointer`}
|
||||
onClickCapture={(e) => {
|
||||
props.onDelete?.();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<DeleteChatIcon />
|
||||
<div className="flex-1 font-common text-actions-popover-menu-item">
|
||||
{Locale.Chat.Actions.Delete}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
popoverClassName={`
|
||||
px-2 py-1 border-delete-chat-popover bg-delete-chat-popover-panel rounded-md shadow-delete-chat-popover-shadow
|
||||
`}
|
||||
noArrow
|
||||
align={props.isMobileScreen ? "end" : "start"}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
!absolute top-[50%] translate-y-[-50%] right-3 pointer-events-none opacity-0
|
||||
group-hover/chat-menu-list:pointer-events-auto
|
||||
group-hover/chat-menu-list:opacity-100
|
||||
hover:bg-select-hover rounded-chat-img
|
||||
`}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</div>
|
||||
</HoverPopover>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
DragDropContext,
|
||||
Droppable,
|
||||
Draggable,
|
||||
OnDragEndResponder,
|
||||
} from "@hello-pangea/dnd";
|
||||
|
||||
@@ -10,130 +9,15 @@ import { useAppConfig, useChatStore } from "@/app/store";
|
||||
import Locale from "@/app/locales";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { Path } from "@/app/constant";
|
||||
import { Mask } from "@/app/store/mask";
|
||||
import { useRef, useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import AddIcon from "@/app/icons/addIcon.svg";
|
||||
import NextChatTitle from "@/app/icons/nextchatTitle.svg";
|
||||
import DeleteChatIcon from "@/app/icons/deleteChatIcon.svg";
|
||||
|
||||
import { getTime } from "@/app/utils";
|
||||
import DeleteIcon from "@/app/icons/deleteIcon.svg";
|
||||
import LogIcon from "@/app/icons/logIcon.svg";
|
||||
|
||||
import MenuLayout from "@/app/components/MenuLayout";
|
||||
import Panel from "./ChatPanel";
|
||||
import Modal from "@/app/components/Modal";
|
||||
import HoverPopover from "@/app/components/HoverPopover";
|
||||
|
||||
export function SessionItem(props: {
|
||||
onClick?: () => void;
|
||||
onDelete?: () => void;
|
||||
title: string;
|
||||
count: number;
|
||||
time: string;
|
||||
selected: boolean;
|
||||
id: string;
|
||||
index: number;
|
||||
narrow?: boolean;
|
||||
mask: Mask;
|
||||
isMobileScreen: boolean;
|
||||
}) {
|
||||
const draggableRef = useRef<HTMLDivElement | null>(null);
|
||||
useEffect(() => {
|
||||
if (props.selected && draggableRef.current) {
|
||||
draggableRef.current?.scrollIntoView({
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
}, [props.selected]);
|
||||
|
||||
const { pathname: currentPath } = useLocation();
|
||||
|
||||
return (
|
||||
<Draggable draggableId={`${props.id}`} index={props.index}>
|
||||
{(provided) => (
|
||||
<div
|
||||
className={`
|
||||
group/chat-menu-list relative flex p-3 items-center gap-2 self-stretch rounded-md mb-2
|
||||
border
|
||||
bg-chat-menu-session-unselected border-chat-menu-session-unselected
|
||||
${
|
||||
props.selected &&
|
||||
(currentPath === Path.Chat || currentPath === Path.Home)
|
||||
? `!bg-chat-menu-session-selected !border-chat-menu-session-selected`
|
||||
: `hover:bg-chat-menu-session-hovered hover:chat-menu-session-hovered`
|
||||
}
|
||||
`}
|
||||
onClick={props.onClick}
|
||||
ref={(ele) => {
|
||||
draggableRef.current = ele;
|
||||
provided.innerRef(ele);
|
||||
}}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
title={`${props.title}\n${Locale.ChatItem.ChatItemCount(
|
||||
props.count,
|
||||
)}`}
|
||||
>
|
||||
<div className=" flex-shrink-0">
|
||||
<LogIcon />
|
||||
</div>
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className={`flex justify-between items-center`}>
|
||||
<div
|
||||
className={` text-text-chat-menu-item-title text-sm-title line-clamp-1 flex-1`}
|
||||
>
|
||||
{props.title}
|
||||
</div>
|
||||
<div
|
||||
className={`text-text-chat-menu-item-time text-sm group-hover/chat-menu-list:opacity-0 pl-3`}
|
||||
>
|
||||
{getTime(props.time)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`text-text-chat-menu-item-description text-sm`}>
|
||||
{Locale.ChatItem.ChatItemCount(props.count)}
|
||||
</div>
|
||||
</div>
|
||||
<HoverPopover
|
||||
content={
|
||||
<div
|
||||
className={`flex items-center gap-3 p-3 rounded-action-btn leading-6 cursor-pointer`}
|
||||
onClickCapture={(e) => {
|
||||
props.onDelete?.();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<DeleteChatIcon />
|
||||
<div className="flex-1 font-common text-actions-popover-menu-item">
|
||||
{Locale.Chat.Actions.Delete}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
popoverClassName={`
|
||||
px-2 py-1 border-delete-chat-popover bg-delete-chat-popover-panel rounded-md shadow-delete-chat-popover-shadow
|
||||
`}
|
||||
noArrow
|
||||
align={props.isMobileScreen ? "end" : "start"}
|
||||
>
|
||||
<div
|
||||
className={`
|
||||
!absolute top-[50%] translate-y-[-50%] right-3 pointer-events-none opacity-0
|
||||
group-hover/chat-menu-list:pointer-events-auto
|
||||
group-hover/chat-menu-list:opacity-100
|
||||
hover:bg-select-hover rounded-chat-img
|
||||
`}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</div>
|
||||
</HoverPopover>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
}
|
||||
import SessionItem from "./components/SessionItem";
|
||||
|
||||
export default MenuLayout(function SessionList(props) {
|
||||
const { setShowPanel } = props;
|
||||
@@ -225,8 +109,8 @@ export default MenuLayout(function SessionList(props) {
|
||||
<Droppable droppableId="chat-list">
|
||||
{(provided) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
// ref={provided.innerRef}
|
||||
// {...provided.droppableProps}
|
||||
className={`w-[100%]`}
|
||||
>
|
||||
{sessions.map((item, i) => (
|
||||
|
Reference in New Issue
Block a user