feat(showcase): vitrine animada presa na rolagem, com capitulos e celular sincronizado
Abaixo dos cards, uma cena sticky em que o site de cada projeto rola dentro de um notebook (com um celular ao lado) conforme a pagina rola. Cada projeto tem um trecho com pausa no comeco e no fim; capitulos nomeiam o que esta na tela, levam ao ponto do video e mantem notebook e celular no mesmo trecho do site. So o projeto em cena e os vizinhos baixam video (nada com economizar dados ligado, e o notebook escondido no celular nao baixa). Um bloco da mesma altura segura o lugar antes de montar, para saltos como #contact cairem certo. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
a1a1e91135
commit
540fe9f87a
3 files changed
+1066
-112
No files matched your search
+124
-112
@@ -8,6 +8,8 @@ import { DrawLine } from "./animations/DrawLine";
|
||||
import MagneticButton from "./cinematic/MagneticButton";
|
||||
import { ProjectCover } from "./ProjectCover";
|
||||
import { Section } from "./Section";
|
||||
import { ProjectReel } from "./showcase/ProjectReel";
|
||||
import { ShowcaseProvider } from "./showcase/ShowcaseProvider";
|
||||
|
||||
export default function Projects({
|
||||
projects,
|
||||
@@ -36,129 +38,139 @@ export default function Projects({
|
||||
dark
|
||||
disableChildrenAnimation
|
||||
>
|
||||
<div className="ds-grid-fluid">
|
||||
{projects.map((project) => {
|
||||
const caseStudy = caseStudies.find(
|
||||
(entry) => entry.id === project.id,
|
||||
);
|
||||
return (
|
||||
<motion.article
|
||||
key={project.id}
|
||||
className="ds-card h-full"
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true, amount: "some" }}
|
||||
variants={cardVariants}
|
||||
whileHover={
|
||||
shouldReduceMotion
|
||||
? undefined
|
||||
: {
|
||||
y: -4,
|
||||
boxShadow: "0 20px 44px rgba(0, 0, 0, 0.42)",
|
||||
}
|
||||
}
|
||||
whileTap={shouldReduceMotion ? undefined : { scale: 0.99 }}
|
||||
transition={{ type: "spring", stiffness: 170, damping: 18 }}
|
||||
>
|
||||
<ProjectCover project={project} />
|
||||
<div className="flex flex-wrap items-start justify-between gap-sp-6">
|
||||
<div className="max-w-[560px]">
|
||||
<div className="ds-kicker">{project.category}</div>
|
||||
<DrawLine delay={0.05} />
|
||||
<h3 className="ds-card-title">{project.title}</h3>
|
||||
{project.subtitle && (
|
||||
<p className="mt-sp-3 text-[13px] leading-6 text-[rgba(255,255,255,.56)]">
|
||||
{project.subtitle}
|
||||
</p>
|
||||
)}
|
||||
<ShowcaseProvider projects={projects}>
|
||||
<div className="ds-grid-fluid">
|
||||
{projects.map((project) => {
|
||||
const caseStudy = caseStudies.find(
|
||||
(entry) => entry.id === project.id,
|
||||
);
|
||||
return (
|
||||
<motion.article
|
||||
key={project.id}
|
||||
className="ds-card h-full"
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true, amount: "some" }}
|
||||
variants={cardVariants}
|
||||
whileHover={
|
||||
shouldReduceMotion
|
||||
? undefined
|
||||
: {
|
||||
y: -4,
|
||||
boxShadow: "0 20px 44px rgba(0, 0, 0, 0.42)",
|
||||
}
|
||||
}
|
||||
whileTap={shouldReduceMotion ? undefined : { scale: 0.99 }}
|
||||
transition={{ type: "spring", stiffness: 170, damping: 18 }}
|
||||
>
|
||||
<ProjectCover project={project} />
|
||||
<div className="flex flex-wrap items-start justify-between gap-sp-6">
|
||||
<div className="max-w-[560px]">
|
||||
<div className="ds-kicker">{project.category}</div>
|
||||
<DrawLine delay={0.05} />
|
||||
<h3 className="ds-card-title">{project.title}</h3>
|
||||
{project.subtitle && (
|
||||
<p className="mt-sp-3 text-[13px] leading-6 text-[rgba(255,255,255,.56)]">
|
||||
{project.subtitle}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<MagneticButton
|
||||
as="span"
|
||||
className="ds-tag"
|
||||
strength={0.15}
|
||||
wrapperClassName="shrink-0 max-sm:ml-auto"
|
||||
>
|
||||
{project.status}
|
||||
</MagneticButton>
|
||||
</div>
|
||||
<MagneticButton
|
||||
as="span"
|
||||
className="ds-tag"
|
||||
strength={0.15}
|
||||
wrapperClassName="shrink-0 max-sm:ml-auto"
|
||||
>
|
||||
{project.status}
|
||||
</MagneticButton>
|
||||
</div>
|
||||
|
||||
<p className="ds-copy">
|
||||
{caseStudy?.summary ?? project.description}
|
||||
</p>
|
||||
{caseStudy && (
|
||||
<div className="mt-sp-4 border-l border-[var(--slash)] pl-sp-4">
|
||||
<p className="ds-kicker">O desafio</p>
|
||||
<p className="ds-copy">{caseStudy.impact}</p>
|
||||
</div>
|
||||
)}
|
||||
{caseStudy?.role && (
|
||||
<div className="mt-sp-4 border-l border-[var(--slash)] pl-sp-4">
|
||||
<p className="ds-kicker">Minha participação</p>
|
||||
<p className="ds-copy">{caseStudy.role}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ul className="ds-tags mt-sp-6" data-reel-stagger="fade">
|
||||
{project.technologies.slice(0, 5).map((tech) => (
|
||||
<li key={tech} className="ds-tag">
|
||||
{tech}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<div className="mt-sp-6 flex flex-wrap gap-sp-3" data-reel="top">
|
||||
<p className="ds-copy">
|
||||
{caseStudy?.summary ?? project.description}
|
||||
</p>
|
||||
{caseStudy && (
|
||||
<MagneticButton
|
||||
as="a"
|
||||
href={`/cases/${caseStudy.id}`}
|
||||
className="ds-link ds-link-accent"
|
||||
strength={0.2}
|
||||
>
|
||||
Entender a solução
|
||||
</MagneticButton>
|
||||
<div className="mt-sp-4 border-l border-[var(--slash)] pl-sp-4">
|
||||
<p className="ds-kicker">O desafio</p>
|
||||
<p className="ds-copy">{caseStudy.impact}</p>
|
||||
</div>
|
||||
)}
|
||||
{project.githubUrl && (
|
||||
<MagneticButton
|
||||
as="a"
|
||||
href={project.githubUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="ds-link ds-link-muted"
|
||||
strength={0.25}
|
||||
>
|
||||
Ver codigo
|
||||
</MagneticButton>
|
||||
{caseStudy?.role && (
|
||||
<div className="mt-sp-4 border-l border-[var(--slash)] pl-sp-4">
|
||||
<p className="ds-kicker">Minha participação</p>
|
||||
<p className="ds-copy">{caseStudy.role}</p>
|
||||
</div>
|
||||
)}
|
||||
{project.demoUrl &&
|
||||
(project.demoAvailability === "available" ||
|
||||
project.demoAvailability === "unknown") && (
|
||||
|
||||
<ul className="ds-tags mt-sp-6" data-reel-stagger="fade">
|
||||
{project.technologies.slice(0, 5).map((tech) => (
|
||||
<li key={tech} className="ds-tag">
|
||||
{tech}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<div
|
||||
className="mt-sp-6 flex flex-wrap gap-sp-3"
|
||||
data-reel="top"
|
||||
>
|
||||
{caseStudy && (
|
||||
<MagneticButton
|
||||
as="a"
|
||||
href={project.demoUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={`/cases/${caseStudy.id}`}
|
||||
className="ds-link ds-link-accent"
|
||||
strength={0.25}
|
||||
strength={0.2}
|
||||
>
|
||||
Abrir projeto
|
||||
{project.demoAvailability === "unknown" && (
|
||||
<span className="sr-only">
|
||||
{" "}
|
||||
Disponibilidade não verificada
|
||||
</span>
|
||||
)}
|
||||
Entender a solução
|
||||
</MagneticButton>
|
||||
)}
|
||||
{project.demoAvailability === "unavailable" && (
|
||||
<span className="ds-link ds-link-accent" aria-disabled="true">
|
||||
Demo indisponível na última verificação
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</motion.article>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{project.githubUrl && (
|
||||
<MagneticButton
|
||||
as="a"
|
||||
href={project.githubUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="ds-link ds-link-muted"
|
||||
strength={0.25}
|
||||
>
|
||||
Ver codigo
|
||||
</MagneticButton>
|
||||
)}
|
||||
{project.demoUrl &&
|
||||
(project.demoAvailability === "available" ||
|
||||
project.demoAvailability === "unknown") && (
|
||||
<MagneticButton
|
||||
as="a"
|
||||
href={project.demoUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="ds-link ds-link-accent"
|
||||
strength={0.25}
|
||||
>
|
||||
Abrir projeto
|
||||
{project.demoAvailability === "unknown" && (
|
||||
<span className="sr-only">
|
||||
{" "}
|
||||
Disponibilidade não verificada
|
||||
</span>
|
||||
)}
|
||||
</MagneticButton>
|
||||
)}
|
||||
{project.demoAvailability === "unavailable" && (
|
||||
<span
|
||||
className="ds-link ds-link-accent"
|
||||
aria-disabled="true"
|
||||
>
|
||||
Demo indisponível na última verificação
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</motion.article>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<ProjectReel />
|
||||
</ShowcaseProvider>
|
||||
|
||||
<div className="mt-sp-8 flex flex-wrap gap-sp-3" data-reel-stagger="left">
|
||||
<MagneticButton
|
||||
|
||||
Reference in new issue
Block a user