diff --git a/web/src/app/globals.css b/web/src/app/globals.css index 0c3221a..2a42827 100644 --- a/web/src/app/globals.css +++ b/web/src/app/globals.css @@ -88,34 +88,24 @@ h3, z-index: 50; inset: 0; display: flex; - flex-direction: column; align-items: center; justify-content: center; - gap: 1rem; background: #000; - color: #e8f4e5; - letter-spacing: 0.18em; - text-transform: uppercase; - font-size: 0.72rem; } -.orbit-loader-dot { - width: 10px; - height: 10px; - border-radius: 999px; - background: #82c85c; - animation: loader-pulse 1s ease-in-out infinite; +.orbit-loader-logo { + width: min(11.5rem, 58vw); + height: auto; + animation: loader-glow 1.6s ease-in-out infinite; } -@keyframes loader-pulse { +@keyframes loader-glow { 0%, 100% { - opacity: 0.35; - transform: scale(1); + opacity: 0.4; } 50% { opacity: 1; - transform: scale(1.35); } } diff --git a/web/src/components/landing/scroll-film.tsx b/web/src/components/landing/scroll-film.tsx index 631d553..c85c9b5 100644 --- a/web/src/components/landing/scroll-film.tsx +++ b/web/src/components/landing/scroll-film.tsx @@ -8,6 +8,10 @@ type ScrollFilmProps = { children: ReactNode; }; +function easeInOutCubic(value: number) { + return value < 0.5 ? 4 * value * value * value : 1 - (-2 * value + 2) ** 3 / 2; +} + export function ScrollFilm({ src, poster, children }: ScrollFilmProps) { const orbitRef = useRef(null); const filmRef = useRef(null); @@ -30,6 +34,9 @@ export function ScrollFilm({ src, poster, children }: ScrollFilmProps) { let current = 0; let frame = 0; let blobUrl: string | null = null; + let introStartedAt = 0; + let introDone = false; + const introMs = 2400; const markReady = () => { if (ready) { @@ -39,6 +46,9 @@ export function ScrollFilm({ src, poster, children }: ScrollFilmProps) { film.pause(); film.classList.add("is-ready"); setLoading(false); + const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches; + introDone = reduce; + introStartedAt = reduce ? 0 : performance.now(); }; fetch(src) @@ -59,13 +69,33 @@ export function ScrollFilm({ src, poster, children }: ScrollFilmProps) { return y / total; }; - const tick = () => { + const introSeconds = (now: number, duration: number) => { + if (introDone || !introStartedAt) { + return null; + } + if (progressFromScroll() > 0.02) { + introDone = true; + return null; + } + const elapsed = now - introStartedAt; + const t = Math.min(elapsed / introMs, 1); + const peak = Math.min(2, Math.max(duration * 0.22, 0.6)); + const trip = t < 0.5 ? easeInOutCubic(t * 2) : 1 - easeInOutCubic((t - 0.5) * 2); + if (t >= 1) { + introDone = true; + return 0; + } + return trip * peak; + }; + + const tick = (now: number) => { const target = progressFromScroll(); current += (target - current) * 0.42; orbit.style.setProperty("--scrub", current.toFixed(4)); if (ready && film.duration && !film.seeking) { - const time = current * (film.duration - 0.04); + const intro = introSeconds(now, film.duration); + const time = intro ?? current * (film.duration - 0.04); if (Math.abs(film.currentTime - time) >= 0.02) { film.currentTime = time; } @@ -104,9 +134,8 @@ export function ScrollFilm({ src, poster, children }: ScrollFilmProps) {
{children}
{loading ? ( -
- -

Carregando Sinka

+
+ Sinka
) : null}
diff --git a/web/src/components/login-form.tsx b/web/src/components/login-form.tsx index c142c0c..eb5a848 100644 --- a/web/src/components/login-form.tsx +++ b/web/src/components/login-form.tsx @@ -19,10 +19,8 @@ export function LoginForm({ google_unlinked: "Este e-mail Google não tem acesso à administração.", google_denied: "Não foi possível entrar com o Google.", }[search.get("error") ?? ""]; - const [email, setEmail] = useState( - variant === "admin" ? "tina.r@example.net" : "xena.w@example.org", - ); - const [password, setPassword] = useState(variant === "admin" ? "SinkaPlatform!1" : "SinkaAdmin!1"); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false);