Commit 1d055972 by HoMeTown

feat: 优化

parent 69e6c37f
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
"axios": "^1.7.3", "axios": "^1.7.3",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"github-markdown-css": "^5.8.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hot-toast": "^2.4.1", "react-hot-toast": "^2.4.1",
......
.markdown-body {
min-height: auto;
box-sizing: border-box;
margin: 0 auto;
font-family: 'alir';
ul {
list-style: circle;
}
}
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><path d="M24 0v24H0V0zM12.594 23.258l-.012.002l-.071.035l-.02.004l-.014-.004l-.071-.036c-.01-.003-.019 0-.024.006l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427c-.002-.01-.009-.017-.016-.018m.264-.113l-.014.002l-.184.093l-.01.01l-.003.011l.018.43l.005.012l.008.008l.201.092c.012.004.023 0 .029-.008l.004-.014l-.034-.614c-.003-.012-.01-.02-.02-.022m-.715.002a.023.023 0 0 0-.027.006l-.006.014l-.034.614c0 .012.007.02.017.024l.015-.002l.201-.093l.01-.008l.003-.011l.018-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M5.94 5.94a1.5 1.5 0 0 1 2.12 0l5 5a1.5 1.5 0 0 1 0 2.12l-5 5a1.5 1.5 0 0 1-2.12-2.12L9.878 12l-3.94-3.94a1.5 1.5 0 0 1 0-2.12Zm6 0a1.5 1.5 0 0 1 2.12 0l5 5a1.5 1.5 0 0 1 0 2.12l-5 5a1.5 1.5 0 0 1-2.12-2.12L15.878 12l-3.94-3.94a1.5 1.5 0 0 1 0-2.12Z"/></g></svg>
<svg class="animate-spotlight pointer-events-none absolute z-[1] h-[30%] w-[138%] lg:w-[154%] opacity-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3787 2842" fill="none"><g filter="url(#filter)"><ellipse cx="1924.71" cy="273.501" rx="1924.71" ry="273.501" transform="matrix(-0.822377 -0.568943 -0.568943 0.822377 3631.88 2291.09)" fill="white" fill-opacity="0.21"></ellipse></g><defs><filter id="filter" x="0.860352" y="0.838989" width="3785.16" height="2840.26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood><feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend><feGaussianBlur stdDeviation="151" result="effect1_foregroundBlur_1065_8"></feGaussianBlur></filter></defs></svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg width="36px" height="36px" viewBox="0 0 193 192" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>资源 7</title>
<defs>
<rect id="path-1" x="0" y="0" width="192" height="192"></rect>
<linearGradient x1="41.6050784%" y1="31.5359665%" x2="73.4960504%" y2="63.2152197%" id="linearGradient-3">
<stop stop-color="#29B6FD" stop-opacity="0.3" offset="0%"></stop>
<stop stop-color="#005DBC" offset="100%"></stop>
</linearGradient>
<linearGradient x1="73.5491818%" y1="83.5182119%" x2="18.3273687%" y2="30.720658%" id="linearGradient-4">
<stop stop-color="#29B6FD" stop-opacity="0.3" offset="0%"></stop>
<stop stop-color="#005DBC" offset="100%"></stop>
</linearGradient>
<linearGradient x1="37.1513273%" y1="81.8486603%" x2="62.3685523%" y2="23.4808241%" id="linearGradient-5">
<stop stop-color="#29B6FD" stop-opacity="0.3" offset="0%"></stop>
<stop stop-color="#005DBC" offset="100%"></stop>
</linearGradient>
</defs>
<g id="晓得---PC端页面-草稿" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="logo" transform="translate(-432.000000, -305.000000)">
<g id="资源-7" transform="translate(432.000000, 305.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="矩形"></g>
<path d="M132,44.1800204 L118.15,44.1000204 L117.81,44.1000204 C96.1903516,44.1164431 76.1945009,55.5752526 65.25,74.2200204 L56.25,59.7200204 C50.0055289,49.6472382 38.9913351,43.5252987 27.14,43.5399939 L0,43.5900204 L40.47,109.59002 L0,175.54002 L26.87,175.96002 C38.8706516,176.150694 50.0930004,170.036658 56.44,159.85002 L65.44,145.36002 L65.54,145.53002 C76.3573031,164.414876 96.4167048,176.106032 118.18,176.21002 L123.94,176.21002 L127.62,176.21002 L127.7,176.21002 C129.08,176.21002 130.46,176.10002 131.82,175.97002 C165.824112,172.959906 191.9,144.477104 191.9,110.34002 L191.9,104.04002 C191.877919,70.9737859 165.066242,44.180013 132,44.1800204 Z M154.63,126.24002 C152.06396,130.69544 148.492348,134.489636 144.2,137.32002 C140.046087,140.047729 135.334185,141.810848 130.41,142.48002 C120.251243,143.728091 110.200624,139.448473 104.06,131.26002 L87.74,109.90002 L97.39,93.1800204 C103.254594,82.8689566 114.19391,76.490213 126.05607,76.4646838 C137.91823,76.4393075 148.884819,82.7710474 154.793608,93.056849 C160.702396,103.34265 160.647594,116.005746 154.65,126.24002 L154.63,126.24002 Z" id="形状" fill="#29B6FD" fill-rule="nonzero" mask="url(#mask-2)"></path>
<polygon id="路径" fill="url(#linearGradient-3)" fill-rule="nonzero" mask="url(#mask-2)" points="65.25 74.2200204 40.47 109.60002 21.77 79.1000204 55.63 58.7400204"></polygon>
<path d="M87.74,109.90002 L65.44,145.26002 C65.44,145.26002 68.25,151.15002 75.44,158.31002 C83.5753872,166.359801 93.7664229,172.019181 104.9,174.67002 L126.9,142.72002 C126.9,142.72002 114.49,144.13002 104.08,131.26002 C93.67,118.39002 87.74,109.90002 87.74,109.90002 Z" id="路径" fill="url(#linearGradient-4)" fill-rule="nonzero" mask="url(#mask-2)"></path>
<path d="M148.16,134.26002 C148.16,134.26002 166.67,118.19002 155.86,95.7600204 C146.06,75.4400204 126.86,76.6400204 126.86,76.6400204 L131.78,76.6400204 C161.51,76.6400204 192.03,92.9400204 192.03,110.38002 C191.944262,118.553656 190.379005,126.644203 187.41,134.26002 L148.16,134.26002 Z" id="路径" fill="url(#linearGradient-5)" fill-rule="nonzero" mask="url(#mask-2)"></path>
<path d="M192.21,66.5700204 C183.7,53.0000204 170.49,42.7800204 159.08,41.6500204 L159.08,26.2400204 C159.085513,20.5869095 163.666889,16.0055329 169.32,16 L181.77,16 C187.393278,15.9889081 191.966965,20.5268283 192,26.1500204" id="路径" fill="#FFAE00" fill-rule="nonzero" mask="url(#mask-2)"></path>
</g>
</g>
</g>
</svg>
...@@ -5,8 +5,22 @@ ...@@ -5,8 +5,22 @@
right: 0; right: 0;
height: 100vh; height: 100vh;
// background: linear-gradient( 180deg, #FFFFFF 0%, #E6F6FE 100%), radial-gradient( 159% 92% at -4% -5%, rgba(182,180,255,0.8) 0%, rgba(193,227,255,0) 100%), radial-gradient( 107% 70% at 103% -14%, rgba(205,232,255,0.8) 0%, rgba(193,227,255,0) 100%); // background: linear-gradient( 180deg, #FFFFFF 0%, #E6F6FE 100%), radial-gradient( 159% 92% at -4% -5%, rgba(182,180,255,0.8) 0%, rgba(193,227,255,0) 100%), radial-gradient( 107% 70% at 103% -14%, rgba(205,232,255,0.8) 0%, rgba(193,227,255,0) 100%);
z-index: -1; // z-index: -1;
img { // img {
width: 100%; // width: 100%;
// }
.animate-spotlight {
animation: spotlight 3s ease .75s 1 forwards;
}
@keyframes spotlight {
0% {
opacity: 0;
transform: translate(-72%, -62%) scale(.5);
}
100% {
opacity: 1;
transform: translate(-50%, -40%) scale(1);
}
} }
} }
// This file is automatically generated. // This file is automatically generated.
// Please do not change this file! // Please do not change this file!
interface CssExports { interface CssExports {
gradientBackground: string 'animate-spotlight': string
'animateSpotlight': string
'gradientBackground': string
'spotlight': string
} }
declare const cssExports: CssExports declare const cssExports: CssExports
export default cssExports export default cssExports
import React from 'react' import React from 'react'
import { motion } from 'framer-motion' import { motion } from 'framer-motion'
import styles from './GradientBackground.module.less' import styles from './GradientBackground.module.less'
import Bg from '@/assets/bg.png'
export const GradientBackground: React.FC = () => { export const GradientBackground: React.FC = () => {
return ( return (
<motion.div <motion.div
className={styles.gradientBackground} className={`${styles.gradientBackground} hidden sm:block`}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 2, ease: 'easeOut' }}
> >
<motion.img src={Bg} alt="" /> {/* <motion.img src={Bg} alt="" /> */}
<svg className={`${styles.animateSpotlight} pointer-events-none absolute left top-0 z-[1] h-[100%] w-[128%] opacity-0`} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2787 2842" fill="none">
<g filter="url(#filter)"><ellipse cx="2524.71" cy="3.501" rx="1224.71" ry="803.501" transform="matrix(-0.822377 -0.568943 -0.568943 1.22377 3631.88 2391.09)" fill="#B6B4FF" fill-opacity="0.21"></ellipse></g>
<defs>
<filter id="filter" x="0.860352" y="0.838989" width="3785.16" height="2840.26" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend>
<feGaussianBlur stdDeviation="151" result="effect1_foregroundBlur_1065_8"></feGaussianBlur>
</filter>
</defs>
</svg>
</motion.div> </motion.div>
) )
} }
...@@ -14,7 +14,7 @@ export const MarkdownDetail: React.FC<MarkdownDetailProps> = ({ children }) => { ...@@ -14,7 +14,7 @@ export const MarkdownDetail: React.FC<MarkdownDetailProps> = ({ children }) => {
<ReactMarkdown <ReactMarkdown
rehypePlugins={[rehypeRaw, rehypeSanitize]} rehypePlugins={[rehypeRaw, rehypeSanitize]}
remarkPlugins={[remarkGfm]} remarkPlugins={[remarkGfm]}
className="flex flex-col gap-[12px] text-[#27353C] text-[15px]" className="markdown-body flex flex-col gap-[12px] text-[#27353C] text-[15px]"
components={{ components={{
img: ({ ...data }): JSX.Element => ( img: ({ ...data }): JSX.Element => (
<PhotoProvider maskOpacity={0.1} bannerVisible={false}> <PhotoProvider maskOpacity={0.1} bannerVisible={false}>
...@@ -23,15 +23,15 @@ export const MarkdownDetail: React.FC<MarkdownDetailProps> = ({ children }) => { ...@@ -23,15 +23,15 @@ export const MarkdownDetail: React.FC<MarkdownDetailProps> = ({ children }) => {
</PhotoView> </PhotoView>
</PhotoProvider> </PhotoProvider>
), ),
p(data): JSX.Element { // p(data): JSX.Element {
return <p className="leading-[24px] break-words w-full" {...data} /> // return <p className="leading-[24px] break-words w-full" {...data} />
}, // },
ul(data): JSX.Element { // ul(data): JSX.Element {
return <ul className="mb-[24px]" {...data} /> // return <ul className="mb-[24px]" {...data} />
}, // },
strong(data): JSX.Element { // strong(data): JSX.Element {
return <strong className="text-[#27353C]" {...data} /> // return <strong className="text-[#27353C]" {...data} />
}, // },
}} }}
> >
{children as string} {children as string}
......
'use client'
import { motion, stagger, useAnimate, useInView } from 'framer-motion'
import { useEffect } from 'react'
import { cn } from '@/lib/utils'
interface TypewriterEffectProps {
words: {
text: string
className?: string
}[]
className?: string
cursorClassName?: string
}
export default function TypewriterEffect({
words,
className,
cursorClassName,
}: TypewriterEffectProps) {
// split text inside of words into array of characters
const wordsArray = words.map((word) => {
return {
...word,
text: word.text.split(''),
}
})
const [scope, animate] = useAnimate()
const isInView = useInView(scope)
useEffect(() => {
if (isInView) {
animate(
'span',
{
display: 'inline-block',
opacity: 1,
width: 'fit-content',
},
{
duration: 0.3,
delay: stagger(0.1),
ease: 'easeInOut',
},
)
}
}, [isInView])
const renderWords = () => {
return (
<motion.div ref={scope} className="inline">
{wordsArray.map((word, idx) => {
return (
<div key={`word-${idx}`} className="inline-block">
{word.text.map((char, index) => (
<motion.span
initial={{}}
key={`char-${index}`}
className={cn(
`dark:text-white text-black opacity-0 hidden`,
className,
word.className,
)}
>
{char}
</motion.span>
))}
&nbsp;
</div>
)
})}
</motion.div>
)
}
return (
<div
className={cn(
'text-base sm:text-xl md:text-3xl lg:text-5xl font-bold text-center',
className,
)}
>
{renderWords()}
<motion.span
initial={{
opacity: 0,
}}
animate={{
opacity: 1,
}}
transition={{
duration: 0.8,
repeat: Infinity,
repeatType: 'reverse',
}}
className={cn(
'inline-block rounded-sm w-[4px] h-4 md:h-6 lg:h-10 bg-blue-500',
cursorClassName,
)}
>
</motion.span>
</div>
)
}
import Tools from '@/assets/svg/tools.svg?react' import Tools from '@/assets/svg/tools.svg?react'
import Logo from '@/assets/svg/logo.svg?react'
import AddNewChat from '@/assets/svg/addNewChat.svg?react' import AddNewChat from '@/assets/svg/addNewChat.svg?react'
import HistoryChat from '@/assets/svg/historyChat.svg?react' import HistoryChat from '@/assets/svg/historyChat.svg?react'
import Collect from '@/assets/svg/collect.svg?react' import Collect from '@/assets/svg/collect.svg?react'
export const NAV_BAR_ITEMS = [ export const NAV_BAR_ITEMS = [
{ icon: Logo, label: '', key: 'logo' }, // { icon: Logo, label: '', key: 'logo' },
{ icon: '', label: '', key: 'line1' }, { icon: '', label: '', key: 'line1' },
{ icon: AddNewChat, label: '新建对话', key: 'add' }, { icon: AddNewChat, label: '新建对话', key: 'add' },
{ icon: HistoryChat, label: '历史对话', key: 'history' }, { icon: HistoryChat, label: '历史对话', key: 'history' },
......
...@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom/client' ...@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom/client'
import { NextUIProvider } from '@nextui-org/react' import { NextUIProvider } from '@nextui-org/react'
import App from './App' import App from './App'
import './styles/index.less' import './styles/index.less'
import 'github-markdown-css/github-markdown.css'
import 'react-photo-view/dist/react-photo-view.css' import 'react-photo-view/dist/react-photo-view.css'
import { printText2Console } from './utils/console' import { printText2Console } from './utils/console'
......
...@@ -10,3 +10,28 @@ ...@@ -10,3 +10,28 @@
box-sizing: border-box; box-sizing: border-box;
padding: 0 12px; padding: 0 12px;
} }
.sidebarArrow {
background-color: #fff;
border-radius: 0 12px 12px 0;
position: relative;
&::before {
content: "";
position: absolute;
width: 10px;
height: 10px;
bottom: -10px;
background: #000;
background:radial-gradient(circle at 0 0, transparent 10px, #fff 10px);
transform: rotate(180deg);
}
&::after {
content: "";
position: absolute;
width: 10px;
height: 10px;
top: -10px;
background: #000;
background:radial-gradient(circle at 0 0, transparent 10px, #fff 10px);
transform: rotate(90deg);
}
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
interface CssExports { interface CssExports {
layoutContent: string layoutContent: string
layoutMain: string layoutMain: string
sidebarArrow: string
} }
declare const cssExports: CssExports declare const cssExports: CssExports
export default cssExports export default cssExports
...@@ -9,6 +9,7 @@ import { useAuth } from '@/auth/AuthContext' ...@@ -9,6 +9,7 @@ import { useAuth } from '@/auth/AuthContext'
import { LoginModal } from '@/components/LoginModal' import { LoginModal } from '@/components/LoginModal'
import { useAppDispatch } from '@/store/hook' import { useAppDispatch } from '@/store/hook'
import { fetchConversations } from '@/store/conversationSlice' import { fetchConversations } from '@/store/conversationSlice'
import MingcuteArrowsRightFill from '@/assets/svg/MingcuteArrowsRightFill.svg?react'
interface MainLayoutProps { interface MainLayoutProps {
children: React.ReactNode children: React.ReactNode
...@@ -46,13 +47,29 @@ export const MainLayout: React.FC<MainLayoutProps> = ({ children }) => { ...@@ -46,13 +47,29 @@ export const MainLayout: React.FC<MainLayoutProps> = ({ children }) => {
return ( return (
<motion.main className={styles.layoutMain}> <motion.main className={styles.layoutMain}>
{/* hidden */}
<motion.div <motion.div
animate={isHistoryVisible ? 'shrunk' : 'expanded'} animate={isHistoryVisible ? 'shrunk' : 'expanded'}
variants={contentVariants} variants={contentVariants}
className={`hidden sm:flex h-full pl-[12px] items-center ${isHistoryVisible ? 'w-[340px]' : 'w-[90px]'}`} className={`fixed right-[2px] top-[22px] z-[10] h-auto sm:relative flex sm:h-full pl-[12px] items-center ${isHistoryVisible ? 'w-[340px]' : 'w-[90px]'} box-border`}
> >
<Navbar isHistoryVisible={isHistoryVisible} onSetHistoryVisible={setHistoryVisible} /> <Navbar isHistoryVisible={isHistoryVisible} onSetHistoryVisible={setHistoryVisible} />
<HistoryBar isVisible={isHistoryVisible} /> <HistoryBar isVisible={isHistoryVisible} />
{!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>
<motion.div <motion.div
className={`${styles.layoutContent}`} className={`${styles.layoutContent}`}
......
.layoutNavBarAgent { .layoutNavBarAgent {
width: 64px; width: 64px;
background: #FFFFFF; background: #FFFFFF;
border-radius: var(--sdream-radius-large);
box-sizing: border-box; box-sizing: border-box;
padding: 24px 8px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
transition: all 0.3s ease-in-out;
} }
import type React from 'react' import type React from 'react'
import { motion } from 'framer-motion' import { motion } from 'framer-motion'
import { useEffect } from 'react' import { useEffect, useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useClickAway } from 'ahooks'
import styles from './Navbar.module.less' import styles from './Navbar.module.less'
import { NavBarItem } from './components/NavBarItem' import { NavBarItem } from './components/NavBarItem'
import { User } from './components/User' import { User } from './components/User'
...@@ -10,6 +11,8 @@ import type { WithAuthProps } from '@/auth/withAuth' ...@@ -10,6 +11,8 @@ import type { WithAuthProps } from '@/auth/withAuth'
import { withAuth } from '@/auth/withAuth' import { withAuth } from '@/auth/withAuth'
import { NAV_BAR_ITEMS } from '@/config/nav' import { NAV_BAR_ITEMS } from '@/config/nav'
import { useAppDispatch, useAppSelector } from '@/store/hook' import { useAppDispatch, useAppSelector } from '@/store/hook'
import Logo from '@/assets/svg/logo.svg?react'
import { isMobile } from '@/utils'
interface NavbarProps { interface NavbarProps {
isHistoryVisible: boolean isHistoryVisible: boolean
...@@ -30,9 +33,23 @@ const NavbarBase: React.FC<NavbarProps & WithAuthProps> = ({ isHistoryVisible, c ...@@ -30,9 +33,23 @@ const NavbarBase: React.FC<NavbarProps & WithAuthProps> = ({ isHistoryVisible, c
})) }))
} }
const [isH5NavVisible, setIsH5NavVisible] = useState(isMobile())
const handleClick = (type: string | undefined) => { const handleClick = (type: string | undefined) => {
if (!checkAuth()) if (type === 'logo') {
if (!isH5NavVisible) {
navigate('/')
setIsH5NavVisible(true)
}
else {
setIsH5NavVisible(!isH5NavVisible)
}
return return
}
setIsH5NavVisible(true)
if (!checkAuth()) {
return
}
if (type === 'add') { if (type === 'add') {
handleCreateConversation() handleCreateConversation()
...@@ -62,9 +79,17 @@ const NavbarBase: React.FC<NavbarProps & WithAuthProps> = ({ isHistoryVisible, c ...@@ -62,9 +79,17 @@ const NavbarBase: React.FC<NavbarProps & WithAuthProps> = ({ isHistoryVisible, c
} }
}, [shouldNavigateToNewConversation, currentConversationId, navigate, dispatch]) }, [shouldNavigateToNewConversation, currentConversationId, navigate, dispatch])
const navRef = useRef<HTMLButtonElement>(null)
useClickAway(() => {
setIsH5NavVisible(true)
}, navRef)
return ( return (
<motion.nav className="h-full flex-shrink-0 flex flex-col items-center justify-center"> <motion.nav ref={navRef} className="h-full flex-shrink-0 flex flex-col items-center justify-center">
<motion.div className={`${styles.layoutNavBarAgent} sm:flex hidden w-[64px] bg-white gap-[24px]`}> {/* hidden */}
<motion.div className={`${styles.layoutNavBarAgent} rounded-full ${isH5NavVisible ? 'h-[55px] bg-white/20' : '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]`}>
<NavBarItem isHistoryVisible={isHistoryVisible} onClick={handleClick} icon={Logo} label="" key="logo" type={isMobile() ? 'logo3' : 'logo'} />
{NAV_BAR_ITEMS.map((item) => { {NAV_BAR_ITEMS.map((item) => {
return ( return (
<NavBarItem isHistoryVisible={isHistoryVisible} onClick={handleClick} icon={item.icon} label={item.label} key={item.key} type={item.key} /> <NavBarItem isHistoryVisible={isHistoryVisible} onClick={handleClick} icon={item.icon} label={item.label} key={item.key} type={item.key} />
......
...@@ -5,6 +5,8 @@ import { useLocation, useNavigate } from 'react-router-dom' ...@@ -5,6 +5,8 @@ import { useLocation, useNavigate } from 'react-router-dom'
import { NavBarDivider } from '../NavBarDivider' import { NavBarDivider } from '../NavBarDivider'
import styles from './NavBarItem.module.less' import styles from './NavBarItem.module.less'
import Logo from '@/assets/svg/logo.svg?react' import Logo from '@/assets/svg/logo.svg?react'
import Logo3 from '@/assets/svg/logo3.svg?react'
import { isMobile } from '@/utils'
interface NavBarItemProps { interface NavBarItemProps {
onClick: (key: string) => void onClick: (key: string) => void
...@@ -18,8 +20,13 @@ export const NavBarItem: React.FC<NavBarItemProps> = ({ isHistoryVisible, onClic ...@@ -18,8 +20,13 @@ export const NavBarItem: React.FC<NavBarItemProps> = ({ isHistoryVisible, onClic
const location = useLocation() const location = useLocation()
const handleClickLogo = () => { const handleClickLogo = () => {
if (isMobile()) {
onClick('logo')
}
else {
navigate('/') navigate('/')
} }
}
if (label === '' && icon === '') { if (label === '' && icon === '') {
return <NavBarDivider /> return <NavBarDivider />
} }
...@@ -31,7 +38,8 @@ export const NavBarItem: React.FC<NavBarItemProps> = ({ isHistoryVisible, onClic ...@@ -31,7 +38,8 @@ export const NavBarItem: React.FC<NavBarItemProps> = ({ isHistoryVisible, onClic
className="nav-logo cursor-pointer" className="nav-logo cursor-pointer"
onClick={handleClickLogo} onClick={handleClickLogo}
> >
<Logo /> {type === 'logo' && <Logo />}
{type === 'logo3' && <Logo3 />}
</motion.div> </motion.div>
) )
} }
......
...@@ -3,6 +3,7 @@ import { withAuth } from '@/auth/withAuth' ...@@ -3,6 +3,7 @@ import { withAuth } from '@/auth/withAuth'
import type { WithAuthProps } from '@/auth/withAuth' import type { WithAuthProps } from '@/auth/withAuth'
import UserIcon from '@/assets/svg/user.svg?react' import UserIcon from '@/assets/svg/user.svg?react'
import { useAuth } from '@/auth/AuthContext' import { useAuth } from '@/auth/AuthContext'
import { isMobile } from '@/utils'
interface UserProps { interface UserProps {
onLogout: () => void onLogout: () => void
...@@ -56,7 +57,7 @@ export const UserLogin: React.FC<UserProps> = ({ onLogout }) => { ...@@ -56,7 +57,7 @@ export const UserLogin: React.FC<UserProps> = ({ onLogout }) => {
const UserNotLoginBase: React.FC<WithAuthProps> = ({ showLoginTip, checkAuth }) => { const UserNotLoginBase: React.FC<WithAuthProps> = ({ showLoginTip, checkAuth }) => {
return ( return (
<Tooltip isOpen={showLoginTip} color="foreground" content="登录体验更多功能" placement="right"> <Tooltip isOpen={showLoginTip && !isMobile()} color="foreground" content="登录体验更多功能" placement="right">
<Button onClick={checkAuth} variant="light" isIconOnly aria-label="Like"> <Button onClick={checkAuth} variant="light" isIconOnly aria-label="Like">
<UserIcon /> <UserIcon />
</Button> </Button>
......
.chatPage { .scrollView {
// display: flex;
// flex-direction: column;
// flex: 1 1;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.scrollView {
// display: flex; .chatPage {
// flex-direction: column;
// flex: 1 1;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.content { .content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
......
...@@ -156,7 +156,7 @@ export const Chat: React.FC = () => { ...@@ -156,7 +156,7 @@ export const Chat: React.FC = () => {
> >
<div className={styles.inter}> <div className={styles.inter}>
{allItems.map((record, index) => ( {allItems.map((record, index) => (
<div className="w-full chatItem max-w-[1000px] mx-auto" key={index}> <div className="w-full chatItem max-w-[912px] mx-auto" key={index}>
{record.role === 'system' && <ChatWelcome />} {record.role === 'system' && <ChatWelcome />}
{record.role === 'user' && <ChatItemUser record={record} />} {record.role === 'user' && <ChatItemUser record={record} />}
{record.role === 'ai' && <ChatAnswerBox onSubmitQuestion={handleSubmitQuestion} isLastAnswer={index === allItems.length - 1} showIndex={0} record={record} index={index} />} {record.role === 'ai' && <ChatAnswerBox onSubmitQuestion={handleSubmitQuestion} isLastAnswer={index === allItems.length - 1} showIndex={0} record={record} index={index} />}
...@@ -166,7 +166,7 @@ export const Chat: React.FC = () => { ...@@ -166,7 +166,7 @@ export const Chat: React.FC = () => {
</motion.div> </motion.div>
)} )}
</div> </div>
<div className="relative box-border px-[0] mx-auto iptContainer w-full max-w-[1000px] flex-shrink-0 sm:px-0 pb-[18px]"> <div className="relative box-border px-[0] mx-auto iptContainer w-full max-w-[912px] flex-shrink-0 sm:px-0 pb-[18px]">
<div className="absolute left-1/2 ml-[-20px] top-[-65px]"> <div className="absolute left-1/2 ml-[-20px] top-[-65px]">
<motion.div <motion.div
initial="hidden" initial="hidden"
...@@ -184,7 +184,7 @@ export const Chat: React.FC = () => { ...@@ -184,7 +184,7 @@ export const Chat: React.FC = () => {
</div> </div>
<ChatEditor onSubmit={handleSubmitQuestion} placeholders={RECOMMEND_QUESTIONS_OTHER} /> <ChatEditor onSubmit={handleSubmitQuestion} placeholders={RECOMMEND_QUESTIONS_OTHER} />
<div className="w-full text-center mt-[20px] text-[#3333334d] text-[12px]"> <div className="w-full text-center mt-[12px] text-[#3333334d] text-[12px]">
内容由AI模型生成,其准确性和完整性无法保证,仅供参考 内容由AI模型生成,其准确性和完整性无法保证,仅供参考
</div> </div>
</div> </div>
......
...@@ -54,7 +54,7 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex, ...@@ -54,7 +54,7 @@ export const ChatAnswerBox: React.FC<ChatAnswerBoxProps> = ({ record, showIndex,
<div className="flex"> <div className="flex">
<Avatar className="flex-shrink-0" src={AvatarBot} /> <Avatar className="flex-shrink-0" src={AvatarBot} />
<motion.div <motion.div
className="ml-[20px] bg-white rounded-[20px] box-border px-[24px] py-[20px]" className="ml-[20px] bg-white rounded-[20px] box-border px-[16px] py-[12px] sm:px-[24px] sm:py-[20px]"
> >
{(item.answer?.length || item.attachmentList?.length) {(item.answer?.length || item.attachmentList?.length)
? ( ? (
......
...@@ -95,7 +95,7 @@ export const ChatAnswerOperate: React.FC<ChatAnswerOperateProps> = ({ answer }) ...@@ -95,7 +95,7 @@ export const ChatAnswerOperate: React.FC<ChatAnswerOperateProps> = ({ answer })
} }
} }
return ( return (
<div className="mt-[12px] flex gap-[4px] justify-end"> <div className="sm:mt-[12px] flex gap-[4px] justify-end">
{/* 点赞 */} {/* 点赞 */}
<Tooltip color="foreground" content={isLike ? '取消点赞' : '点赞'} className="capitalize"> <Tooltip color="foreground" content={isLike ? '取消点赞' : '点赞'} className="capitalize">
<Button variant="light" isIconOnly aria-label="LikeIcon" onClick={handleLike.run}> <Button variant="light" isIconOnly aria-label="LikeIcon" onClick={handleLike.run}>
......
...@@ -10,7 +10,7 @@ export const ChatItemUser: React.FC<ChatItemUserProps> = ({ record }) => { ...@@ -10,7 +10,7 @@ export const ChatItemUser: React.FC<ChatItemUserProps> = ({ record }) => {
return ( return (
<div className="chatItemUser"> <div className="chatItemUser">
<div className="flex justify-end"> <div className="flex justify-end">
<div className="mr-[20px] bg-[#29B6FD] rounded-[20px] box-border px-[18px] py-[18px] text-[#fff]">{record.question}</div> <div className="mr-[20px] bg-[#29B6FD] rounded-[20px] box-border text-[#fff] px-[16px] py-[12px] sm:px-[24px] sm:py-[20px]">{record.question}</div>
<Avatar className="flex-shrink-0" src={AvatarUser} /> <Avatar className="flex-shrink-0" src={AvatarUser} />
</div> </div>
<div className="h-[32px] w-full"></div> <div className="h-[32px] w-full"></div>
......
...@@ -6,7 +6,7 @@ export const ChatSlogan: React.FC = () => { ...@@ -6,7 +6,7 @@ export const ChatSlogan: React.FC = () => {
const navigate = useNavigate() const navigate = useNavigate()
return ( return (
<div className="w-full"> <div className="w-full">
<div className="max-w-[1000px] mx-auto h-[112px] flex flex-col justify-center"> <div className="max-w-[912px] mx-auto h-[112px] flex flex-col justify-center">
<div className="flex items-center cursor-pointer" onClick={() => navigate('/')}> <div className="flex items-center cursor-pointer" onClick={() => navigate('/')}>
<TextLogo className="w-[70px]" /> <TextLogo className="w-[70px]" />
<GradualSpacing text="晓得解惑,让沟通更智能" className="ml-[8px] text-[16px] text-[#333] font-medium" /> <GradualSpacing text="晓得解惑,让沟通更智能" className="ml-[8px] text-[16px] text-[#333] font-medium" />
......
...@@ -9,11 +9,11 @@ export const ChatWelcome: React.FC = () => { ...@@ -9,11 +9,11 @@ export const ChatWelcome: React.FC = () => {
<div className="flex"> <div className="flex">
<Avatar className="flex-shrink-0" src={AvatarBot} /> <Avatar className="flex-shrink-0" src={AvatarBot} />
<motion.div <motion.div
className="ml-[20px] bg-white rounded-[20px] box-border px-[24px] py-[20px]" className="ml-[20px] bg-white rounded-[20px] box-border px-[16px] py-[12px] sm:px-[24px] sm:py-[20px]"
> >
<div className="content"> <div className="content">
<p className="text-[18px] font-medium text-[#333]">您好,我是晓得</p> <p className="text-[16px] sm:text-[18px] font-medium text-[#333]">您好,我是晓得</p>
<p className="mt-[8px] text-13px text-[#27353C] font-300">做为您的智能保险伙伴,您有各类专业相关的问题都可以抛给我哟~让我们互相帮助共同成长吧~</p> <p className="text-[14px] mt-[8px] sm:text-13px text-[#27353C] font-300">做为您的智能保险伙伴,您有各类专业相关的问题都可以抛给我哟~让我们互相帮助共同成长吧~</p>
</div> </div>
</motion.div> </motion.div>
</div> </div>
......
...@@ -36,9 +36,14 @@ export const Collect: React.FC = () => { ...@@ -36,9 +36,14 @@ export const Collect: React.FC = () => {
pageSize, pageSize,
} }
const res = await fetchQueryCollectionList(params) const res = await fetchQueryCollectionList(params)
let timer = null as any
timer = setTimeout(() => {
setCollectList([...collectList, ...res.data.records]) setCollectList([...collectList, ...res.data.records])
setTotal(res.data.total) setTotal(res.data.total)
setIsLoading(false) setIsLoading(false)
clearTimeout(timer)
timer = null
}, 500)
} }
const handleCopy = async (item: Answer) => { const handleCopy = async (item: Answer) => {
...@@ -111,7 +116,7 @@ export const Collect: React.FC = () => { ...@@ -111,7 +116,7 @@ export const Collect: React.FC = () => {
<ShineBorder <ShineBorder
borderRadius={20} borderRadius={20}
className="text-[#27353C] w-full max-w-[1000px] mx-auto bg-white rounded-[20px] box-border px-[24px] py-[20px]" className="text-[#27353C] w-full max-w-[912px] mx-auto bg-white rounded-[20px] box-border px-[24px] py-[20px]"
key={`${item.collectionId}_${index}`} key={`${item.collectionId}_${index}`}
> >
<div className="flex mb-[20px]"> <div className="flex mb-[20px]">
...@@ -159,7 +164,7 @@ export const Collect: React.FC = () => { ...@@ -159,7 +164,7 @@ export const Collect: React.FC = () => {
{isLoading && <div className="w-full flex justify-center items-center"><SdreamLoading /></div>} {isLoading && <div className="w-full flex justify-center items-center"><SdreamLoading /></div>}
{ {
!isLoading && collectList.length < total && ( !isLoading && collectList.length < total && (
<div className="w-full max-w-[1000px] mx-auto flex justify-center mt-[24px]"> <div className="w-full max-w-[912px] mx-auto flex justify-center mt-[24px]">
<Button onClick={handleLoadMore} color="primary" variant="light"> <Button onClick={handleLoadMore} color="primary" variant="light">
加载更多 加载更多
</Button> </Button>
...@@ -168,7 +173,7 @@ export const Collect: React.FC = () => { ...@@ -168,7 +173,7 @@ export const Collect: React.FC = () => {
} }
{ {
collectList.length === total && collectList.length !== 0 && ( collectList.length === total && collectList.length !== 0 && (
<div className="w-full mt-[24px] max-w-[1000px] mx-auto flex justify-center text-[#8D9795]">到底啦~</div> <div className="w-full mt-[24px] max-w-[912px] mx-auto flex justify-center text-[#8D9795]">到底啦~</div>
) )
} }
</div> </div>
......
...@@ -78,9 +78,9 @@ export const Home: React.FC = () => { ...@@ -78,9 +78,9 @@ export const Home: React.FC = () => {
)} */} )} */}
{/* /> */} {/* /> */}
</div> </div>
<div className="box-border px-[0] mx-auto iptContainer w-full max-w-[1000px] flex-shrink-0 sm:px-0 pb-[18px]"> <div className="box-border px-[0] mx-auto iptContainer w-full max-w-[912px] flex-shrink-0 sm:px-0 pb-[18px]">
<ChatEditor onSubmit={handleCreateConversation} placeholders={RECOMMEND_QUESTIONS_OTHER} /> <ChatEditor onSubmit={handleCreateConversation} placeholders={RECOMMEND_QUESTIONS_OTHER} />
<div className="w-full text-center mt-[20px] text-[#3333334d] text-[12px]"> <div className="w-full text-center mt-[12px] text-[#3333334d] text-[12px]">
内容由AI模型生成,其准确性和完整性无法保证,仅供参考 内容由AI模型生成,其准确性和完整性无法保证,仅供参考
</div> </div>
</div> </div>
......
import type React from 'react' import type React from 'react'
import TextLogo from '@/assets/svg/textLogo.svg?react' import TextLogo from '@/assets/svg/textLogo.svg?react'
import { GradientsBall } from '@/components/GradientsBall/GradientsBall' import { GradientsBall } from '@/components/GradientsBall/GradientsBall'
import TypewriterEFfect from '@/components/TypewriterEffect'
export const Slogan: React.FC = () => { export const Slogan: React.FC = () => {
const words = [
{
text: '晓得解惑,让沟通',
},
{
text: '更智能',
className: 'text-[#29B6FD]',
},
]
return ( return (
<div className="flex flex-col items-center box-border"> <div className="flex flex-col items-center box-border">
<GradientsBall /> <GradientsBall />
<TextLogo className="w-[80px] sm:w-auto" /> <TextLogo className="w-[80px] sm:w-auto" />
{/* <GradualSpacing text="晓得解惑,让沟通更智能" className="mt-[36px] text-[#333] text-[28px] font-medium" /> */} {/* <GradualSpacing text="晓得解惑,让沟通更智能" className="mt-[20px] text-[18px] sm:mt-[36px] text-[#333] sm:text-[28px] font-medium" /> */}
<h2 className="mt-[20px] text-[18px] sm:mt-[36px] text-[#333] sm:text-[28px] font-medium">晓得解惑,让沟通更智能</h2> <TypewriterEFfect cursorClassName="!h-[14px] !w-[2px] sm:!w-[4px] sm:!h-[22px] !bg-[#29B6FD]/40" className="mt-[8px] text-[18px] sm:mt-[12px] text-[#333] sm:text-[28px] font-medium" words={words} />
{/* <h2 className="mt-[20px] text-[18px] sm:mt-[36px] text-[#333] sm:text-[28px] font-medium">晓得解惑,让沟通更智能</h2> */}
<h3 className="mt-[8px] text-[14px] text-center sm:text-[18px] text-[#5AA9D0] font-light sm:mt-[16px]">知晓市场脉搏,引领行业潮流,晓得AI助手全方位为您保驾护航</h3> <h3 className="mt-[8px] text-[14px] text-center sm:text-[18px] text-[#5AA9D0] font-light sm:mt-[16px]">知晓市场脉搏,引领行业潮流,晓得AI助手全方位为您保驾护航</h3>
</div> </div>
) )
......
...@@ -60,8 +60,8 @@ export const Tools: React.FC = () => { ...@@ -60,8 +60,8 @@ export const Tools: React.FC = () => {
<div className="px-[24px] pb-[24px] pt-[42px] sm:pt-[80px] lg:pt-[180px] sm:px-0"> <div className="px-[24px] pb-[24px] pt-[42px] sm:pt-[80px] lg:pt-[180px] sm:px-0">
<Slogan /> <Slogan />
<div> <div>
<div className="max-w-[1000px] flex mx-auto mt-[64px] text-18px text-[#5AA9D0] font-light">全部工具</div> <div className="max-w-[912px] flex mx-auto mt-[64px] text-18px text-[#5AA9D0] font-light">全部工具</div>
<div className="max-w-[1000px] mx-auto gap-[20px] flex flex-col flex-wrap mt-[22px] sm:flex-row"> <div className="max-w-[912px] mx-auto gap-[20px] flex flex-col flex-wrap mt-[22px] sm:flex-row">
{tools.map((item, index) => ( {tools.map((item, index) => (
<motion.div className="flex-1" key={index} onClick={handleClickToolItem} {...getAnimationProps(index + 1)}> <motion.div className="flex-1" key={index} onClick={handleClickToolItem} {...getAnimationProps(index + 1)}>
<ShineBorder <ShineBorder
......
...@@ -24,9 +24,11 @@ body { ...@@ -24,9 +24,11 @@ body {
min-width: 375px; min-width: 375px;
font-family: alir, -apple-system, blinkmacsystemfont, "Helvetica Neue", helvetica, "segoe ui", arial, roboto, "PingFang SC", miui, "Hiragino Sans GB", "Microsoft Yahei", sans-serif; font-family: alir, -apple-system, blinkmacsystemfont, "Helvetica Neue", helvetica, "segoe ui", arial, roboto, "PingFang SC", miui, "Hiragino Sans GB", "Microsoft Yahei", sans-serif;
color: var(--sdream-text-primary); color: var(--sdream-text-primary);
// background-color: #000;
} }
#root { #root {
height: 100%; height: 100%;
margin: 0; margin: 0;
color: var(--sdream-text-primary); color: var(--sdream-text-primary);
overflow: hidden;
} }
...@@ -14,3 +14,32 @@ export const isDate = (val: any): val is Date => toString(val) === '[object Date ...@@ -14,3 +14,32 @@ export const isDate = (val: any): val is Date => toString(val) === '[object Date
export const isWindow = (val: any): boolean => typeof window !== 'undefined' && toString(val) === '[object Window]' export const isWindow = (val: any): boolean => typeof window !== 'undefined' && toString(val) === '[object Window]'
export const isBrowser = typeof window !== 'undefined' export const isBrowser = typeof window !== 'undefined'
/**
* 判断当前设备是否为移动端
* @returns {boolean} true 表示移动端,false 表示 PC 端
*/
export function isMobile(): boolean {
// 1. 使用 navigator.userAgent 进行判断
const userAgent = navigator.userAgent.toLowerCase()
// 2. 定义移动设备的关键词
const mobileKeywords = [
'mobile',
'android',
'iphone',
'ipod',
'ipad',
'windows phone',
'webos',
'blackberry',
]
// 3. 检查是否包含移动设备关键词
const isMobileDevice = mobileKeywords.some(keyword => userAgent.includes(keyword))
// 4. 使用屏幕宽度作为补充判断(可选)
const isMobileWidth = window.innerWidth <= 768
// 5. 返回结果:同时满足 UA 判断和屏幕宽度判断才认为是移动端
return isMobileDevice && isMobileWidth
}
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