Skip to content

Commit 8825071

Browse files
Merge pull request #9 from frontChapter/tweet-cards
Add Tweet cards
2 parents a9beae7 + 81bf543 commit 8825071

File tree

13 files changed

+501
-251
lines changed

13 files changed

+501
-251
lines changed

.all-contributorsrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@
4040
]
4141
}
4242
]
43-
}
43+
}

next.config.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import type { NextConfig } from "next";
22

33
const nextConfig: NextConfig = {
4-
/* config options here */
4+
images: {
5+
remotePatterns: [
6+
{
7+
protocol: "https",
8+
hostname: "avatar.vercel.sh",
9+
port: "",
10+
pathname: "**",
11+
},
12+
],
13+
},
514
};
615

716
export default nextConfig;

pnpm-lock.yaml

Lines changed: 241 additions & 248 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
27.5 KB
Loading
18 KB
Loading
326 KB
Loading
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { cn } from "@/lib/utils";
2+
import { ComponentPropsWithoutRef } from "react";
3+
4+
interface MarqueeProps extends ComponentPropsWithoutRef<"div"> {
5+
/**
6+
* Optional CSS class name to apply custom styles
7+
*/
8+
className?: string;
9+
/**
10+
* Whether to reverse the animation direction
11+
* @default false
12+
*/
13+
reverse?: boolean;
14+
/**
15+
* Whether to pause the animation on hover
16+
* @default false
17+
*/
18+
pauseOnHover?: boolean;
19+
/**
20+
* Content to be displayed in the marquee
21+
*/
22+
children: React.ReactNode;
23+
/**
24+
* Whether to animate vertically instead of horizontally
25+
* @default false
26+
*/
27+
vertical?: boolean;
28+
/**
29+
* Number of times to repeat the content
30+
* @default 4
31+
*/
32+
repeat?: number;
33+
}
34+
35+
export function Marquee({
36+
className,
37+
reverse = false,
38+
pauseOnHover = false,
39+
children,
40+
vertical = false,
41+
repeat = 4,
42+
...props
43+
}: MarqueeProps) {
44+
return (
45+
<div
46+
{...props}
47+
className={cn(
48+
"group flex overflow-hidden p-2 [--duration:40s] [--gap:1rem] [gap:var(--gap)]",
49+
{
50+
"flex-row": !vertical,
51+
"flex-col": vertical,
52+
},
53+
className,
54+
)}
55+
>
56+
{Array(repeat)
57+
.fill(0)
58+
.map((_, i) => (
59+
<div
60+
key={i}
61+
className={cn("flex shrink-0 justify-around [gap:var(--gap)]", {
62+
"animate-marquee flex-row": !vertical,
63+
"animate-marquee-vertical flex-col": vertical,
64+
"group-hover:[animation-play-state:paused]": pauseOnHover,
65+
"[animation-direction:reverse]": reverse,
66+
})}
67+
>
68+
{children}
69+
</div>
70+
))}
71+
</div>
72+
);
73+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { cn } from "@/lib/utils";
2+
import Image from "next/image";
3+
4+
const TweetCard = ({
5+
img,
6+
name,
7+
username,
8+
body,
9+
}: {
10+
img: string;
11+
name: string;
12+
username: string;
13+
body: string;
14+
}) => {
15+
return (
16+
<figure
17+
dir="rtl"
18+
className={cn(
19+
"relative w-96 cursor-pointer overflow-hidden rounded-xl border p-4",
20+
// light styles
21+
"border-gray-950/[.1] bg-gray-950/[.01] hover:bg-gray-950/[.05]",
22+
// dark styles
23+
"dark:border-gray-50/[.1] dark:bg-gray-50/[.10] dark:hover:bg-gray-50/[.15]",
24+
)}
25+
>
26+
<div className="flex flex-row items-center gap-2">
27+
<Image
28+
className="rounded-full"
29+
width="32"
30+
height="32"
31+
alt=""
32+
src={img}
33+
/>
34+
<div className="flex flex-col">
35+
<figcaption className="text-sm font-medium dark:text-white">
36+
{name}
37+
</figcaption>
38+
<p className="text-xs font-medium dark:text-white/40">{username}</p>
39+
</div>
40+
</div>
41+
<blockquote className="mt-2 text-sm">{body}</blockquote>
42+
</figure>
43+
);
44+
};
45+
46+
export default TweetCard;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Marquee } from "./Marquee";
2+
import TweetCard from "./TweetCard";
3+
import { Section } from "@/components/ui/section";
4+
import { firstMarqueetweetsData, secondMarqueetweetsData } from "@/configs/tweetsData";
5+
6+
const TweetSection = () => {
7+
return (
8+
<Section className="md:px-0">
9+
<div className="flex flex-col items-center gap-12">
10+
<h2 className="text-center text-3xl font-semibold text-foreground dark:text-foreground-dark sm:text-5xl">
11+
درمورد <span className="text-orange-500">فرانت چپتر</span> چی
12+
می&#8202;گن؟
13+
</h2>
14+
<div className="relative flex w-full flex-col items-center justify-center overflow-hidden rounded-lg md:shadow-xl">
15+
<Marquee reverse pauseOnHover className="[--duration:50s]">
16+
{firstMarqueetweetsData.map((review, index) => (
17+
<TweetCard key={index} {...review} />
18+
))}
19+
</Marquee>
20+
<Marquee pauseOnHover className="[--duration:50s]">
21+
{secondMarqueetweetsData.map((review, index) => (
22+
<TweetCard key={index} {...review} />
23+
))}
24+
</Marquee>
25+
<div className="pointer-events-none absolute inset-y-0 left-0 w-1/3 bg-gradient-to-r from-white dark:from-foreground"></div>
26+
<div className="pointer-events-none absolute inset-y-0 right-0 w-1/3 bg-gradient-to-l from-white dark:from-foreground"></div>
27+
</div>
28+
</div>
29+
</Section>
30+
);
31+
};
32+
33+
export default TweetSection;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export type TweetDataType = {
2+
name: string;
3+
username: string;
4+
body: string;
5+
img: string;
6+
};

0 commit comments

Comments
 (0)