anky2002 commited on
Commit
3450e70
·
verified ·
1 Parent(s): 034a841

feat: add RelatedPrompts component for internal linking (SEO + engagement)

Browse files
src/components/prompts/related-prompts.tsx ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Link from "next/link"
2
+ import { Play, Star } from "lucide-react"
3
+ import { Card, CardContent } from "@/components/ui/card"
4
+ import { Badge } from "@/components/ui/badge"
5
+ import prisma from "@/lib/prisma"
6
+
7
+ interface RelatedPromptsProps {
8
+ currentSlug: string
9
+ category?: string | null
10
+ tags?: string[]
11
+ limit?: number
12
+ }
13
+
14
+ /**
15
+ * Displays related prompts based on same category/tags.
16
+ * Improves internal linking for SEO and user engagement.
17
+ */
18
+ export async function RelatedPrompts({
19
+ currentSlug,
20
+ category,
21
+ tags = [],
22
+ limit = 4,
23
+ }: RelatedPromptsProps) {
24
+ try {
25
+ // Find prompts in the same category or with overlapping tags
26
+ const relatedPrompts = await prisma.prompt.findMany({
27
+ where: {
28
+ visibility: 'public',
29
+ slug: { not: currentSlug },
30
+ OR: [
31
+ ...(category ? [{ category }] : []),
32
+ ...(tags.length > 0 ? [{ tags: { hasSome: tags } }] : []),
33
+ ],
34
+ },
35
+ select: {
36
+ slug: true,
37
+ title: true,
38
+ description: true,
39
+ category: true,
40
+ totalRuns: true,
41
+ starsCount: true,
42
+ creator: {
43
+ select: { name: true, username: true },
44
+ },
45
+ },
46
+ orderBy: { totalRuns: 'desc' },
47
+ take: limit,
48
+ })
49
+
50
+ if (relatedPrompts.length === 0) return null
51
+
52
+ return (
53
+ <section className="mt-12 pt-8 border-t border-border">
54
+ <h2 className="text-xl font-semibold mb-4">Related Prompts</h2>
55
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
56
+ {relatedPrompts.map((prompt) => (
57
+ <Link key={prompt.slug} href={`/p/${prompt.slug}`}>
58
+ <Card className="h-full group hover:border-primary/50 hover:shadow-md transition-all">
59
+ <CardContent className="p-4 flex flex-col h-full">
60
+ {prompt.category && (
61
+ <Badge variant="secondary" className="w-fit mb-2 text-xs">
62
+ {prompt.category}
63
+ </Badge>
64
+ )}
65
+ <h3 className="font-medium text-sm mb-1 group-hover:text-primary transition-colors line-clamp-2">
66
+ {prompt.title}
67
+ </h3>
68
+ <p className="text-xs text-muted-foreground mb-3 flex-1 line-clamp-2">
69
+ {prompt.description}
70
+ </p>
71
+ <div className="flex items-center gap-3 text-xs text-muted-foreground">
72
+ <span className="flex items-center gap-1">
73
+ <Play className="h-3 w-3" />
74
+ {prompt.totalRuns}
75
+ </span>
76
+ <span className="flex items-center gap-1">
77
+ <Star className="h-3 w-3" />
78
+ {prompt.starsCount}
79
+ </span>
80
+ </div>
81
+ </CardContent>
82
+ </Card>
83
+ </Link>
84
+ ))}
85
+ </div>
86
+ </section>
87
+ )
88
+ } catch (error) {
89
+ console.error('RelatedPrompts error:', error)
90
+ return null
91
+ }
92
+ }