polishing ui
This commit is contained in:
1 parent
e5820a4890
commit
ec0f73f560
4 files changed
+68
-17
No files matched your search
@@ -5,6 +5,11 @@ import { motion } from "framer-motion";
|
|||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
|
|
||||||
|
// Browsers report region variants (e.g. "en-US", "pt-BR"), not just the
|
||||||
|
// bare "en"/"pt" i18next is configured with - matching on that exactly
|
||||||
|
// would pick the wrong sized text class for most real visitors.
|
||||||
|
const currentLang = i18n.language?.startsWith("pt") ? "pt" : "en";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="flex flex-col space-y-8 justify-center items-center mt-10 mb-8 px-6 pt-10">
|
<footer className="flex flex-col space-y-8 justify-center items-center mt-10 mb-8 px-6 pt-10">
|
||||||
<div className="w-full max-w-xs h-px bg-gradient-to-r from-transparent via-white/10 to-transparent" />
|
<div className="w-full max-w-xs h-px bg-gradient-to-r from-transparent via-white/10 to-transparent" />
|
||||||
@@ -38,7 +43,7 @@ const Footer = () => {
|
|||||||
<a
|
<a
|
||||||
href="/tos"
|
href="/tos"
|
||||||
className={
|
className={
|
||||||
i18n.language === "en"
|
currentLang === "en"
|
||||||
? "footer-text hover:text-gold-light transition-colors"
|
? "footer-text hover:text-gold-light transition-colors"
|
||||||
: "footer-text-pt hover:text-gold-light transition-colors"
|
: "footer-text-pt hover:text-gold-light transition-colors"
|
||||||
}
|
}
|
||||||
@@ -48,7 +53,7 @@ const Footer = () => {
|
|||||||
<a
|
<a
|
||||||
href="/privacy"
|
href="/privacy"
|
||||||
className={
|
className={
|
||||||
i18n.language === "en"
|
currentLang === "en"
|
||||||
? "footer-text hover:text-gold-light transition-colors"
|
? "footer-text hover:text-gold-light transition-colors"
|
||||||
: "footer-text-pt hover:text-gold-light transition-colors"
|
: "footer-text-pt hover:text-gold-light transition-colors"
|
||||||
}
|
}
|
||||||
@@ -59,7 +64,7 @@ const Footer = () => {
|
|||||||
|
|
||||||
<p
|
<p
|
||||||
className={
|
className={
|
||||||
i18n.language === "en"
|
currentLang === "en"
|
||||||
? "footer-text text-center"
|
? "footer-text text-center"
|
||||||
: "footer-text-pt text-center"
|
: "footer-text-pt text-center"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,26 +31,52 @@ const Navbar = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
// Each section's offset, measured once (and on resize) instead of on
|
||||||
|
// every scroll tick - getBoundingClientRect() forces a synchronous
|
||||||
|
// layout recalc, and calling it on every native scroll event (which
|
||||||
|
// fires far more often than the display's refresh rate during a fast
|
||||||
|
// swipe or a smooth-scroll animation) is what made scrolling feel
|
||||||
|
// sluggish: layout was being thrashed dozens of times a second.
|
||||||
|
let sectionTops: { path: string; top: number }[] = [];
|
||||||
|
|
||||||
|
const measureSections = () => {
|
||||||
|
sectionTops = navigation.map((item) => {
|
||||||
|
const el = document.getElementById(item.path);
|
||||||
|
const top = el
|
||||||
|
? el.getBoundingClientRect().top + window.scrollY
|
||||||
|
: Infinity;
|
||||||
|
return { path: item.path, top };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let ticking = false;
|
||||||
|
|
||||||
|
const updateFromScroll = () => {
|
||||||
setColorChange(window.scrollY >= 100);
|
setColorChange(window.scrollY >= 100);
|
||||||
|
|
||||||
// The active section is whichever nav target's start we've scrolled
|
// The active section is whichever nav target's start we've scrolled
|
||||||
// past most recently - not just "is it in the viewport", since a
|
// past most recently - not just "is it in the viewport", since a
|
||||||
// short section could otherwise never register as active at all.
|
// short section could otherwise never register as active at all.
|
||||||
let current = navigation[0].path;
|
let current = navigation[0].path;
|
||||||
for (const item of navigation) {
|
for (const { path, top } of sectionTops) {
|
||||||
const el = document.getElementById(item.path);
|
|
||||||
if (!el) continue;
|
|
||||||
const top = el.getBoundingClientRect().top + window.scrollY;
|
|
||||||
if (window.scrollY + NAVBAR_HEIGHT + 40 >= top) {
|
if (window.scrollY + NAVBAR_HEIGHT + 40 >= top) {
|
||||||
current = item.path;
|
current = path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setActiveSection(current);
|
setActiveSection(current);
|
||||||
|
ticking = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
handleScroll();
|
const handleScroll = () => {
|
||||||
|
if (ticking) return;
|
||||||
|
ticking = true;
|
||||||
|
requestAnimationFrame(updateFromScroll);
|
||||||
|
};
|
||||||
|
|
||||||
|
measureSections();
|
||||||
|
updateFromScroll();
|
||||||
window.addEventListener("scroll", handleScroll, { passive: true });
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
||||||
|
window.addEventListener("resize", measureSections);
|
||||||
|
|
||||||
const scrollPath = sessionStorage.getItem("scrollPath");
|
const scrollPath = sessionStorage.getItem("scrollPath");
|
||||||
if (scrollPath) {
|
if (scrollPath) {
|
||||||
@@ -60,6 +86,7 @@ const Navbar = () => {
|
|||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("scroll", handleScroll);
|
window.removeEventListener("scroll", handleScroll);
|
||||||
|
window.removeEventListener("resize", measureSections);
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
@@ -109,12 +136,26 @@ const Navbar = () => {
|
|||||||
>
|
>
|
||||||
<div className={colorChange ? "px-4" : ""}>
|
<div className={colorChange ? "px-4" : ""}>
|
||||||
<div
|
<div
|
||||||
className={`relative mx-auto flex items-center justify-between transition-all duration-500 ${
|
className={`relative mx-auto flex items-center justify-between transition-[max-width,margin,padding] duration-500 ${
|
||||||
colorChange
|
colorChange
|
||||||
? "mt-3 max-w-3xl rounded-full glass-nav shadow-glass-lg px-5 py-2.5"
|
? "mt-3 max-w-3xl px-5 py-2.5"
|
||||||
: "max-w-screen-xl px-4 py-3 md:px-8 md:py-5"
|
: "max-w-screen-xl px-4 py-3 md:px-8 md:py-5"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
{/*
|
||||||
|
The glass material is its own layer, separate from the box
|
||||||
|
above whose size/margin is animating. backdrop-filter can't be
|
||||||
|
smoothly interpolated between "none" and "blur(20px)" - toggling
|
||||||
|
it on the same element that's also resizing is what produced a
|
||||||
|
seam along the bottom edge mid-transition. Here it's always
|
||||||
|
present and only crossfades via opacity, which is safe.
|
||||||
|
*/}
|
||||||
|
<div
|
||||||
|
className={`absolute inset-0 -z-10 rounded-full glass-nav shadow-glass-lg transition-opacity duration-500 ${
|
||||||
|
colorChange ? "opacity-100" : "opacity-0"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
|
||||||
<motion.a
|
<motion.a
|
||||||
href="Top"
|
href="Top"
|
||||||
whileTap={{ scale: 0.92 }}
|
whileTap={{ scale: 0.92 }}
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ const Hero = () => {
|
|||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const prefersReducedMotion = useReducedMotion();
|
const prefersReducedMotion = useReducedMotion();
|
||||||
|
|
||||||
|
// Browsers report region variants (e.g. "en-US", "pt-BR"), not just the
|
||||||
|
// bare "en"/"pt" i18next is configured with - matching on that exactly
|
||||||
|
// would pick the wrong sized text class for most real visitors.
|
||||||
|
const currentLang = i18n.language?.startsWith("pt") ? "pt" : "en";
|
||||||
|
|
||||||
const handleNavigation = (path: string) => {
|
const handleNavigation = (path: string) => {
|
||||||
const element = document.getElementById(path);
|
const element = document.getElementById(path);
|
||||||
const navbarHeight = 110;
|
const navbarHeight = 110;
|
||||||
@@ -51,13 +56,13 @@ const Hero = () => {
|
|||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<motion.h1
|
<motion.h1
|
||||||
className={i18n.language === "en" ? "hero-text" : "hero-text-pt"}
|
className={currentLang === "en" ? "hero-text" : "hero-text-pt"}
|
||||||
{...rise(0.05)}
|
{...rise(0.05)}
|
||||||
>
|
>
|
||||||
{t("hero.heading.part1")}
|
{t("hero.heading.part1")}
|
||||||
</motion.h1>
|
</motion.h1>
|
||||||
<motion.h1
|
<motion.h1
|
||||||
className={i18n.language === "en" ? "hero-text" : "hero-text-pt"}
|
className={currentLang === "en" ? "hero-text" : "hero-text-pt"}
|
||||||
{...rise(0.1)}
|
{...rise(0.1)}
|
||||||
>
|
>
|
||||||
<span className="gold-text">{t("hero.heading.part2")}</span>
|
<span className="gold-text">{t("hero.heading.part2")}</span>
|
||||||
@@ -69,7 +74,7 @@ const Hero = () => {
|
|||||||
<motion.div className="mx-5 lg:mx-0" {...rise(0.15)}>
|
<motion.div className="mx-5 lg:mx-0" {...rise(0.15)}>
|
||||||
<h2
|
<h2
|
||||||
className={
|
className={
|
||||||
i18n.language === "en"
|
currentLang === "en"
|
||||||
? "hero-sub-text mt-4 md:mt-10"
|
? "hero-sub-text mt-4 md:mt-10"
|
||||||
: "hero-sub-text-pt mt-4 md:mt-10"
|
: "hero-sub-text-pt mt-4 md:mt-10"
|
||||||
}
|
}
|
||||||
@@ -78,7 +83,7 @@ const Hero = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
<h2
|
<h2
|
||||||
className={
|
className={
|
||||||
i18n.language === "en" ? "hero-sub-text" : "hero-sub-text-pt"
|
currentLang === "en" ? "hero-sub-text" : "hero-sub-text-pt"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("hero.subheading.part2")}
|
{t("hero.subheading.part2")}
|
||||||
|
|||||||
+1
-1
@@ -121,7 +121,7 @@ body {
|
|||||||
background: rgba(10, 10, 13, 0.55);
|
background: rgba(10, 10, 13, 0.55);
|
||||||
backdrop-filter: blur(20px) saturate(180%);
|
backdrop-filter: blur(20px) saturate(180%);
|
||||||
-webkit-backdrop-filter: blur(20px) saturate(180%);
|
-webkit-backdrop-filter: blur(20px) saturate(180%);
|
||||||
border-bottom: 1px solid rgba(250, 204, 151, 0.1);
|
border: 1px solid rgba(250, 204, 151, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Heavier material for full takeover surfaces (mobile menu sheet) — a
|
/* Heavier material for full takeover surfaces (mobile menu sheet) — a
|
||||||
|
|||||||
Reference in new issue
Block a user