|
|
|
@ -64,7 +64,12 @@ function NetworkGlobe() { |
|
|
|
const y2 = y * cosX - z1 * sinX; |
|
|
|
const y2 = y * cosX - z1 * sinX; |
|
|
|
const z2 = y * sinX + z1 * cosX; |
|
|
|
const z2 = y * sinX + z1 * cosX; |
|
|
|
const scale = 1 / (1.6 + z2 * 0.4); |
|
|
|
const scale = 1 / (1.6 + z2 * 0.4); |
|
|
|
return { sx: cx + x1 * R * scale, sy: cy + y2 * R * scale, sz: z2, scale }; |
|
|
|
return { |
|
|
|
|
|
|
|
sx: cx + x1 * R * scale, |
|
|
|
|
|
|
|
sy: cy + y2 * R * scale, |
|
|
|
|
|
|
|
sz: z2, |
|
|
|
|
|
|
|
scale, |
|
|
|
|
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function draw() { |
|
|
|
function draw() { |
|
|
|
@ -100,7 +105,8 @@ function NetworkGlobe() { |
|
|
|
const d = Math.sqrt(dx * dx + dy * dy + dz * dz); |
|
|
|
const d = Math.sqrt(dx * dx + dy * dy + dz * dz); |
|
|
|
if (d < 0.55) { |
|
|
|
if (d < 0.55) { |
|
|
|
const depth = (a.sz + b.sz) * 0.5; |
|
|
|
const depth = (a.sz + b.sz) * 0.5; |
|
|
|
const alpha = Math.max(0, 0.05 + (depth + 1) * 0.1) * (1 - d / 0.55); |
|
|
|
const alpha = |
|
|
|
|
|
|
|
Math.max(0, 0.05 + (depth + 1) * 0.1) * (1 - d / 0.55); |
|
|
|
const aHex = Math.round(Math.min(255, alpha * 255)) |
|
|
|
const aHex = Math.round(Math.min(255, alpha * 255)) |
|
|
|
.toString(16) |
|
|
|
.toString(16) |
|
|
|
.padStart(2, "0"); |
|
|
|
.padStart(2, "0"); |
|
|
|
@ -129,7 +135,14 @@ function NetworkGlobe() { |
|
|
|
.toString(16) |
|
|
|
.toString(16) |
|
|
|
.padStart(2, "0"); |
|
|
|
.padStart(2, "0"); |
|
|
|
|
|
|
|
|
|
|
|
const glow = ctx.createRadialGradient(n.sx, n.sy, 0, n.sx, n.sy, r * 3.5); |
|
|
|
const glow = ctx.createRadialGradient( |
|
|
|
|
|
|
|
n.sx, |
|
|
|
|
|
|
|
n.sy, |
|
|
|
|
|
|
|
0, |
|
|
|
|
|
|
|
n.sx, |
|
|
|
|
|
|
|
n.sy, |
|
|
|
|
|
|
|
r * 3.5, |
|
|
|
|
|
|
|
); |
|
|
|
glow.addColorStop(0, n.color + gHex); |
|
|
|
glow.addColorStop(0, n.color + gHex); |
|
|
|
glow.addColorStop(1, n.color + "00"); |
|
|
|
glow.addColorStop(1, n.color + "00"); |
|
|
|
ctx.beginPath(); |
|
|
|
ctx.beginPath(); |
|
|
|
@ -165,7 +178,7 @@ function NetworkGlobe() { |
|
|
|
|
|
|
|
|
|
|
|
export default function SubHero({ title, desc, navItems, rightSlot }) { |
|
|
|
export default function SubHero({ title, desc, navItems, rightSlot }) { |
|
|
|
const { pathname } = useLocation(); |
|
|
|
const { pathname } = useLocation(); |
|
|
|
const titleLines = typeof title === "string" ? title.split("\n") : [title]; |
|
|
|
const titleLines = typeof title === "string" ? title.split("\n") : null; |
|
|
|
const [isPill, setIsPill] = useState(false); |
|
|
|
const [isPill, setIsPill] = useState(false); |
|
|
|
const navRef = useRef(null); |
|
|
|
const navRef = useRef(null); |
|
|
|
|
|
|
|
|
|
|
|
@ -182,41 +195,60 @@ export default function SubHero({ title, desc, navItems, rightSlot }) { |
|
|
|
<section className={`sh4${rightSlot ? " sh4--split" : ""}`}> |
|
|
|
<section className={`sh4${rightSlot ? " sh4--split" : ""}`}> |
|
|
|
<div className="sh4-inner"> |
|
|
|
<div className="sh4-inner"> |
|
|
|
<div className="sh4-left"> |
|
|
|
<div className="sh4-left"> |
|
|
|
<motion.span className="sh4-label" initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.6, ease: [0.16, 1, 0.3, 1] }}> |
|
|
|
<motion.span |
|
|
|
|
|
|
|
className="sh4-label" |
|
|
|
|
|
|
|
initial={{ opacity: 0, y: 12 }} |
|
|
|
|
|
|
|
animate={{ opacity: 1, y: 0 }} |
|
|
|
|
|
|
|
transition={{ duration: 0.6, ease: [0.16, 1, 0.3, 1] }} |
|
|
|
|
|
|
|
> |
|
|
|
{menuMap["/" + pathname.split("/")[1]]?.label} |
|
|
|
{menuMap["/" + pathname.split("/")[1]]?.label} |
|
|
|
</motion.span> |
|
|
|
</motion.span> |
|
|
|
|
|
|
|
|
|
|
|
<h1 className="sh4-title"> |
|
|
|
<h1 className="sh4-title"> |
|
|
|
{titleLines.map((line, li) => ( |
|
|
|
{typeof title === "string" |
|
|
|
<span key={li} className="sh4-title-line"> |
|
|
|
? titleLines.map((line, li) => ( |
|
|
|
{line.split("").map((char, ci) => ( |
|
|
|
<span key={li} className="sh4-title-line"> |
|
|
|
<motion.span |
|
|
|
{line.split("").map((char, ci) => ( |
|
|
|
key={ci} |
|
|
|
<motion.span |
|
|
|
className="sh4-char" |
|
|
|
key={ci} |
|
|
|
initial={{ opacity: 0 }} |
|
|
|
className="sh4-char" |
|
|
|
animate={{ opacity: 1 }} |
|
|
|
initial={{ opacity: 0 }} |
|
|
|
transition={{ |
|
|
|
animate={{ opacity: 1 }} |
|
|
|
duration: 0.6, |
|
|
|
transition={{ |
|
|
|
delay: li * 0.08 + ci * 0.022, |
|
|
|
duration: 0.6, |
|
|
|
ease: [0.16, 1, 0.3, 1], |
|
|
|
delay: li * 0.08 + ci * 0.022, |
|
|
|
}} |
|
|
|
ease: [0.16, 1, 0.3, 1], |
|
|
|
> |
|
|
|
}} |
|
|
|
{char === " " ? "\u00A0" : char} |
|
|
|
> |
|
|
|
</motion.span> |
|
|
|
{char === " " ? "\u00A0" : char} |
|
|
|
))} |
|
|
|
</motion.span> |
|
|
|
</span> |
|
|
|
))} |
|
|
|
))} |
|
|
|
</span> |
|
|
|
|
|
|
|
)) |
|
|
|
|
|
|
|
: title} |
|
|
|
</h1> |
|
|
|
</h1> |
|
|
|
|
|
|
|
|
|
|
|
{desc && ( |
|
|
|
{desc && ( |
|
|
|
<motion.p className="sh4-desc" initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.7, delay: 0.8, ease: [0.16, 1, 0.3, 1] }}> |
|
|
|
<motion.p |
|
|
|
|
|
|
|
className="sh4-desc" |
|
|
|
|
|
|
|
initial={{ opacity: 0, y: 16 }} |
|
|
|
|
|
|
|
animate={{ opacity: 1, y: 0 }} |
|
|
|
|
|
|
|
transition={{ |
|
|
|
|
|
|
|
duration: 0.7, |
|
|
|
|
|
|
|
delay: 0.8, |
|
|
|
|
|
|
|
ease: [0.16, 1, 0.3, 1], |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
> |
|
|
|
{desc} |
|
|
|
{desc} |
|
|
|
</motion.p> |
|
|
|
</motion.p> |
|
|
|
)} |
|
|
|
)} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
{rightSlot && ( |
|
|
|
{rightSlot && ( |
|
|
|
<motion.div className="sh4-right" initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1, delay: 0.3 }}> |
|
|
|
<motion.div |
|
|
|
|
|
|
|
className="sh4-right" |
|
|
|
|
|
|
|
initial={{ opacity: 0 }} |
|
|
|
|
|
|
|
animate={{ opacity: 1 }} |
|
|
|
|
|
|
|
transition={{ duration: 1, delay: 0.3 }} |
|
|
|
|
|
|
|
> |
|
|
|
{rightSlot} |
|
|
|
{rightSlot} |
|
|
|
</motion.div> |
|
|
|
</motion.div> |
|
|
|
)} |
|
|
|
)} |
|
|
|
@ -224,10 +256,18 @@ export default function SubHero({ title, desc, navItems, rightSlot }) { |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
{navItems?.length > 1 && ( |
|
|
|
{navItems?.length > 1 && ( |
|
|
|
<nav ref={navRef} className={`sh4-nav-wrap${isPill ? " is-pill" : ""}`} aria-label="Sub Navigation"> |
|
|
|
<nav |
|
|
|
|
|
|
|
ref={navRef} |
|
|
|
|
|
|
|
className={`sh4-nav-wrap${isPill ? " is-pill" : ""}`} |
|
|
|
|
|
|
|
aria-label="Sub Navigation" |
|
|
|
|
|
|
|
> |
|
|
|
<div className="sh4-nav"> |
|
|
|
<div className="sh4-nav"> |
|
|
|
{navItems.map((item) => ( |
|
|
|
{navItems.map((item) => ( |
|
|
|
<Link key={item.to} to={item.to} className={`sh4-nav-tab${pathname === item.to ? " sh4-nav-tab--active" : ""}`}> |
|
|
|
<Link |
|
|
|
|
|
|
|
key={item.to} |
|
|
|
|
|
|
|
to={item.to} |
|
|
|
|
|
|
|
className={`sh4-nav-tab${pathname === item.to ? " sh4-nav-tab--active" : ""}`} |
|
|
|
|
|
|
|
> |
|
|
|
{item.label} |
|
|
|
{item.label} |
|
|
|
</Link> |
|
|
|
</Link> |
|
|
|
))} |
|
|
|
))} |
|
|
|
|