routes.tsx

import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { BasePage } from './pages/BasePage';
import { Films } from './pages/Films';
import { Home } from './pages/Home';
import { FilmDetails } from './pages/FilmDetails';

export function AppRoutes() {
    return (
        <BrowserRouter>
            <Routes>
                <Route path="/" element={<BasePage />}>
                    <Route index element={<Home />} />
                    <Route path="/filmes" element={<Films />} />
                    <Route path="/filme/:id" element={<FilmDetails />} />
                </Route>
            </Routes>
        </BrowserRouter>
    );
}

Header

// src/components/Header.tsx

import { Link } from 'react-router-dom';
import { useScrolled } from '../../../hooks/useScrolled';

export function Header() {
    const scrolled = useScrolled(24);

    return (
        <header
            className={[
                'fixed inset-x-0 top-0 z-50 h-20 px-10',
                'flex items-center',
                'transition-colors duration-300',
                'border-b',
                scrolled
                    ? 'bg-surface border-white/10 backdrop-blur-md'
                    : 'bg-transparent border-transparent',
            ].join(' ')}
        >
            <Link to="/" className="font-roboto font-semibold text-2xl">
                DevMovie
            </Link>
        </header>
    );
}

Footer

export function Footer() {
    return (
        <footer className="h-14 mt-16 bg-footer-bg text-footer-color flex justify-center items-center">
            <p className="font-light">
                Desenvolvido por{' '}
                <a
                    href="<https://www.arturbomtempo.dev/>"
                    target="_blank"
                    className="hover:underline underline-offset-4 decoration-1 transition"
                >
                    Artur Bomtempo
                </a>
            </p>
        </footer>
    );
}

Container

import type { ReactNode } from 'react';

interface ContainerProps {
    children: ReactNode;
}

export function Container({ children }: ContainerProps) {
    return <section>{children}</section>;
}

hooks/useScrolled.ts

// src/hooks/useScrolled.ts
import { useEffect, useState } from 'react';

export function useScrolled(threshold = 16) {
    const [scrolled, setScrolled] = useState(false);

    useEffect(() => {
        let ticking = false;

        const onScroll = () => {
            const y = window.scrollY || document.documentElement.scrollTop;
            if (!ticking) {
                window.requestAnimationFrame(() => {
                    setScrolled(y > threshold);
                    ticking = false;
                });
                ticking = true;
            }
        };

        onScroll(); // define o estado correto já no mount
        window.addEventListener('scroll', onScroll, { passive: true });
        return () => window.removeEventListener('scroll', onScroll);
    }, [threshold]);

    return scrolled;
}

pages/BasePage/index.tsx

import { Outlet } from 'react-router-dom';
import { Container } from '../../components/Common/Container';
import { Header } from '../../components/Common/Header';
import { Footer } from '../../components/Common/Footer';

export function BasePage() {
    return (
        <main>
            <Header />
            <Container>
                <Outlet />
            </Container>
            <Footer />
        </main>
    );
}

Home/Title/index.tsx

interface TitleProps {
    text: string;
}

export function Title({ text }: TitleProps) {
    return <h2 className="font-medium font-libre text-2xl text-center my-8 md:text-4xl">{text}</h2>;
}