feat(ui): add staggered entry animations using framer-motion and fix typography nesting
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { Badge, Card, Typography } from "poyraz-ui/atoms";
|
||||
import { Sheet, SheetContent, SheetTitle, SheetTrigger } from "poyraz-ui/molecules";
|
||||
import { StaggerContainer, StaggerItem } from "@/components/motion-wrapper";
|
||||
import { BOOKMARKS } from "@/data/bookmarks";
|
||||
import { certificates } from "@/data/certificates";
|
||||
import { EDUCATION } from "@/data/education";
|
||||
@@ -25,21 +26,23 @@ export function AboutContent() {
|
||||
</Card>
|
||||
|
||||
<div>
|
||||
<div className="grid gap-2">
|
||||
<StaggerContainer className="grid gap-2">
|
||||
{EDUCATION.map((item) => (
|
||||
<Card key={item.id} className="rounded-sm border-border p-3">
|
||||
<Typography variant="large" className="text-base leading-tight">
|
||||
{item.title}
|
||||
</Typography>
|
||||
<Typography variant="small" className="mt-0.5 text-muted-foreground">
|
||||
{item.institution}
|
||||
</Typography>
|
||||
<Typography variant="small" className="mt-1 text-red-600">
|
||||
{item.period}
|
||||
</Typography>
|
||||
</Card>
|
||||
<StaggerItem key={item.id}>
|
||||
<Card className="rounded-sm border-border p-3">
|
||||
<Typography variant="large" className="text-base leading-tight">
|
||||
{item.title}
|
||||
</Typography>
|
||||
<Typography variant="small" className="mt-0.5 text-muted-foreground">
|
||||
{item.institution}
|
||||
</Typography>
|
||||
<Typography variant="small" className="mt-1 text-red-600">
|
||||
{item.period}
|
||||
</Typography>
|
||||
</Card>
|
||||
</StaggerItem>
|
||||
))}
|
||||
</div>
|
||||
</StaggerContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -106,21 +109,23 @@ export function AboutContent() {
|
||||
</Sheet>
|
||||
|
||||
<div className="h-full">
|
||||
<div className="grid gap-2">
|
||||
<StaggerContainer className="grid gap-2">
|
||||
{EXPERIENCE.map((item) => (
|
||||
<Card key={item.id} className="rounded-sm border-border p-3">
|
||||
<Typography variant="large" className="text-base leading-tight">
|
||||
{item.role}
|
||||
</Typography>
|
||||
<Typography variant="small" className="mt-0.5 text-muted-foreground">
|
||||
{item.company}
|
||||
</Typography>
|
||||
<Typography variant="small" className="mt-1 text-red-600">
|
||||
{item.period}
|
||||
</Typography>
|
||||
</Card>
|
||||
<StaggerItem key={item.id}>
|
||||
<Card className="rounded-sm border-border p-3">
|
||||
<Typography variant="large" className="text-base leading-tight">
|
||||
{item.role}
|
||||
</Typography>
|
||||
<Typography variant="small" className="mt-0.5 text-muted-foreground">
|
||||
{item.company}
|
||||
</Typography>
|
||||
<Typography variant="small" className="mt-1 text-red-600">
|
||||
{item.period}
|
||||
</Typography>
|
||||
</Card>
|
||||
</StaggerItem>
|
||||
))}
|
||||
</div>
|
||||
</StaggerContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+18
-14
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { Badge, Card, Typography } from "poyraz-ui/atoms";
|
||||
import {
|
||||
@@ -10,6 +12,7 @@ import {
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
} from "poyraz-ui/molecules";
|
||||
import { StaggerContainer, StaggerItem } from "@/components/motion-wrapper";
|
||||
import type { BlogPageData } from "@/data/blog";
|
||||
|
||||
type BlogContentProps = {
|
||||
@@ -118,22 +121,23 @@ export function BlogContent({ data }: BlogContentProps) {
|
||||
|
||||
<div className="space-y-3">
|
||||
{hasArticles ? (
|
||||
<div className="grid gap-3 md:grid-cols-3">
|
||||
<StaggerContainer className="grid gap-3 md:grid-cols-3">
|
||||
{data.articles.map((post) => (
|
||||
<ArticleCard
|
||||
key={post.id}
|
||||
image={post.image}
|
||||
category={post.category}
|
||||
title={post.title}
|
||||
excerpt={post.excerpt}
|
||||
date={post.date}
|
||||
readTime={post.readTime}
|
||||
href={post.href}
|
||||
className="rounded-sm border-border [&_h3]:line-clamp-2 [&_h3]:min-h-[2.5rem]"
|
||||
author={{ name: post.author, avatar: "/logo/logo.jpeg" }}
|
||||
/>
|
||||
<StaggerItem key={post.id}>
|
||||
<ArticleCard
|
||||
image={post.image}
|
||||
category={post.category}
|
||||
title={post.title}
|
||||
excerpt={post.excerpt}
|
||||
date={post.date}
|
||||
readTime={post.readTime}
|
||||
href={post.href}
|
||||
className="rounded-sm border-border [&_h3]:line-clamp-2 [&_h3]:min-h-[2.5rem]"
|
||||
author={{ name: post.author, avatar: "/logo/logo.jpeg" }}
|
||||
/>
|
||||
</StaggerItem>
|
||||
))}
|
||||
</div>
|
||||
</StaggerContainer>
|
||||
) : (
|
||||
<Card className="rounded-sm border-border p-5">
|
||||
<Typography variant="p" className="text-muted-foreground">
|
||||
|
||||
+43
-43
@@ -4,6 +4,7 @@ import Image from "next/image";
|
||||
import { useRef, useState } from "react";
|
||||
import { Card, Typography } from "poyraz-ui/atoms";
|
||||
import { NewsCard } from "poyraz-ui/molecules";
|
||||
import { StaggerContainer, StaggerItem, FadeIn } from "@/components/motion-wrapper";
|
||||
|
||||
type HomeHeroProps = {
|
||||
news: {
|
||||
@@ -38,52 +39,51 @@ export function HomeHero({ news }: HomeHeroProps) {
|
||||
|
||||
return (
|
||||
<section className="grid gap-3 md:h-65 md:grid-cols-2">
|
||||
<div className="grid gap-2 md:grid-rows-3">
|
||||
<StaggerContainer className="grid gap-2 md:grid-rows-3">
|
||||
{news.map((item) => (
|
||||
<NewsCard
|
||||
key={item.id}
|
||||
className="rounded-sm border-border md:h-full"
|
||||
category={item.category}
|
||||
title={item.title}
|
||||
date={item.date}
|
||||
image={item.image}
|
||||
href={item.href}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Card className="grid grid-cols-[112px_1fr] items-stretch gap-2 rounded-sm border-border sm:grid-cols-[168px_1fr] md:h-full">
|
||||
<div className="flex flex-col justify-center gap-1 px-3 py-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<Typography variant="h2" className="leading-tight">
|
||||
Poyraz
|
||||
</Typography>
|
||||
<Typography variant="h2" secondaryFont className="leading-tight text-red-600">
|
||||
{" "}
|
||||
Avsever
|
||||
</Typography>
|
||||
</div>
|
||||
<Typography variant="small" className="text-muted-foreground">
|
||||
Teknolojiyi merak eden bir genç. Yazılım geliştirme, yapay zeka ve teknoloji dünyasındaki gelişmeleri takip ediyor.
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div className="relative h-full overflow-hidden">
|
||||
<div
|
||||
className="relative h-full w-full"
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<Image
|
||||
src={frame === 1 ? "/images/hero1.png" : "/images/hero2.png"}
|
||||
alt="Poyraz Avsever"
|
||||
width={240}
|
||||
height={240}
|
||||
className="absolute right-0 bottom-0 h-auto w-20 object-contain md:w-48"
|
||||
<StaggerItem key={item.id}>
|
||||
<NewsCard
|
||||
className="rounded-sm border-border md:h-full"
|
||||
category={item.category}
|
||||
title={item.title}
|
||||
date={item.date}
|
||||
image={item.image}
|
||||
href={item.href}
|
||||
/>
|
||||
</StaggerItem>
|
||||
))}
|
||||
</StaggerContainer>
|
||||
|
||||
<FadeIn delay={0.15}>
|
||||
<Card className="grid grid-cols-[112px_1fr] items-stretch gap-2 rounded-sm border-border sm:grid-cols-[168px_1fr] md:h-full">
|
||||
<div className="flex flex-col justify-center gap-1 px-3 py-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<Typography variant="h2" className="leading-tight">
|
||||
Poyraz <span className="font-secondary text-red-600">Avsever</span>
|
||||
</Typography>
|
||||
</div>
|
||||
<Typography variant="small" className="text-muted-foreground">
|
||||
Teknolojiyi merak eden bir genç. Yazılım geliştirme, yapay zeka ve teknoloji dünyasındaki gelişmeleri takip ediyor.
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<div className="relative h-full overflow-hidden">
|
||||
<div
|
||||
className="relative h-full w-full"
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<Image
|
||||
src={frame === 1 ? "/images/hero1.png" : "/images/hero2.png"}
|
||||
alt="Poyraz Avsever"
|
||||
width={240}
|
||||
height={240}
|
||||
className="absolute right-0 bottom-0 h-auto w-20 object-contain md:w-48"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</FadeIn>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
type FadeInProps = {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
delay?: number;
|
||||
};
|
||||
|
||||
export function FadeIn({ children, className, delay = 0 }: FadeInProps) {
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 12 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.35, delay, ease: "easeOut" }}
|
||||
className={className}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
type StaggerContainerProps = {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
stagger?: number;
|
||||
};
|
||||
|
||||
export function StaggerContainer({ children, className, stagger = 0.06 }: StaggerContainerProps) {
|
||||
return (
|
||||
<motion.div
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={{
|
||||
hidden: {},
|
||||
visible: { transition: { staggerChildren: stagger } },
|
||||
}}
|
||||
className={className}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
type StaggerItemProps = {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function StaggerItem({ children, className }: StaggerItemProps) {
|
||||
return (
|
||||
<motion.div
|
||||
variants={{
|
||||
hidden: { opacity: 0, y: 12 },
|
||||
visible: { opacity: 1, y: 0, transition: { duration: 0.35, ease: "easeOut" } },
|
||||
}}
|
||||
className={className}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import Link from "next/link";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { Badge, Card, Typography } from "poyraz-ui/atoms";
|
||||
import { ImageCard } from "poyraz-ui/molecules";
|
||||
import { StaggerContainer, StaggerItem } from "@/components/motion-wrapper";
|
||||
import { FIGMA_TEMPLATES, MOBILE_APPS, WEB_APPS, type ProjectItem } from "@/data/projects";
|
||||
import { getGithubRepos, getNpmPackages } from "@/lib/project-feeds";
|
||||
|
||||
@@ -43,19 +44,20 @@ function ProjectSection({ title, items }: { title: string; items: ProjectItem[]
|
||||
<Typography variant="large" className="text-base">
|
||||
{title}
|
||||
</Typography>
|
||||
<div className="grid grid-cols-2 gap-2 lg:grid-cols-4">
|
||||
<StaggerContainer className="grid grid-cols-2 gap-2 lg:grid-cols-4">
|
||||
{items.map((item) => (
|
||||
<ImageCard
|
||||
key={item.id}
|
||||
image={item.image}
|
||||
title={item.title}
|
||||
description={item.description}
|
||||
badge={item.badge}
|
||||
href={item.href}
|
||||
className="aspect-square rounded-sm border-border"
|
||||
/>
|
||||
<StaggerItem key={item.id}>
|
||||
<ImageCard
|
||||
image={item.image}
|
||||
title={item.title}
|
||||
description={item.description}
|
||||
badge={item.badge}
|
||||
href={item.href}
|
||||
className="aspect-square rounded-sm border-border"
|
||||
/>
|
||||
</StaggerItem>
|
||||
))}
|
||||
</div>
|
||||
</StaggerContainer>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user