mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-09-03 13:56:55 +08:00
feat: maskpage&newchatpage adapt new ui framework done
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
import { Path } from "@/app/constant";
|
||||
import { ComponentType } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export interface MenuWrapperProps {
|
||||
show: boolean;
|
||||
wrapperClassName?: string;
|
||||
}
|
||||
|
||||
export default function MenuWrapper<ComponentProps>(
|
||||
Component: ComponentType<ComponentProps>,
|
||||
) {
|
||||
return function MenuHood(props: MenuWrapperProps & ComponentProps) {
|
||||
const { show, wrapperClassName } = props;
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
if (!show) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex flex-col px-6 pb-6 ${wrapperClassName}`}
|
||||
onClick={(e) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
navigate(Path.Home);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Component {...props} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}
|
@@ -1,220 +0,0 @@
|
||||
import {
|
||||
DragDropContext,
|
||||
Droppable,
|
||||
Draggable,
|
||||
OnDragEndResponder,
|
||||
} from "@hello-pangea/dnd";
|
||||
|
||||
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, useMemo } from "react";
|
||||
import { showConfirm } from "@/app/components/ui-lib";
|
||||
|
||||
import AddIcon from "@/app/icons/addIcon.svg";
|
||||
import NextChatTitle from "@/app/icons/nextchatTitle.svg";
|
||||
import { ListHoodProps } from "./types";
|
||||
import useMobileScreen from "@/app/hooks/useMobileScreen";
|
||||
import { getTime } from "@/app/utils";
|
||||
import DeleteIcon from "@/app/icons/deleteIcon.svg";
|
||||
import LogIcon from "@/app/icons/logIcon.svg";
|
||||
|
||||
export function SessionItem(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]);
|
||||
|
||||
const { pathname: currentPath } = useLocation();
|
||||
|
||||
return (
|
||||
<Draggable draggableId={`${props.id}`} index={props.index}>
|
||||
{(provided) => (
|
||||
<div
|
||||
className={`group relative flex p-3 items-center gap-2 self-stretch rounded-md hover:bg-gray-200 mb-2 ${
|
||||
props.selected &&
|
||||
(currentPath === Path.Chat || currentPath === Path.Home)
|
||||
? `bg-blue-100 border-blue-200 border`
|
||||
: `bg-gray-100`
|
||||
}`}
|
||||
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-gray-900 text-sm-title line-clamp-1 flex-1`}
|
||||
>
|
||||
{props.title}
|
||||
</div>
|
||||
<div
|
||||
className={`text-gray-500 text-sm group-hover:opacity-0 pl-3`}
|
||||
>
|
||||
{getTime(props.time)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`text-gray-500 text-sm`}>
|
||||
{Locale.ChatItem.ChatItemCount(props.count)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`absolute top-[50%] translate-y-[-50%] right-3 pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100`}
|
||||
onClickCapture={(e) => {
|
||||
props.onDelete?.();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
}
|
||||
|
||||
export default function SessionList(props: ListHoodProps) {
|
||||
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 config = useAppConfig();
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
let layoutClassName = "py-7 px-0";
|
||||
|
||||
if (isMobileScreen) {
|
||||
layoutClassName = "h-menu-title-mobile py-6";
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div data-tauri-drag-region>
|
||||
<div
|
||||
className={`flex items-center justify-between ${layoutClassName}`}
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<div className="">
|
||||
<NextChatTitle />
|
||||
</div>
|
||||
<div
|
||||
className=""
|
||||
onClick={() => {
|
||||
if (config.dontShowMaskSplashScreen) {
|
||||
chatStore.newSession();
|
||||
navigate(Path.Chat);
|
||||
} else {
|
||||
navigate(Path.NewChat);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<AddIcon />
|
||||
</div>
|
||||
</div>
|
||||
<div className={`pb-3 text-sm sm:text-sm-mobile text-blue-500`}>
|
||||
Build your own AI assistant.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`flex overflow-y-auto overflow-x-hidden`}
|
||||
onClick={(e) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
navigate(Path.Home);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<Droppable droppableId="chat-list">
|
||||
{(provided) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
className="w-[100%]"
|
||||
>
|
||||
{sessions.map((item, i) => (
|
||||
<SessionItem
|
||||
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 (
|
||||
!isMobileScreen ||
|
||||
(await showConfirm(Locale.Home.DeleteChat))
|
||||
) {
|
||||
chatStore.deleteSession(i);
|
||||
}
|
||||
}}
|
||||
mask={item.mask}
|
||||
/>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
import { ListHoodProps } from "./types";
|
||||
|
||||
export default function SettingList(props: ListHoodProps) {
|
||||
return <></>;
|
||||
}
|
@@ -1,42 +1,25 @@
|
||||
import DragIcon from "@/app/icons/drag.svg";
|
||||
import DiscoverIcon from "@/app/icons/discoverActive.svg";
|
||||
import AssistantActiveIcon from "@/app/icons/assistantActive.svg";
|
||||
import GitHubIcon from "@/app/icons/githubIcon.svg";
|
||||
import SettingIcon from "@/app/icons/settingActive.svg";
|
||||
import DiscoverIcon from "@/app/icons/discoverActive.svg";
|
||||
import DiscoverInactiveIcon from "@/app/icons/discoverInactive.svg";
|
||||
import AssistantInactiveIcon from "@/app/icons/assistantInactive.svg";
|
||||
import DiscoverMobileActive from "@/app/icons/discoverMobileActive.svg";
|
||||
import DiscoverMobileInactive from "@/app/icons/discoverMobileInactive.svg";
|
||||
import SettingIcon from "@/app/icons/settingActive.svg";
|
||||
import SettingInactiveIcon from "@/app/icons/settingInactive.svg";
|
||||
import SettingMobileActive from "@/app/icons/settingMobileActive.svg";
|
||||
import DiscoverMobileActive from "@/app/icons/discoverMobileActive.svg";
|
||||
import SettingMobileInactive from "@/app/icons/settingMobileInactive.svg";
|
||||
import AssistantActiveIcon from "@/app/icons/assistantActive.svg";
|
||||
import AssistantInactiveIcon from "@/app/icons/assistantInactive.svg";
|
||||
import AssistantMobileActive from "@/app/icons/assistantMobileActive.svg";
|
||||
import AssistantMobileInactive from "@/app/icons/assistantMobileInactive.svg";
|
||||
|
||||
import { useAppConfig } from "@/app/store";
|
||||
import { Path, REPO_URL } from "@/app/constant";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import dynamic from "next/dynamic";
|
||||
import useHotKey from "@/app/hooks/useHotKey";
|
||||
import useDragSideBar from "@/app/hooks/useDragSideBar";
|
||||
import useMobileScreen from "@/app/hooks/useMobileScreen";
|
||||
import MenuWrapper from "./MenuWrapper";
|
||||
import ActionsBar from "@/app/components/ActionsBar";
|
||||
|
||||
const SessionList = MenuWrapper(
|
||||
dynamic(async () => await import("./SessionList"), {
|
||||
loading: () => null,
|
||||
}),
|
||||
);
|
||||
|
||||
const SettingList = MenuWrapper(
|
||||
dynamic(async () => await import("./SettingList"), {
|
||||
loading: () => null,
|
||||
}),
|
||||
);
|
||||
|
||||
export function SideBar(props: { className?: string }) {
|
||||
// drag side bar
|
||||
const { onDragStart } = useDragSideBar();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const loc = useLocation();
|
||||
|
||||
@@ -56,18 +39,15 @@ export function SideBar(props: { className?: string }) {
|
||||
selectedTab = Path.Settings;
|
||||
break;
|
||||
default:
|
||||
selectedTab = Path.Chat;
|
||||
selectedTab = Path.Home;
|
||||
}
|
||||
|
||||
let containerClassName = "relative flex h-[100%] w-[100%]";
|
||||
let containerClassName = "relative flex h-[100%]";
|
||||
let tabActionsClassName = "2xl:px-5 xl:px-4 px-2 py-6";
|
||||
let menuClassName =
|
||||
"max-md:px-4 max-md:pb-4 rounded-md my-2.5 bg-gray-50 flex-1";
|
||||
|
||||
if (isMobileScreen) {
|
||||
containerClassName = "flex flex-col-reverse w-[100%] h-[100%]";
|
||||
tabActionsClassName = "bg-gray-100 rounded-tl-md rounded-tr-md h-mobile";
|
||||
menuClassName = `flex-1 px-4`;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -81,12 +61,12 @@ export function SideBar(props: { className?: string }) {
|
||||
active: <DiscoverIcon />,
|
||||
inactive: <DiscoverInactiveIcon />,
|
||||
mobileActive: <DiscoverMobileActive />,
|
||||
mobileInactive: <DiscoverInactiveIcon />,
|
||||
mobileInactive: <DiscoverMobileInactive />,
|
||||
},
|
||||
title: "Discover",
|
||||
},
|
||||
{
|
||||
id: Path.Chat,
|
||||
id: Path.Home,
|
||||
icons: {
|
||||
active: <AssistantActiveIcon />,
|
||||
inactive: <AssistantInactiveIcon />,
|
||||
@@ -106,7 +86,7 @@ export function SideBar(props: { className?: string }) {
|
||||
active: <SettingIcon />,
|
||||
inactive: <SettingInactiveIcon />,
|
||||
mobileActive: <SettingMobileActive />,
|
||||
mobileInactive: <SettingInactiveIcon />,
|
||||
mobileInactive: <SettingMobileInactive />,
|
||||
},
|
||||
className: "p-2",
|
||||
title: "Settrings",
|
||||
@@ -127,36 +107,16 @@ export function SideBar(props: { className?: string }) {
|
||||
}}
|
||||
groups={{
|
||||
normal: [
|
||||
[Path.Chat, Path.Masks],
|
||||
[Path.Home, Path.Masks],
|
||||
["github", Path.Settings],
|
||||
],
|
||||
mobile: [[Path.Chat, Path.Masks, Path.Settings]],
|
||||
mobile: [[Path.Home, Path.Masks, Path.Settings]],
|
||||
}}
|
||||
selected={selectedTab}
|
||||
className={`${
|
||||
isMobileScreen ? "justify-around" : "flex-col"
|
||||
} ${tabActionsClassName}`}
|
||||
/>
|
||||
|
||||
<SessionList
|
||||
show={selectedTab === Path.Chat}
|
||||
wrapperClassName={menuClassName}
|
||||
/>
|
||||
<SettingList
|
||||
show={selectedTab === Path.Settings}
|
||||
wrapperClassName={menuClassName}
|
||||
/>
|
||||
|
||||
{!isMobileScreen && (
|
||||
<div
|
||||
className={`group absolute right-0 h-[100%] flex items-center`}
|
||||
onPointerDown={(e) => onDragStart(e as any)}
|
||||
>
|
||||
<div className="opacity-0 group-hover:bg-[rgba($color: #000000, $alpha: 0.01) group-hover:opacity-20">
|
||||
<DragIcon />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -1,4 +0,0 @@
|
||||
export interface ListHoodProps {
|
||||
// narrow?: boolean;
|
||||
className?: string;
|
||||
}
|
Reference in New Issue
Block a user