diff --git a/web/pages/Dashboard.tsx b/web/pages/Dashboard.tsx index a6351ad..6f77690 100644 --- a/web/pages/Dashboard.tsx +++ b/web/pages/Dashboard.tsx @@ -13,8 +13,12 @@ export const DashboardPage: React.FC = () => { const [selectedAssistantId, setSelectedAssistantId] = useState('all'); const [assistants, setAssistants] = useState([]); const [topRailHeight, setTopRailHeight] = useState(0); + const [isOverviewVisible, setIsOverviewVisible] = useState(true); + const [scrollRootCenterX, setScrollRootCenterX] = useState(null); + const scrollRootRef = useRef(null); const topRailRef = useRef(null); + const overviewRef = useRef(null); const workflowRef = useRef(null); const aboutRef = useRef(null); @@ -56,12 +60,53 @@ export const DashboardPage: React.FC = () => { }; }, []); + useEffect(() => { + if (!scrollRootRef.current || !overviewRef.current) return; + + const observer = new IntersectionObserver( + ([entry]) => { + setIsOverviewVisible(entry.isIntersecting); + }, + { + root: scrollRootRef.current, + threshold: 0.35, + } + ); + + observer.observe(overviewRef.current); + return () => observer.disconnect(); + }, []); + + useEffect(() => { + const updateScrollRootCenter = () => { + if (!scrollRootRef.current) return; + const rect = scrollRootRef.current.getBoundingClientRect(); + setScrollRootCenterX(rect.left + rect.width / 2); + }; + + updateScrollRootCenter(); + + const observer = new ResizeObserver(() => { + updateScrollRootCenter(); + }); + + if (scrollRootRef.current) { + observer.observe(scrollRootRef.current); + } + + window.addEventListener('resize', updateScrollRootCenter); + return () => { + observer.disconnect(); + window.removeEventListener('resize', updateScrollRootCenter); + }; + }, []); + const scrollToNext = (ref: React.RefObject) => { ref.current?.scrollIntoView({ behavior: 'smooth' }); }; return ( -
+
@@ -77,6 +122,7 @@ export const DashboardPage: React.FC = () => { {/* SECTION 1: METRICS & CHARTS */}
@@ -212,17 +258,25 @@ export const DashboardPage: React.FC = () => {
- {/* Scroll Indicator */} -
scrollToNext(workflowRef)} - className="mt-3 mb-1 self-center flex flex-col items-center gap-2 cursor-pointer group animate-bounce-slow opacity-35 hover:opacity-100 transition-all duration-500 hover:scale-110" + + + {/* Scroll Indicator (Overview, fixed to viewport bottom) */} + {isOverviewVisible && ( +
- 核心流程 -
- +
scrollToNext(workflowRef)} + className="pointer-events-auto flex flex-col items-center gap-2 cursor-pointer group animate-bounce-slow opacity-45 hover:opacity-100 transition-all duration-500 hover:scale-110" + > + 核心流程 +
+ +
- + )} {/* SECTION 2: WORKFLOW LOGIC */}
{ {/* Scroll Indicator */}
scrollToNext(aboutRef)} - className="absolute bottom-10 left-1/2 -translate-x-1/2 cursor-pointer opacity-30 hover:opacity-100 transition-opacity p-4 flex flex-col items-center gap-2 hover:scale-110 duration-300" + className="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2 cursor-pointer group animate-bounce-slow opacity-45 hover:opacity-100 transition-all duration-500 hover:scale-110" > - 了解更多 - + 了解更多 +
+ +