import React, { useEffect, useRef, useMemo, useState, Fragment } from "react";
import styles from "./home.module.scss";
import { IconButton } from "./button";
import SettingsIcon from "../icons/settings.svg";
import GithubIcon from "../icons/github.svg";
import ChatGptIcon from "../icons/chatgpt.svg";
import AddIcon from "../icons/add.svg";
import CloseIcon from "../icons/close.svg";
import DeleteIcon from "../icons/delete.svg";
import MaskIcon from "../icons/mask.svg";
import DragIcon from "../icons/drag.svg";
import DiscoveryIcon from "../icons/discovery.svg";
import faviconSrc from "../icons/favicon.png";
import { EditOutlined } from '@ant-design/icons';
import Locale from "../locales";
import { useAppConfig, useChatStore, useGlobalStore } from "../store";
import {
DEFAULT_SIDEBAR_WIDTH,
MAX_SIDEBAR_WIDTH,
MIN_SIDEBAR_WIDTH,
NARROW_SIDEBAR_WIDTH,
Path,
PLUGINS,
REPO_URL,
} from "../constant";
import { Link, useNavigate } from "react-router-dom";
import { isIOS, useMobileScreen } from "../utils";
import dynamic from "next/dynamic";
import api from "@/app/api/api";
import { Button, Dropdown, Form, Input, Menu, Modal } from "antd";
import { downloadFile } from "../utils/index";
const FormItem = Form.Item;
const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
loading: () => null,
});
export function useHotKey() {
const chatStore = useChatStore();
useEffect(() => {
const onKeyDown = (e: KeyboardEvent) => {
if (e.altKey || e.ctrlKey) {
if (e.key === "ArrowUp") {
chatStore.nextSession(-1);
} else if (e.key === "ArrowDown") {
chatStore.nextSession(1);
}
}
};
window.addEventListener("keydown", onKeyDown);
return () => window.removeEventListener("keydown", onKeyDown);
});
}
export function useDragSideBar() {
const limit = (x: number) => Math.min(MAX_SIDEBAR_WIDTH, x);
const config = useAppConfig();
const startX = useRef(0);
const startDragWidth = useRef(config.sidebarWidth ?? DEFAULT_SIDEBAR_WIDTH);
const lastUpdateTime = useRef(Date.now());
const toggleSideBar = () => {
config.update((config) => {
if (config.sidebarWidth < MIN_SIDEBAR_WIDTH) {
config.sidebarWidth = DEFAULT_SIDEBAR_WIDTH;
} else {
config.sidebarWidth = NARROW_SIDEBAR_WIDTH;
}
});
};
const onDragStart = (e: MouseEvent) => {
// Remembers the initial width each time the mouse is pressed
startX.current = e.clientX;
startDragWidth.current = config.sidebarWidth;
const dragStartTime = Date.now();
const handleDragMove = (e: MouseEvent) => {
if (Date.now() < lastUpdateTime.current + 20) {
return;
}
lastUpdateTime.current = Date.now();
const d = e.clientX - startX.current;
const nextWidth = limit(startDragWidth.current + d);
config.update((config) => {
if (nextWidth < MIN_SIDEBAR_WIDTH) {
config.sidebarWidth = NARROW_SIDEBAR_WIDTH;
} else {
config.sidebarWidth = nextWidth;
}
});
};
const handleDragEnd = () => {
// In useRef the data is non-responsive, so `config.sidebarWidth` can't get the dynamic sidebarWidth
window.removeEventListener("pointermove", handleDragMove);
window.removeEventListener("pointerup", handleDragEnd);
// if user click the drag icon, should toggle the sidebar
const shouldFireClick = Date.now() - dragStartTime < 300;
if (shouldFireClick) {
toggleSideBar();
}
};
window.addEventListener("pointermove", handleDragMove);
window.addEventListener("pointerup", handleDragEnd);
};
const isMobileScreen = useMobileScreen();
const shouldNarrow =
!isMobileScreen && config.sidebarWidth < MIN_SIDEBAR_WIDTH;
useEffect(() => {
const barWidth = shouldNarrow
? NARROW_SIDEBAR_WIDTH
: limit(config.sidebarWidth ?? DEFAULT_SIDEBAR_WIDTH);
const sideBarWidth = isMobileScreen ? "100vw" : `${barWidth}px`;
document.documentElement.style.setProperty("--sidebar-width", sideBarWidth);
}, [config.sidebarWidth, isMobileScreen, shouldNarrow]);
return {
onDragStart,
shouldNarrow,
};
}
export function SideBarContainer(props: {
children: React.ReactNode;
onDragStart: (e: MouseEvent) => void;
shouldNarrow: boolean;
className?: string;
}) {
const isMobileScreen = useMobileScreen();
const isIOSMobile = useMemo(
() => isIOS() && isMobileScreen,
[isMobileScreen],
);
const { children, className, onDragStart, shouldNarrow } = props;
return (
{children}
onDragStart(e as any)}
>
);
}
export function SideBarHeader(props: {
title?: string | React.ReactNode;
subTitle?: string | React.ReactNode;
logo?: React.ReactNode;
children?: React.ReactNode;
}) {
const { title, subTitle, logo, children } = props;
return (
{children}
);
}
export function SideBarBody(props: {
children: React.ReactNode;
onClick?: (e: React.MouseEvent) => void;
}) {
const { onClick, children } = props;
return (
{children}
);
}
export function SideBarTail(props: {
primaryAction?: React.ReactNode;
secondaryAction?: React.ReactNode;
}) {
const { primaryAction, secondaryAction } = props;
return (
{primaryAction}
{secondaryAction}
);
}
export const SideBar = (props: { className?: string }) => {
// useHotKey();
const { onDragStart, shouldNarrow } = useDragSideBar();
const [showPluginSelector, setShowPluginSelector] = useState(false);
const navigate = useNavigate();
const config = useAppConfig();
const chatStore = useChatStore();
const globalStore = useGlobalStore();
const [menuList, setMenuList] = useState([])
const [modalOpen, setModalOpen] = useState(false)
const [form] = Form.useForm();
// 获取聊天列表
const fetchChatList = async () => {
try {
const res = await api.get(`/bigmodel/api/dialog/list/${globalStore.selectedAppId}`);
const list = res.data.map((item: any) => {
return {
...item,
children: item.children.map((child: any) => {
const items = [
{
key: '1',
label: (
{
setModalOpen(true);
form.setFieldsValue({
dialogId: child.key,
dialogName: child.label
});
}}>
重命名
),
},
{
key: '2',
label: (
{
try {
const blob = await api.post(`/bigmodel/api/dialog/export/${child.key}`, {}, { responseType: 'blob' });
const fileName = `${child.label}.xlsx`;
downloadFile(blob, fileName);
} catch (error) {
console.error(error);
}
}}>
导出
),
},
{
key: '3',
label: (
{
try {
await api.delete(`/bigmodel/api/dialog/del/${child.key}`);
await fetchChatList()
// 删除不需要清理消息
// chatStore.clearSessions();
// chatStore.updateCurrentSession((value) => {
// value.appId = globalStore.selectedAppId;
// });
} catch (error) {
console.error(error);
}
}}>
删除
),
},
];
return {
...child,
label:
{child.label}
e.stopPropagation()} />
}
})
}
})
setMenuList(list);
} catch (error) {
console.error(error)
}
}
useEffect(() => {
fetchChatList();
}, [globalStore.selectedAppId]);
useEffect(() => {
chatStore.clearSessions();
}, []);
return (
}
>
{/*
}
text={shouldNarrow ? undefined : Locale.Mask.Name}
className={styles["sidebar-bar-button"]}
onClick={() => {
if (config.dontShowMaskSplashScreen !== true) {
navigate(Path.NewChat, { state: { fromHome: true } });
} else {
navigate(Path.Masks, { state: { fromHome: true } });
}
}}
shadow
/>
}
text={shouldNarrow ? undefined : Locale.Discovery.Name}
className={styles["sidebar-bar-button"]}
onClick={() => setShowPluginSelector(true)}
shadow
/>
*/}
{/* {showPluginSelector && (
{
return {
title: item.name,
value: item.path,
};
}),
]}
onClose={() => setShowPluginSelector(false)}
onSelection={(s) => {
navigate(s[0], { state: { fromHome: true } });
}}
/>
)} */}
{/* {
if (e.target === e.currentTarget) {
navigate(Path.Home);
}
}}
>
*/}
{/*
}
onClick={async () => {
if (await showConfirm(Locale.Home.DeleteChat)) {
chatStore.deleteSession(chatStore.currentSessionIndex);
}
}}
/>
}
shadow
/>
>
}
secondaryAction={
}
text={shouldNarrow ? undefined : Locale.Home.NewChat}
onClick={() => {
if (config.dontShowMaskSplashScreen) {
chatStore.newSession();
navigate(Path.Chat);
} else {
navigate(Path.NewChat);
}
}}
shadow
/>
}
/> */}
);
}