2023-03-10 02:01:40 +09:00
|
|
|
"use client";
|
|
|
|
|
2023-04-03 14:29:37 +09:00
|
|
|
require("../polyfill");
|
|
|
|
|
2023-04-11 03:54:31 +09:00
|
|
|
import { useState, useEffect, useRef } from "react";
|
2023-03-12 02:14:07 +09:00
|
|
|
|
2023-03-10 02:01:40 +09:00
|
|
|
import { IconButton } from "./button";
|
2023-03-13 04:06:21 +09:00
|
|
|
import styles from "./home.module.scss";
|
2023-03-10 02:01:40 +09:00
|
|
|
|
|
|
|
import SettingsIcon from "../icons/settings.svg";
|
|
|
|
import GithubIcon from "../icons/github.svg";
|
|
|
|
import ChatGptIcon from "../icons/chatgpt.svg";
|
2023-04-03 00:05:54 +09:00
|
|
|
|
2023-03-10 02:01:40 +09:00
|
|
|
import BotIcon from "../icons/bot.svg";
|
|
|
|
import AddIcon from "../icons/add.svg";
|
2023-03-11 03:25:33 +09:00
|
|
|
import LoadingIcon from "../icons/three-dots.svg";
|
2023-03-15 02:44:42 +09:00
|
|
|
import CloseIcon from "../icons/close.svg";
|
2023-03-11 03:25:33 +09:00
|
|
|
|
2023-04-03 14:29:37 +09:00
|
|
|
import { useChatStore } from "../store";
|
2023-04-21 00:20:25 +09:00
|
|
|
import { getCSSVar, useMobileScreen } from "../utils";
|
2023-03-21 23:56:27 +09:00
|
|
|
import Locale from "../locales";
|
2023-04-03 00:05:54 +09:00
|
|
|
import { Chat } from "./chat";
|
2023-03-14 01:25:07 +09:00
|
|
|
|
2023-03-21 00:11:04 +09:00
|
|
|
import dynamic from "next/dynamic";
|
2023-03-24 01:01:00 +09:00
|
|
|
import { REPO_URL } from "../constant";
|
2023-04-03 14:29:37 +09:00
|
|
|
import { ErrorBoundary } from "./error";
|
2023-03-21 00:11:04 +09:00
|
|
|
|
2023-03-21 23:56:27 +09:00
|
|
|
export function Loading(props: { noLogo?: boolean }) {
|
|
|
|
return (
|
|
|
|
<div className={styles["loading-content"]}>
|
|
|
|
{!props.noLogo && <BotIcon />}
|
|
|
|
<LoadingIcon />
|
|
|
|
</div>
|
|
|
|
);
|
2023-03-21 00:11:04 +09:00
|
|
|
}
|
|
|
|
|
2023-03-21 23:56:27 +09:00
|
|
|
const Settings = dynamic(async () => (await import("./settings")).Settings, {
|
|
|
|
loading: () => <Loading noLogo />,
|
|
|
|
});
|
2023-03-21 00:11:04 +09:00
|
|
|
|
2023-04-06 03:41:27 +09:00
|
|
|
const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
|
|
|
|
loading: () => <Loading noLogo />,
|
2023-03-21 23:56:27 +09:00
|
|
|
});
|
2023-03-11 21:54:24 +09:00
|
|
|
|
2023-03-13 04:06:21 +09:00
|
|
|
function useSwitchTheme() {
|
|
|
|
const config = useChatStore((state) => state.config);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
document.body.classList.remove("light");
|
|
|
|
document.body.classList.remove("dark");
|
2023-03-27 18:04:11 +09:00
|
|
|
|
2023-03-13 04:06:21 +09:00
|
|
|
if (config.theme === "dark") {
|
|
|
|
document.body.classList.add("dark");
|
|
|
|
} else if (config.theme === "light") {
|
|
|
|
document.body.classList.add("light");
|
|
|
|
}
|
2023-03-27 18:04:11 +09:00
|
|
|
|
2023-04-04 01:24:59 +09:00
|
|
|
const metaDescriptionDark = document.querySelector(
|
|
|
|
'meta[name="theme-color"][media]',
|
|
|
|
);
|
|
|
|
const metaDescriptionLight = document.querySelector(
|
|
|
|
'meta[name="theme-color"]:not([media])',
|
|
|
|
);
|
2023-03-16 02:24:03 +09:00
|
|
|
|
2023-04-04 01:24:59 +09:00
|
|
|
if (config.theme === "auto") {
|
|
|
|
metaDescriptionDark?.setAttribute("content", "#151515");
|
|
|
|
metaDescriptionLight?.setAttribute("content", "#fafafa");
|
|
|
|
} else {
|
2023-04-13 03:07:24 +09:00
|
|
|
const themeColor = getCSSVar("--themeColor");
|
2023-04-04 01:24:59 +09:00
|
|
|
metaDescriptionDark?.setAttribute("content", themeColor);
|
|
|
|
metaDescriptionLight?.setAttribute("content", themeColor);
|
|
|
|
}
|
2023-03-27 18:04:11 +09:00
|
|
|
}, [config.theme]);
|
2023-03-20 00:13:10 +09:00
|
|
|
}
|
|
|
|
|
2023-04-10 01:54:17 +09:00
|
|
|
function useDragSideBar() {
|
|
|
|
const limit = (x: number) => Math.min(500, Math.max(220, x));
|
|
|
|
|
|
|
|
const chatStore = useChatStore();
|
|
|
|
const startX = useRef(0);
|
|
|
|
const startDragWidth = useRef(chatStore.config.sidebarWidth ?? 300);
|
|
|
|
const lastUpdateTime = useRef(Date.now());
|
|
|
|
|
|
|
|
const handleMouseMove = useRef((e: MouseEvent) => {
|
|
|
|
if (Date.now() < lastUpdateTime.current + 100) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lastUpdateTime.current = Date.now();
|
|
|
|
const d = e.clientX - startX.current;
|
|
|
|
const nextWidth = limit(startDragWidth.current + d);
|
|
|
|
chatStore.updateConfig((config) => (config.sidebarWidth = nextWidth));
|
|
|
|
});
|
|
|
|
|
|
|
|
const handleMouseUp = useRef(() => {
|
|
|
|
startDragWidth.current = chatStore.config.sidebarWidth ?? 300;
|
|
|
|
window.removeEventListener("mousemove", handleMouseMove.current);
|
|
|
|
window.removeEventListener("mouseup", handleMouseUp.current);
|
|
|
|
});
|
|
|
|
|
|
|
|
const onDragMouseDown = (e: MouseEvent) => {
|
|
|
|
startX.current = e.clientX;
|
|
|
|
|
|
|
|
window.addEventListener("mousemove", handleMouseMove.current);
|
|
|
|
window.addEventListener("mouseup", handleMouseUp.current);
|
|
|
|
};
|
2023-04-21 00:20:25 +09:00
|
|
|
const isMobileScreen = useMobileScreen();
|
2023-04-10 01:54:17 +09:00
|
|
|
|
|
|
|
useEffect(() => {
|
2023-04-21 00:20:25 +09:00
|
|
|
const sideBarWidth = isMobileScreen
|
|
|
|
? "100vw"
|
|
|
|
: `${limit(chatStore.config.sidebarWidth ?? 300)}px`;
|
|
|
|
document.documentElement.style.setProperty("--sidebar-width", sideBarWidth);
|
|
|
|
}, [chatStore.config.sidebarWidth, isMobileScreen]);
|
2023-04-10 01:54:17 +09:00
|
|
|
|
|
|
|
return {
|
|
|
|
onDragMouseDown,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-03-27 17:58:53 +09:00
|
|
|
const useHasHydrated = () => {
|
|
|
|
const [hasHydrated, setHasHydrated] = useState<boolean>(false);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
setHasHydrated(true);
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
return hasHydrated;
|
|
|
|
};
|
|
|
|
|
2023-04-03 14:29:37 +09:00
|
|
|
function _Home() {
|
2023-03-21 23:56:27 +09:00
|
|
|
const [createNewSession, currentIndex, removeSession] = useChatStore(
|
|
|
|
(state) => [
|
|
|
|
state.newSession,
|
|
|
|
state.currentSessionIndex,
|
2023-04-02 03:56:45 +09:00
|
|
|
state.removeSession,
|
2023-04-02 14:45:34 +09:00
|
|
|
],
|
2023-03-21 23:56:27 +09:00
|
|
|
);
|
2023-04-07 01:14:27 +09:00
|
|
|
const chatStore = useChatStore();
|
2023-03-27 17:58:53 +09:00
|
|
|
const loading = !useHasHydrated();
|
2023-03-15 02:44:42 +09:00
|
|
|
const [showSideBar, setShowSideBar] = useState(true);
|
2023-03-11 03:25:33 +09:00
|
|
|
|
2023-03-17 01:08:16 +09:00
|
|
|
// setting
|
2023-03-12 02:14:07 +09:00
|
|
|
const [openSettings, setOpenSettings] = useState(false);
|
2023-03-13 04:21:48 +09:00
|
|
|
const config = useChatStore((state) => state.config);
|
2023-03-12 02:14:07 +09:00
|
|
|
|
2023-04-10 01:54:17 +09:00
|
|
|
// drag side bar
|
|
|
|
const { onDragMouseDown } = useDragSideBar();
|
2023-04-21 00:20:25 +09:00
|
|
|
const isMobileScreen = useMobileScreen();
|
2023-04-10 01:54:17 +09:00
|
|
|
|
2023-03-13 04:06:21 +09:00
|
|
|
useSwitchTheme();
|
|
|
|
|
2023-03-14 01:25:07 +09:00
|
|
|
if (loading) {
|
2023-03-21 00:11:04 +09:00
|
|
|
return <Loading />;
|
2023-03-14 01:25:07 +09:00
|
|
|
}
|
|
|
|
|
2023-03-10 02:01:40 +09:00
|
|
|
return (
|
2023-04-11 03:56:48 +09:00
|
|
|
<div
|
|
|
|
className={`${
|
2023-04-21 00:20:25 +09:00
|
|
|
config.tightBorder && !isMobileScreen
|
2023-04-11 03:56:48 +09:00
|
|
|
? styles["tight-container"]
|
|
|
|
: styles.container
|
|
|
|
}`}
|
|
|
|
>
|
2023-03-15 02:44:42 +09:00
|
|
|
<div
|
2023-04-11 03:56:48 +09:00
|
|
|
className={styles.sidebar + ` ${showSideBar && styles["sidebar-show"]}`}
|
2023-03-15 02:44:42 +09:00
|
|
|
>
|
2023-04-11 03:56:48 +09:00
|
|
|
<div className={styles["sidebar-header"]}>
|
|
|
|
<div className={styles["sidebar-title"]}>ChatGPT Next</div>
|
|
|
|
<div className={styles["sidebar-sub-title"]}>
|
|
|
|
Build your own AI assistant.
|
2023-04-11 03:54:31 +09:00
|
|
|
</div>
|
2023-04-11 03:56:48 +09:00
|
|
|
<div className={styles["sidebar-logo"]}>
|
|
|
|
<ChatGptIcon />
|
2023-04-11 03:54:31 +09:00
|
|
|
</div>
|
2023-04-11 03:56:48 +09:00
|
|
|
</div>
|
2023-04-11 03:54:31 +09:00
|
|
|
|
2023-04-11 03:56:48 +09:00
|
|
|
<div
|
|
|
|
className={styles["sidebar-body"]}
|
|
|
|
onClick={() => {
|
|
|
|
setOpenSettings(false);
|
|
|
|
setShowSideBar(false);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<ChatList />
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className={styles["sidebar-tail"]}>
|
|
|
|
<div className={styles["sidebar-actions"]}>
|
|
|
|
<div className={styles["sidebar-action"] + " " + styles.mobile}>
|
|
|
|
<IconButton
|
|
|
|
icon={<CloseIcon />}
|
|
|
|
onClick={chatStore.deleteSession}
|
|
|
|
/>
|
2023-03-15 02:44:42 +09:00
|
|
|
</div>
|
2023-04-11 03:56:48 +09:00
|
|
|
<div className={styles["sidebar-action"]}>
|
2023-03-12 02:14:07 +09:00
|
|
|
<IconButton
|
2023-04-11 03:56:48 +09:00
|
|
|
icon={<SettingsIcon />}
|
2023-03-21 02:00:05 +09:00
|
|
|
onClick={() => {
|
2023-04-11 03:56:48 +09:00
|
|
|
setOpenSettings(true);
|
2023-03-21 23:56:27 +09:00
|
|
|
setShowSideBar(false);
|
2023-03-21 02:00:05 +09:00
|
|
|
}}
|
2023-04-03 02:48:43 +09:00
|
|
|
shadow
|
2023-03-12 02:14:07 +09:00
|
|
|
/>
|
2023-03-10 02:01:40 +09:00
|
|
|
</div>
|
2023-04-11 03:56:48 +09:00
|
|
|
<div className={styles["sidebar-action"]}>
|
|
|
|
<a href={REPO_URL} target="_blank">
|
|
|
|
<IconButton icon={<GithubIcon />} shadow />
|
|
|
|
</a>
|
|
|
|
</div>
|
2023-03-10 02:01:40 +09:00
|
|
|
</div>
|
2023-04-11 03:56:48 +09:00
|
|
|
<div>
|
|
|
|
<IconButton
|
|
|
|
icon={<AddIcon />}
|
|
|
|
text={Locale.Home.NewChat}
|
|
|
|
onClick={() => {
|
|
|
|
createNewSession();
|
|
|
|
setShowSideBar(false);
|
2023-03-28 12:51:36 +09:00
|
|
|
}}
|
2023-04-11 03:56:48 +09:00
|
|
|
shadow
|
2023-03-11 03:25:33 +09:00
|
|
|
/>
|
2023-04-11 03:56:48 +09:00
|
|
|
</div>
|
2023-03-10 02:01:40 +09:00
|
|
|
</div>
|
2023-04-11 03:56:48 +09:00
|
|
|
|
|
|
|
<div
|
|
|
|
className={styles["sidebar-drag"]}
|
|
|
|
onMouseDown={(e) => onDragMouseDown(e as any)}
|
|
|
|
></div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className={styles["window-content"]}>
|
|
|
|
{openSettings ? (
|
|
|
|
<Settings
|
|
|
|
closeSettings={() => {
|
|
|
|
setOpenSettings(false);
|
|
|
|
setShowSideBar(true);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<Chat
|
|
|
|
key="chat"
|
|
|
|
showSideBar={() => setShowSideBar(true)}
|
|
|
|
sideBarShowing={showSideBar}
|
|
|
|
/>
|
|
|
|
)}
|
2023-03-12 02:14:07 +09:00
|
|
|
</div>
|
2023-04-11 03:56:48 +09:00
|
|
|
</div>
|
2023-03-10 02:01:40 +09:00
|
|
|
);
|
|
|
|
}
|
2023-04-03 14:29:37 +09:00
|
|
|
|
|
|
|
export function Home() {
|
|
|
|
return (
|
|
|
|
<ErrorBoundary>
|
|
|
|
<_Home></_Home>
|
|
|
|
</ErrorBoundary>
|
|
|
|
);
|
|
|
|
}
|