feat(home): seção Sobre com prova por ponto, contato por oferta e hero com a Lavação 047 na tela larga
This commit is contained in:
1 parent
d356c364e0
commit
9fd1570426
33 files changed
+1128
-369
No files matched your search
@@ -1,5 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { type RefObject, useEffect, useRef, useState } from "react";
|
||||
import type { PortfolioProjectView } from "@/lib/portfolio-data";
|
||||
import { secondaryButtonDark } from "./button-styles";
|
||||
import HoverPrefetchLink from "./HoverPrefetchLink";
|
||||
@@ -7,12 +8,69 @@ import { Section } from "./Section";
|
||||
import { ProjectReel } from "./showcase/ProjectReel";
|
||||
import { ShowcaseProvider } from "./showcase/ShowcaseProvider";
|
||||
|
||||
/**
|
||||
* Quanto "Ver os cases" anda para a direita para ficar na coluna da legenda e dos botões da vitrine. Na vitrine fixa
|
||||
* (a partir de 1024 px) o conjunto de aparelhos, com a legenda e os botões no canto esquerdo dele, fica centrado no
|
||||
* palco, e esse canto muda com a altura da janela (o palco mede a si mesmo): só medindo dá para alinhar o link a ele.
|
||||
* Sem vitrine fixa (celular, movimento reduzido, janela baixa) não há conjunto e o link fica no começo da coluna.
|
||||
*/
|
||||
function useReelColumnOffset(exitRef: RefObject<HTMLElement | null>) {
|
||||
const [offset, setOffset] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const exit = exitRef.current;
|
||||
const section = exit?.closest("section");
|
||||
if (!exit || !section) return;
|
||||
let observedSet: Element | null = null;
|
||||
|
||||
const refresh = () => {
|
||||
const set = section.querySelector(".ds-reel-set");
|
||||
if (set !== observedSet) {
|
||||
if (observedSet) resizes?.unobserve(observedSet);
|
||||
if (set) resizes?.observe(set);
|
||||
observedSet = set;
|
||||
}
|
||||
// o padding do próprio bloco não muda o `left` dele: a medida é só a distância até o canto do conjunto
|
||||
setOffset(
|
||||
set
|
||||
? Math.max(
|
||||
0,
|
||||
Math.round(
|
||||
set.getBoundingClientRect().left -
|
||||
exit.getBoundingClientRect().left,
|
||||
),
|
||||
)
|
||||
: 0,
|
||||
);
|
||||
};
|
||||
const resizes =
|
||||
typeof ResizeObserver === "undefined"
|
||||
? undefined
|
||||
: new ResizeObserver(refresh);
|
||||
|
||||
refresh();
|
||||
resizes?.observe(section);
|
||||
// a vitrine fixa chega depois (pacote sob demanda) e sai quando a janela deixa de comportá-la
|
||||
const mutations = new MutationObserver(refresh);
|
||||
mutations.observe(section, { childList: true, subtree: true });
|
||||
return () => {
|
||||
resizes?.disconnect();
|
||||
mutations.disconnect();
|
||||
};
|
||||
}, [exitRef]);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/** Vitrine única da home: recebe só projetos de cliente (o filtro vem de app/page.tsx). */
|
||||
export default function Projects({
|
||||
projects,
|
||||
}: {
|
||||
projects: PortfolioProjectView[];
|
||||
}) {
|
||||
const exitRef = useRef<HTMLDivElement>(null);
|
||||
const offset = useReelColumnOffset(exitRef);
|
||||
|
||||
return (
|
||||
<Section
|
||||
id="projects"
|
||||
@@ -26,7 +84,12 @@ export default function Projects({
|
||||
<ProjectReel />
|
||||
</ShowcaseProvider>
|
||||
|
||||
<div className="mt-sp-8" data-reel-stagger="left">
|
||||
<div
|
||||
ref={exitRef}
|
||||
className="mt-sp-8"
|
||||
data-reel-stagger="left"
|
||||
style={offset ? { paddingLeft: offset } : undefined}
|
||||
>
|
||||
<HoverPrefetchLink href="/cases" className={secondaryButtonDark}>
|
||||
Ver os cases
|
||||
</HoverPrefetchLink>
|
||||
|
||||
Reference in new issue
Block a user