Update overview layout
This commit is contained in:
@@ -13,8 +13,12 @@ export const DashboardPage: React.FC = () => {
|
||||
const [selectedAssistantId, setSelectedAssistantId] = useState<string>('all');
|
||||
const [assistants, setAssistants] = useState<Assistant[]>([]);
|
||||
const [topRailHeight, setTopRailHeight] = useState(0);
|
||||
const [isOverviewVisible, setIsOverviewVisible] = useState(true);
|
||||
const [scrollRootCenterX, setScrollRootCenterX] = useState<number | null>(null);
|
||||
|
||||
const scrollRootRef = useRef<HTMLDivElement>(null);
|
||||
const topRailRef = useRef<HTMLDivElement>(null);
|
||||
const overviewRef = useRef<HTMLElement>(null);
|
||||
const workflowRef = useRef<HTMLDivElement>(null);
|
||||
const aboutRef = useRef<HTMLDivElement>(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<HTMLDivElement>) => {
|
||||
ref.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-[calc(100vh-5rem)] overflow-y-auto snap-y snap-mandatory custom-scrollbar relative scroll-smooth bg-background">
|
||||
<div ref={scrollRootRef} className="h-[calc(100vh-5rem)] overflow-y-auto snap-y snap-mandatory custom-scrollbar relative scroll-smooth bg-background">
|
||||
<div ref={topRailRef} className="sticky top-0 z-40 bg-gradient-to-b from-background via-background/95 to-transparent pb-3">
|
||||
<div className="mx-auto w-full max-w-[1600px] px-6 lg:px-12 pt-3">
|
||||
<div className="flex justify-end items-center gap-3 rounded-2xl border border-white/10 bg-background/75 px-3 py-2 backdrop-blur-xl shadow-[0_8px_30px_rgba(0,0,0,0.25)]">
|
||||
@@ -77,6 +122,7 @@ export const DashboardPage: React.FC = () => {
|
||||
|
||||
{/* SECTION 1: METRICS & CHARTS */}
|
||||
<section
|
||||
ref={overviewRef}
|
||||
className="min-h-full snap-start flex flex-col pb-4 relative"
|
||||
style={{ paddingTop: `${topRailHeight + 8}px` }}
|
||||
>
|
||||
@@ -212,17 +258,25 @@ export const DashboardPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scroll Indicator */}
|
||||
</section>
|
||||
|
||||
{/* Scroll Indicator (Overview, fixed to viewport bottom) */}
|
||||
{isOverviewVisible && (
|
||||
<div
|
||||
onClick={() => 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"
|
||||
className="pointer-events-none fixed bottom-4 z-30 -translate-x-1/2"
|
||||
style={{ left: scrollRootCenterX ? `${scrollRootCenterX}px` : '50%' }}
|
||||
>
|
||||
<span className="text-[10px] font-bold text-primary tracking-[0.3em] uppercase group-hover:tracking-[0.5em] transition-all">核心流程</span>
|
||||
<div className="p-2 rounded-full bg-primary/10 border border-primary/20 backdrop-blur-sm group-hover:bg-primary group-hover:text-black transition-colors">
|
||||
<ArrowDown className="w-5 h-5" />
|
||||
<div
|
||||
onClick={() => 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"
|
||||
>
|
||||
<span className="text-[10px] font-bold text-primary tracking-[0.3em] uppercase group-hover:tracking-[0.5em] transition-all">核心流程</span>
|
||||
<div className="p-2 rounded-full bg-primary/10 border border-primary/20 backdrop-blur-sm group-hover:bg-primary group-hover:text-black transition-colors">
|
||||
<ArrowDown className="w-5 h-5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* SECTION 2: WORKFLOW LOGIC */}
|
||||
<section
|
||||
@@ -282,10 +336,12 @@ export const DashboardPage: React.FC = () => {
|
||||
{/* Scroll Indicator */}
|
||||
<div
|
||||
onClick={() => 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"
|
||||
>
|
||||
<span className="text-[10px] text-muted-foreground tracking-widest font-bold">了解更多</span>
|
||||
<ArrowDown className="w-6 h-6 text-white animate-bounce" />
|
||||
<span className="text-[10px] font-bold text-primary tracking-[0.3em] uppercase group-hover:tracking-[0.5em] transition-all">了解更多</span>
|
||||
<div className="p-2 rounded-full bg-primary/10 border border-primary/20 backdrop-blur-sm group-hover:bg-primary group-hover:text-black transition-colors">
|
||||
<ArrowDown className="w-5 h-5" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user