import React, { useEffect, useRef, useMemo, useState, Fragment } from "react"; import styles from "./home.module.scss"; import DragIcon from "../icons/drag.svg"; import faviconSrc from "../icons/favicon.png"; import deepSeekSrc from "../icons/deepSeek.png"; import { MenuOutlined, PlusOutlined } from '@ant-design/icons'; import { useAppConfig, useChatStore, useGlobalStore } from "../store"; import { DEFAULT_SIDEBAR_WIDTH, MAX_SIDEBAR_WIDTH, MIN_SIDEBAR_WIDTH, NARROW_SIDEBAR_WIDTH, } from "../constant"; import { useLocation, useNavigate } from "react-router-dom"; import { isIOS, useMobileScreen } from "../utils"; import { Button } from "antd"; 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 ? "60vw" : `${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 (
{title}
{subTitle}
{logo}
{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 }) => { const { onDragStart, shouldNarrow } = useDragSideBar(); const navigate = useNavigate(); const location = useLocation(); const chatStore = useChatStore(); const globalStore = useGlobalStore(); const isMobileScreen = useMobileScreen(); const getType = (): 'bigModel' | 'deepSeek' => { if (['/knowledgeChat', '/newChat'].includes(location.pathname)) { return 'bigModel'; } else if (['/deepseekChat', '/newDeepseekChat'].includes(location.pathname)) { return 'deepSeek'; } else { return 'bigModel'; } } const closeSidebar = () => { globalStore.setShowMenu(false); }; return ( <> { isMobileScreen && globalStore.showMenu && (
) } { (location.search.includes('showMenu=false') ? globalStore.showMenu : true) && { getType() === 'deepSeek' &&
} 建科•小智
: '' } logo={getType() === 'bigModel' ? null : ''} >
} ); }