123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- "use client";
- require("../polyfill");
- import { useState, useEffect } from "react";
- import { IconButton } from "./button";
- import styles from "./home.module.scss";
- import SettingsIcon from "../icons/settings.svg";
- import GithubIcon from "../icons/github.svg";
- import ChatGptIcon from "../icons/chatgpt.svg";
- import BotIcon from "../icons/bot.svg";
- import AddIcon from "../icons/add.svg";
- import LoadingIcon from "../icons/three-dots.svg";
- import CloseIcon from "../icons/close.svg";
- import { useChatStore } from "../store";
- import { isMobileScreen } from "../utils";
- import Locale from "../locales";
- import { Chat } from "./chat";
- import dynamic from "next/dynamic";
- import { REPO_URL } from "../constant";
- import { ErrorBoundary } from "./error";
- import calcTextareaHeight from "../calcTextareaHeight";
- export function Loading(props: { noLogo?: boolean }) {
- return (
- <div className={styles["loading-content"]}>
- {!props.noLogo && <BotIcon />}
- <LoadingIcon />
- </div>
- );
- }
- const Settings = dynamic(async () => (await import("./settings")).Settings, {
- loading: () => <Loading noLogo />,
- });
- const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
- loading: () => <Loading noLogo />,
- });
- function useSwitchTheme() {
- const config = useChatStore((state) => state.config);
- useEffect(() => {
- document.body.classList.remove("light");
- document.body.classList.remove("dark");
- if (config.theme === "dark") {
- document.body.classList.add("dark");
- } else if (config.theme === "light") {
- document.body.classList.add("light");
- }
- const metaDescriptionDark = document.querySelector(
- 'meta[name="theme-color"][media]',
- );
- const metaDescriptionLight = document.querySelector(
- 'meta[name="theme-color"]:not([media])',
- );
- if (config.theme === "auto") {
- metaDescriptionDark?.setAttribute("content", "#151515");
- metaDescriptionLight?.setAttribute("content", "#fafafa");
- } else {
- const themeColor = getComputedStyle(document.body)
- .getPropertyValue("--theme-color")
- .trim();
- metaDescriptionDark?.setAttribute("content", themeColor);
- metaDescriptionLight?.setAttribute("content", themeColor);
- }
- }, [config.theme]);
- }
- const useHasHydrated = () => {
- const [hasHydrated, setHasHydrated] = useState<boolean>(false);
- useEffect(() => {
- setHasHydrated(true);
- }, []);
- return hasHydrated;
- };
- function _Home() {
- const [createNewSession, currentIndex, removeSession] = useChatStore(
- (state) => [
- state.newSession,
- state.currentSessionIndex,
- state.removeSession,
- ],
- );
- const chatStore = useChatStore();
- const loading = !useHasHydrated();
- const [showSideBar, setShowSideBar] = useState(true);
- // setting
- const [openSettings, setOpenSettings] = useState(false);
- const config = useChatStore((state) => state.config);
- useSwitchTheme();
- if (loading) {
- return <Loading />;
- }
- return (
- <div
- className={`${
- config.tightBorder && !isMobileScreen()
- ? styles["tight-container"]
- : styles.container
- }`}
- >
- <div
- className={styles.sidebar + ` ${showSideBar && styles["sidebar-show"]}`}
- >
- <div className={styles["sidebar-header"]}>
- <div className={styles["sidebar-title"]}>ChatGPT Next</div>
- <div className={styles["sidebar-sub-title"]}>
- Build your own AI assistant.
- </div>
- <div className={styles["sidebar-logo"]}>
- <ChatGptIcon />
- </div>
- </div>
- <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}
- />
- </div>
- <div className={styles["sidebar-action"]}>
- <IconButton
- icon={<SettingsIcon />}
- onClick={() => {
- setOpenSettings(true);
- setShowSideBar(false);
- }}
- shadow
- />
- </div>
- <div className={styles["sidebar-action"]}>
- <a href={REPO_URL} target="_blank">
- <IconButton icon={<GithubIcon />} shadow />
- </a>
- </div>
- </div>
- <div>
- <IconButton
- icon={<AddIcon />}
- text={Locale.Home.NewChat}
- onClick={() => {
- createNewSession();
- setShowSideBar(false);
- }}
- shadow
- />
- </div>
- </div>
- </div>
- <div className={styles["window-content"]}>
- {openSettings ? (
- <Settings
- closeSettings={() => {
- setOpenSettings(false);
- setShowSideBar(true);
- }}
- />
- ) : (
- <Chat
- key="chat"
- showSideBar={() => setShowSideBar(true)}
- sideBarShowing={showSideBar}
- autoSize={{ minRows: 2, maxRows: 6 }}
- />
- )}
- </div>
- </div>
- );
- }
- export function Home() {
- return (
- <ErrorBoundary>
- <_Home></_Home>
- </ErrorBoundary>
- );
- }
|