Commit a7da634c by Liu

feat:新建策略页面

parent 8a250ce8
import './App.css' import './App.css'
import React from 'react' import React from 'react'
import { BrowserRouter as Router } from 'react-router-dom' import { BrowserRouter as Router, useLocation } from 'react-router-dom'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
import { MainLayout } from './layouts' import { MainLayout, MainLayoutTactics } from './layouts'
import { AppRoutes } from './routes/AppRoutes' import { AppRoutes } from './routes/AppRoutes'
import { AuthProvider } from './auth/AuthContext' import { AuthProvider } from './auth/AuthContext'
import ToastWrapper from './components/ToastWrapper/ToastWrapper' import ToastWrapper from './components/ToastWrapper/ToastWrapper'
...@@ -11,15 +11,30 @@ import { store } from './store' ...@@ -11,15 +11,30 @@ import { store } from './store'
const viteOutputObj = import.meta.env.VITE_OUTPUT_OBJ || 'open' const viteOutputObj = import.meta.env.VITE_OUTPUT_OBJ || 'open'
const basename = viteOutputObj === 'inner' ? '/sdream-fe' : '/sdream-ai' const basename = viteOutputObj === 'inner' ? '/sdream-fe' : '/sdream-ai'
const LayoutSwitcher: React.FC = () => {
const location = useLocation()
const isFromTactics = new URLSearchParams(location.search).get('from') === 'tactics'
if (isFromTactics) {
return (
<MainLayoutTactics>
<AppRoutes />
</MainLayoutTactics>
)
}
return (
<MainLayout>
<AppRoutes />
</MainLayout>
)
}
const App: React.FC = () => { const App: React.FC = () => {
return ( return (
<Provider store={store}> <Provider store={store}>
<ToastWrapper> <ToastWrapper>
<AuthProvider> <AuthProvider>
<Router basename={basename}> <Router basename={basename}>
<MainLayout> <LayoutSwitcher />
<AppRoutes />
</MainLayout>
</Router> </Router>
</AuthProvider> </AuthProvider>
</ToastWrapper> </ToastWrapper>
......
import type React from 'react'
import { motion } from 'framer-motion'
import { useEffect, useState } from 'react'
import { useLocation } from 'react-router-dom'
import { useSessionStorageState } from 'ahooks'
import styles from './MainLayout.module.less'
import { useAuth } from '@/auth/AuthContext'
import { LoginModal } from '@/components/LoginModal'
import MingcuteArrowsRightFill from '@/assets/svg/MingcuteArrowsRightFill.svg?react'
import { isMobile } from '@/utils'
import { useAppDispatch } from '@/store/hook'
import { fetchConversations } from '@/store/conversationSlice'
interface MainLayoutTacticsProps {
children: React.ReactNode
}
const contentVariants = {
navTween: {
x: '-90px',
transition: { type: 'tween', duration: 0.3, ease: 'easeInOut' },
},
mainTween: {
x: '-60px',
transition: { type: 'tween', duration: 0.3, ease: 'easeInOut' },
},
expanded: {
width: '90px',
x: 0,
transition: { type: 'spring', stiffness: 300, damping: 30 },
},
shrunk: {
width: isMobile() ? '90px' : '340px',
x: 0,
transition: { type: 'spring', stiffness: 300, damping: 30 },
},
}
export const MainLayoutTactics: React.FC<MainLayoutTacticsProps> = ({ children }) => {
const { showLoginModal, toggleLoginModal } = useAuth()
const [isHistoryVisible, setHistoryVisible] = useState(false)
const location = useLocation()
const dispatch = useAppDispatch()
const [navBarVisibleLocal] = useSessionStorageState<string | undefined>(
'__NAV_BAR_VISIBLE_LOCAL__',
{
defaultValue: '0',
listenStorageChange: true,
},
)
useEffect(() => {
dispatch(fetchConversations())
}, [dispatch])
useEffect(() => {
if (location.pathname === '/tools' || location.pathname === '/collect') {
setHistoryVisible(false)
}
}, [location.pathname])
return (
<motion.main className={styles.layoutMain}>
<motion.div
animate={navBarVisibleLocal === '0' ? isHistoryVisible ? 'shrunk' : 'expanded' : 'navTween'}
variants={contentVariants}
className={`fixed right-[-12px] top-[10px] z-[49] h-auto sm:relative flex sm:h-full items-center ${isHistoryVisible && !isMobile() ? 'w-[340px]' : 'w-[90px]'} box-border`}
>
{!isHistoryVisible && (
<motion.div
initial="hidden"
animate="visible"
variants={{
hidden: {
x: -5,
opacity: 0,
},
}}
className={`${styles.sidebarArrow} side-bar-arrow h-[42px] flex items-center`}
>
<MingcuteArrowsRightFill className="text-[#818d91]" />
</motion.div>
)}
</motion.div>
<motion.div
variants={contentVariants}
animate={navBarVisibleLocal === '0' ? '' : 'mainTween'}
className={`${styles.layoutContent} px-[12px]`}
>
{children}
</motion.div>
<LoginModal isOpen={showLoginModal} onClose={toggleLoginModal} />
</motion.main>
)
}
export { MainLayout } from './MainLayout' export { MainLayout } from './MainLayout'
export { MainLayoutTactics } from './MainLayoutTactics'
import type React from 'react'
import { motion } from 'framer-motion'
import { useEffect, useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useClickAway, useSessionStorageState } from 'ahooks'
import styles from './Navbar.module.less'
import { NavBarItem } from './components/NavBarItem'
import { clearNavigationFlag, createConversation } from '@/store/conversationSlice'
import type { WithAuthProps } from '@/auth/withAuth'
import { withAuth } from '@/auth/withAuth'
import { NAV_BAR_ITEMS } from '@/config/nav'
import { useAppDispatch, useAppSelector } from '@/store/hook'
import { isMobile } from '@/utils'
interface NavbarProps {
isHistoryVisible: boolean
onSetHistoryVisible: (visible: boolean) => void
}
const NavbarFromBase: React.FC<NavbarProps & WithAuthProps> = ({ isHistoryVisible, checkAuth, onSetHistoryVisible }) => {
const dispatch = useAppDispatch()
const navigate = useNavigate()
const { currentConversationId, shouldNavigateToNewConversation, currentToolId } = useAppSelector(state => state.conversation)
const handleCreateConversation = () => {
dispatch(createConversation({
conversationData: {},
shouldNavigate: true,
shouldSendQuestion: '',
}))
}
const [isH5NavVisible, setIsH5NavVisible] = useState(isMobile())
const handleClick = (type: string | undefined) => {
if (type === 'logo') {
if (!isH5NavVisible) {
navigate('/')
setIsH5NavVisible(true)
}
else {
setIsH5NavVisible(!isH5NavVisible)
}
return
}
setIsH5NavVisible(true)
if (!checkAuth()) {
return
}
if (type === 'add') {
if (location.pathname.includes('/chat')) {
handleCreateConversation()
}
else {
navigate('/')
}
onSetHistoryVisible(false)
}
if (type === 'history') {
onSetHistoryVisible(!isHistoryVisible)
}
}
const [navBarVisibleLocal, setNavBarVisibleLocal] = useSessionStorageState<string | undefined>(
'__NAV_BAR_VISIBLE_LOCAL__',
{
defaultValue: '0',
listenStorageChange: true,
},
)
const toggleNavBarVisible = () => {
setNavBarVisibleLocal(navBarVisibleLocal === '1' ? '0' : '1')
}
useEffect(() => {
if (shouldNavigateToNewConversation && currentConversationId) {
const url = currentToolId
? `/chat/${currentConversationId}?toolId=${currentToolId}`
: `/chat/${currentConversationId}`
navigate(url, {
state: {
toolId: currentToolId || null,
},
})
dispatch(clearNavigationFlag())
}
}, [shouldNavigateToNewConversation, currentConversationId, currentToolId, navigate, dispatch])
useEffect(() => {
if (currentConversationId) {
sessionStorage.setItem('currentConversationId', currentConversationId)
}
}, [currentConversationId])
const navRef = useRef<HTMLButtonElement>(null)
useClickAway(() => {
setIsH5NavVisible(true)
}, navRef)
return (
<motion.nav
ref={navRef}
animate={navBarVisibleLocal === '0' ? 'hidden' : ''}
className="h-full flex-shrink-0 flex flex-col items-center justify-center relative"
>
<motion.div className={`layoutNavBarJoyride ${styles.layoutNavBarAgent} rounded-full ${isH5NavVisible ? 'h-[55px] bg-white/70 shadow-md' : 'h-[380px]'} w-[54px] overflow-hidden py-[8px] sm:w-[64px] sm:bg-white gap-[24px] sm:h-auto sm:rounded-3xl sm:flex sm:py-[24px] sm:px-[8px]`}>
{NAV_BAR_ITEMS.map((item) => {
return (
<NavBarItem isHistoryVisible={isHistoryVisible} onClick={handleClick} icon={item.icon} label={item.label} key={item.key} type={item.key} />
)
})}
</motion.div>
<div onClick={toggleNavBarVisible} className={`${styles.sidebarAction} ${navBarVisibleLocal === '0' ? styles.open : ''}`}></div>
</motion.nav>
)
}
export const NavbarFrom = withAuth(NavbarFromBase)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment