Skip to content

Commit a233026

Browse files
committed
💄 Improve the looks of the featured jargons
1 parent 4aac74d commit a233026

File tree

3 files changed

+106
-73
lines changed

3 files changed

+106
-73
lines changed

app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export default async function Home({
8686
}));
8787

8888
return (
89-
<div className="mx-auto flex max-w-7xl flex-col gap-3">
89+
<div className="mx-auto flex max-w-7xl flex-col gap-8">
9090
<FeaturedJargonCarousel featuredJargons={featuredJargons} />
9191
<HomePageClient
9292
searchQuery={searchQuery}

components/home/featured-jargon-carousel.tsx

Lines changed: 81 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useRef, useState, useEffect } from "react";
44
import Autoplay from "embla-carousel-autoplay";
5-
import { Award } from "lucide-react";
5+
import { Sparkles } from "lucide-react";
66
import {
77
Carousel,
88
CarouselContent,
@@ -13,6 +13,7 @@ import {
1313
} from "@/components/ui/carousel";
1414
import { Skeleton } from "@/components/ui/skeleton";
1515
import JargonCard from "@/components/jargon/jargon-card";
16+
import { cn } from "@/lib/utils";
1617

1718
export type FeaturedJargonCarouselItem = {
1819
id: string;
@@ -26,8 +27,10 @@ export type FeaturedJargonCarouselItem = {
2627

2728
export default function FeaturedJargonCarousel({
2829
featuredJargons,
30+
className,
2931
}: {
3032
featuredJargons: FeaturedJargonCarouselItem[];
33+
className?: string;
3134
}) {
3235
const plugin = useRef(Autoplay({ delay: 2000, stopOnInteraction: true }));
3336
const [api, setApi] = useState<CarouselApi>();
@@ -53,70 +56,86 @@ export default function FeaturedJargonCarousel({
5356
}, [api]);
5457

5558
return (
56-
<div className="flex flex-col gap-3">
57-
<h2 className="flex items-center gap-2 text-lg font-bold">
58-
<Award className="h-5 w-5" />
59-
하이라이트
60-
</h2>
61-
<Carousel
62-
setApi={setApi}
63-
plugins={[plugin.current]}
64-
className="w-full"
65-
onMouseEnter={plugin.current.stop}
66-
onMouseLeave={plugin.current.reset}
67-
>
68-
<CarouselContent className="-ml-4">
69-
{featuredJargons.length > 0
70-
? featuredJargons.map((jargon) => (
71-
<CarouselItem
72-
key={jargon.id}
73-
className="basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4"
74-
>
75-
<JargonCard
76-
jargon={{
77-
id: jargon.id,
78-
name: jargon.name,
79-
slug: jargon.slug,
80-
translations: jargon.translation
81-
? [jargon.translation]
82-
: [],
83-
categories: jargon.categories,
84-
commentCount: jargon.comment_count,
85-
updatedAt: jargon.updated_at,
86-
}}
87-
/>
88-
</CarouselItem>
89-
))
90-
: Array.from({ length: 8 }).map((_, index) => (
91-
<CarouselItem
92-
key={index}
93-
className="basis-full md:basis-1/2 lg:basis-1/3 xl:basis-1/4"
94-
>
95-
<div className="bg-card text-card-foreground flex h-full flex-col gap-1 rounded-md p-3">
96-
{/* Category chips skeleton */}
97-
<div className="flex flex-wrap gap-2">
98-
<Skeleton className="h-5 w-12 rounded-full" />
99-
<Skeleton className="h-5 w-10 rounded-full" />
100-
</div>
101-
102-
{/* Name skeleton */}
103-
<Skeleton className="h-5 w-3/4" />
59+
<div
60+
className={cn(
61+
"relative rounded-xl border border-stone-300/50 bg-stone-100/30 p-4 dark:border-stone-700/40 dark:bg-stone-800/20",
62+
className,
63+
)}
64+
>
65+
<div className="flex flex-col gap-3">
66+
<h2 className="flex items-center gap-2 text-lg font-bold">
67+
<span className="text-stone-500 dark:text-stone-400">
68+
<Sparkles className="h-4 w-4" />
69+
</span>
70+
<span className="text-stone-800 dark:text-stone-100">하이라이트</span>
71+
</h2>
72+
<Carousel
73+
setApi={setApi}
74+
plugins={[plugin.current]}
75+
className="relative w-full"
76+
onMouseEnter={plugin.current.stop}
77+
onMouseLeave={plugin.current.reset}
78+
>
79+
{/* Left fade overlay */}
80+
{canScrollPrev && (
81+
<div className="pointer-events-none absolute top-0 left-0 z-10 h-full w-16 bg-gradient-to-r from-[#F6F1E9]/75 to-transparent dark:from-[#1E1B1A]" />
82+
)}
83+
{/* Right fade overlay */}
84+
{canScrollNext && (
85+
<div className="pointer-events-none absolute top-0 right-0 z-10 h-full w-16 bg-gradient-to-l from-[#F6F1E9]/75 to-transparent dark:from-[#1E1B1A]" />
86+
)}
87+
<CarouselContent className="-ml-3">
88+
{featuredJargons.length > 0
89+
? featuredJargons.map((jargon) => (
90+
<CarouselItem
91+
key={jargon.id}
92+
className="basis-full pl-3 md:basis-1/2 lg:basis-1/3 xl:basis-1/4"
93+
>
94+
<JargonCard
95+
jargon={{
96+
id: jargon.id,
97+
name: jargon.name,
98+
slug: jargon.slug,
99+
translations: jargon.translation
100+
? [jargon.translation]
101+
: [],
102+
categories: jargon.categories,
103+
commentCount: jargon.comment_count,
104+
updatedAt: jargon.updated_at,
105+
}}
106+
compact
107+
/>
108+
</CarouselItem>
109+
))
110+
: Array.from({ length: 8 }).map((_, index) => (
111+
<CarouselItem
112+
key={index}
113+
className="basis-full pl-3 md:basis-1/2 lg:basis-1/3 xl:basis-1/4"
114+
>
115+
<div className="bg-card text-card-foreground flex h-full flex-col gap-1 rounded-md p-3">
116+
{/* Name skeleton */}
117+
<Skeleton className="h-5 w-3/4" />
104118

105-
{/* Translation skeleton */}
106-
<Skeleton className="h-4 w-full" />
119+
{/* Translation skeleton */}
120+
<Skeleton className="h-4 w-full" />
107121

108-
{/* Footer skeleton (comment count + timestamp) */}
109-
<div className="mt-auto flex gap-1 self-end">
110-
<Skeleton className="h-4 w-12" />
111-
<Skeleton className="h-4 w-16" />
122+
{/* Footer skeleton (comment count + timestamp) */}
123+
<div className="mt-auto flex gap-1 self-end">
124+
<Skeleton className="h-4 w-12" />
125+
<Skeleton className="h-4 w-16" />
126+
</div>
112127
</div>
113-
</div>
114-
</CarouselItem>
115-
))}
116-
</CarouselContent>
117-
{canScrollPrev && <CarouselPrevious className="left-1" />}
118-
{canScrollNext && <CarouselNext className="right-1" />}
119-
</Carousel>
128+
</CarouselItem>
129+
))}
130+
</CarouselContent>
131+
{canScrollPrev && (
132+
<CarouselPrevious className="left-2 z-20 border-stone-200 bg-white hover:bg-stone-50 dark:border-stone-700 dark:bg-stone-900 dark:hover:bg-stone-800" />
133+
)}
134+
{canScrollNext && (
135+
<CarouselNext className="right-2 z-20 border-stone-200 bg-white hover:bg-stone-50 dark:border-stone-700 dark:bg-stone-900 dark:hover:bg-stone-800" />
136+
)}
137+
</Carousel>
138+
</div>
120139
</div>
121140
);
122141
}

components/jargon/jargon-card.tsx

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import relativeTime from "dayjs/plugin/relativeTime";
55
import "dayjs/locale/ko";
66
import { MessageCircle } from "lucide-react";
77
import Link from "next/link";
8+
import { cn } from "@/lib/utils";
89

910
dayjs.extend(relativeTime);
1011
dayjs.locale("ko");
@@ -21,14 +22,25 @@ export interface JargonData {
2122

2223
interface JargonCardProps {
2324
jargon: JargonData;
25+
className?: string;
26+
compact?: boolean;
2427
}
2528

26-
export default function JargonCard({ jargon }: JargonCardProps) {
29+
export default function JargonCard({
30+
jargon,
31+
className,
32+
compact = false,
33+
}: JargonCardProps) {
2734
return (
2835
<Link href={`/jargon/${jargon.slug}`}>
29-
<div className="hover:bg-accent bg-card text-card-foreground flex h-full cursor-pointer flex-col gap-1 rounded-md p-3 transition-all duration-200">
36+
<div
37+
className={cn(
38+
"hover:bg-accent bg-card text-card-foreground flex h-full cursor-pointer flex-col gap-1 rounded-md p-3 transition-all duration-200",
39+
className,
40+
)}
41+
>
3042
{/* categories */}
31-
{jargon.categories.length > 0 ? (
43+
{!compact && jargon.categories.length > 0 ? (
3244
<div className="flex flex-wrap gap-2">
3345
{jargon.categories.map((cat) => (
3446
<span
@@ -52,13 +64,15 @@ export default function JargonCard({ jargon }: JargonCardProps) {
5264
</p>
5365

5466
{/* comment count · last updated */}
55-
<div className="text-muted-foreground mt-auto flex gap-1 self-end text-sm">
56-
<span className="flex items-center gap-0.5">
57-
<MessageCircle className="mb-[-1.5] inline size-3.5" />
58-
{jargon.commentCount}
59-
</span>
60-
·<span>{dayjs(jargon.updatedAt).fromNow()}</span>
61-
</div>
67+
{!compact && (
68+
<div className="text-muted-foreground mt-auto flex gap-1 self-end text-sm">
69+
<span className="flex items-center gap-0.5">
70+
<MessageCircle className="mb-[-1.5] inline size-3.5" />
71+
{jargon.commentCount}
72+
</span>
73+
·<span>{dayjs(jargon.updatedAt).fromNow()}</span>
74+
</div>
75+
)}
6276
</div>
6377
</Link>
6478
);

0 commit comments

Comments
 (0)