forked from emre/www_projectmycelium_com
refactor: implement smart navigation for "Get Mycelium Connector" button with smooth scroll utility
- Added smoothScrollToElement utility function in src/utils/scroll.ts with easeInOutQuad animation and configurable duration - Changed Header and HeaderDark "Get Mycelium Connector" button from static /download link to onClick handler with conditional navigation - Added handleGetConnectorClick function that scrolls to #download section when on /network page, otherwise navigates to /network - Change
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Link, useLocation, useNavigate } from 'react-router-dom'
|
||||
import { smoothScrollToElement } from '@/utils/scroll'
|
||||
import { Container } from './Container'
|
||||
import { Button } from './Button'
|
||||
import pmyceliumLogo from '../images/logos/mainlogo.svg'
|
||||
@@ -9,6 +10,17 @@ import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
|
||||
export function Header() {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
|
||||
const handleGetConnectorClick = () => {
|
||||
if (location.pathname === '/network') {
|
||||
smoothScrollToElement('download', 1200)
|
||||
} else {
|
||||
navigate('/network')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<header className="bg-white">
|
||||
<nav className="border-b border-gray-100">
|
||||
@@ -61,7 +73,7 @@ export function Header() {
|
||||
>
|
||||
Deploy Now
|
||||
</Button>
|
||||
<Button to="/download" variant="solid" color="cyan">
|
||||
<Button variant="solid" color="cyan" onClick={handleGetConnectorClick}>
|
||||
Get Mycelium Connector
|
||||
</Button>
|
||||
</div>
|
||||
@@ -150,7 +162,15 @@ export function Header() {
|
||||
>
|
||||
Start Deployment
|
||||
</Button>
|
||||
<Button to="/download" variant="solid" color="cyan" className="mt-4 w-full" onClick={() => setMobileMenuOpen(false)}>
|
||||
<Button
|
||||
variant="solid"
|
||||
color="cyan"
|
||||
className="mt-4 w-full"
|
||||
onClick={() => {
|
||||
setMobileMenuOpen(false)
|
||||
handleGetConnectorClick()
|
||||
}}
|
||||
>
|
||||
Get Mycelium Connector
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Link, useLocation, useNavigate } from 'react-router-dom'
|
||||
import { smoothScrollToElement } from '@/utils/scroll'
|
||||
import { Container } from './Container'
|
||||
import { Button } from './Button'
|
||||
import pmyceliumLogo from '../images/logos/mainlogo.svg'
|
||||
@@ -9,6 +10,17 @@ import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
|
||||
export function HeaderDark() {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
|
||||
const handleGetConnectorClick = () => {
|
||||
if (location.pathname === '/network') {
|
||||
smoothScrollToElement('download', 1200)
|
||||
} else {
|
||||
navigate('/network')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<header className="bg-[#111111]">
|
||||
<nav className="border-b border-gray-800">
|
||||
@@ -61,7 +73,7 @@ export function HeaderDark() {
|
||||
>
|
||||
Deploy Now
|
||||
</Button>
|
||||
<Button to="/download" variant="solid" color="cyan">
|
||||
<Button variant="solid" color="cyan" onClick={handleGetConnectorClick}>
|
||||
Get Mycelium Connector
|
||||
</Button>
|
||||
</div>
|
||||
@@ -150,7 +162,15 @@ export function HeaderDark() {
|
||||
>
|
||||
Start Deployment
|
||||
</Button>
|
||||
<Button to="/download" variant="solid" color="cyan" className="mt-4 w-full" onClick={() => setMobileMenuOpen(false)}>
|
||||
<Button
|
||||
variant="solid"
|
||||
color="cyan"
|
||||
className="mt-4 w-full"
|
||||
onClick={() => {
|
||||
setMobileMenuOpen(false)
|
||||
handleGetConnectorClick()
|
||||
}}
|
||||
>
|
||||
Get Mycelium Connector
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -6,9 +6,10 @@ import {
|
||||
useScroll,
|
||||
useMotionValueEvent,
|
||||
} from "motion/react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "../Button";
|
||||
import { smoothScrollToElement } from "@/utils/scroll";
|
||||
|
||||
|
||||
export const FloatingNav = ({
|
||||
@@ -23,8 +24,17 @@ export const FloatingNav = ({
|
||||
className?: string;
|
||||
}) => {
|
||||
const { scrollYProgress } = useScroll();
|
||||
|
||||
const [visible, setVisible] = useState(true);
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
const handleGetConnectorClick = () => {
|
||||
if (location.pathname === "/network") {
|
||||
smoothScrollToElement("download", 1200);
|
||||
} else {
|
||||
navigate("/network");
|
||||
}
|
||||
};
|
||||
|
||||
useMotionValueEvent(scrollYProgress, "change", (current) => {
|
||||
if (typeof current === "number") {
|
||||
@@ -80,7 +90,7 @@ export const FloatingNav = ({
|
||||
>
|
||||
<span className="hidden sm:block text-sm">Docs</span>
|
||||
</a>
|
||||
<Button to="/download" variant="solid" color="cyan">
|
||||
<Button variant="solid" color="cyan" onClick={handleGetConnectorClick}>
|
||||
Get Mycelium Connector
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useId } from 'react'
|
||||
import { Container } from '@/components/Container'
|
||||
import { Button } from '@/components/Button'
|
||||
import { smoothScrollToElement } from '@/utils/scroll'
|
||||
import phoneFrame from '../../images/phoneframe.png'
|
||||
import { H3, P
|
||||
, Eyebrow } from "@/components/Texts";
|
||||
@@ -93,7 +94,11 @@ export function Hero() {
|
||||
Your Pod is your personal gateway to the network.
|
||||
</P>
|
||||
<div className="mt-8 flex flex-wrap gap-x-6 gap-y-4">
|
||||
<Button to="/download" variant="solid" color="cyan">
|
||||
<Button
|
||||
variant="solid"
|
||||
color="cyan"
|
||||
onClick={() => smoothScrollToElement('download', 1200)}
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { Button } from '@/components/Button'
|
||||
import { Eyebrow, H3, P } from '@/components/Texts'
|
||||
import { smoothScrollToElement } from '@/utils/scroll'
|
||||
|
||||
export function NodeHero() {
|
||||
return (
|
||||
@@ -31,12 +32,7 @@ export function NodeHero() {
|
||||
<Button
|
||||
variant="solid"
|
||||
color="cyan"
|
||||
onClick={() => {
|
||||
const el = document.getElementById('node-how-it-works')
|
||||
if (el) {
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
}
|
||||
}}
|
||||
onClick={() => smoothScrollToElement('node-how-it-works', 1200)}
|
||||
>
|
||||
How it works
|
||||
</Button>
|
||||
|
||||
28
src/utils/scroll.ts
Normal file
28
src/utils/scroll.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
export function smoothScrollToElement(id: string, duration = 800) {
|
||||
const element = document.getElementById(id)
|
||||
if (!element) return
|
||||
|
||||
const startY = window.scrollY || window.pageYOffset
|
||||
const targetRect = element.getBoundingClientRect()
|
||||
const targetY = startY + targetRect.top
|
||||
const startTime = performance.now()
|
||||
|
||||
function easeInOutQuad(t: number) {
|
||||
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t
|
||||
}
|
||||
|
||||
function step(currentTime: number) {
|
||||
const elapsed = currentTime - startTime
|
||||
const progress = Math.min(elapsed / duration, 1)
|
||||
const eased = easeInOutQuad(progress)
|
||||
const nextY = startY + (targetY - startY) * eased
|
||||
|
||||
window.scrollTo(0, nextY)
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(step)
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(step)
|
||||
}
|
||||
Reference in New Issue
Block a user