153 lines
5.2 KiB
TypeScript
153 lines
5.2 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect, use } from 'react';
|
|
import Link from 'next/link';
|
|
import { getPromptBySlug } from '@/lib/actions/promptActions';
|
|
import { ArrowLeft, Copy, Check, Sparkles, Tag, Share2 } from 'lucide-react';
|
|
|
|
export default function PromptDetailPage({ params }: { params: Promise<{ locale: string; slug: string }> }) {
|
|
const { locale, slug } = use(params);
|
|
const [prompt, setPrompt] = useState<any>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [copied, setCopied] = useState(false);
|
|
const [copiedLink, setCopiedLink] = useState(false);
|
|
|
|
useEffect(() => {
|
|
async function loadData() {
|
|
setLoading(true);
|
|
const res = await getPromptBySlug(slug);
|
|
setPrompt(res);
|
|
setLoading(false);
|
|
}
|
|
loadData();
|
|
}, [slug]);
|
|
|
|
const handleCopyPrompt = async () => {
|
|
if (!prompt) return;
|
|
try {
|
|
await navigator.clipboard.writeText(prompt.content);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
} catch (err) {
|
|
console.error('Copy error:', err);
|
|
}
|
|
};
|
|
|
|
const handleShare = async () => {
|
|
try {
|
|
await navigator.clipboard.writeText(window.location.href);
|
|
setCopiedLink(true);
|
|
setTimeout(() => setCopiedLink(false), 2000);
|
|
} catch (err) {
|
|
console.error('Share error:', err);
|
|
}
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="max-w-7xl mx-auto px-4 py-24 text-center text-slate-400 flex flex-col items-center justify-center gap-3">
|
|
<p className="text-sm font-semibold">Loading prompt...</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!prompt) {
|
|
return (
|
|
<div className="max-w-7xl mx-auto px-4 py-24 text-center space-y-4">
|
|
<h1 className="text-2xl font-bold text-white">Prompt Not Found</h1>
|
|
<Link href={`/${locale}/prompts`} className="text-xs font-bold text-red-400 hover:underline">
|
|
← Back to Prompts Library
|
|
</Link>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-10 space-y-8 flex-1 w-full">
|
|
|
|
{/* Navigation & Share Bar */}
|
|
<div className="flex items-center justify-between gap-4">
|
|
<Link
|
|
href={`/${locale}/prompts`}
|
|
className="flex items-center gap-1.5 px-3.5 py-2 rounded-xl bg-slate-900 hover:bg-slate-800 text-slate-300 text-xs font-bold border border-slate-800 transition-colors"
|
|
>
|
|
<ArrowLeft className="w-4 h-4" />
|
|
<span>Back to Prompts</span>
|
|
</Link>
|
|
|
|
<button
|
|
onClick={handleShare}
|
|
className="flex items-center gap-1.5 px-3 py-1.5 rounded-xl bg-slate-900 hover:bg-slate-800 text-slate-300 text-xs font-semibold border border-slate-800 transition-colors"
|
|
>
|
|
{copiedLink ? (
|
|
<>
|
|
<Check className="w-3.5 h-3.5 text-emerald-400" />
|
|
<span className="text-emerald-400">Link Copied</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Share2 className="w-3.5 h-3.5 text-slate-400" />
|
|
<span>Share Prompt</span>
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
|
|
{/* Header Banner */}
|
|
<div className="p-8 rounded-3xl bg-gradient-to-br from-slate-900 via-slate-950 to-slate-900 border border-slate-800 space-y-4 shadow-2xl">
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<span className="text-xs font-bold text-red-400 bg-red-500/10 px-3 py-1 rounded-full border border-red-500/20">
|
|
{prompt.category}
|
|
</span>
|
|
|
|
{prompt.tags?.map((t: string) => (
|
|
<span key={t} className="text-[11px] text-slate-400 px-2.5 py-0.5 rounded-full bg-slate-800 border border-slate-700">
|
|
#{t}
|
|
</span>
|
|
))}
|
|
</div>
|
|
|
|
<h1 className="text-3xl sm:text-4xl font-extrabold text-white tracking-tight leading-snug">
|
|
{prompt.title}
|
|
</h1>
|
|
|
|
<p className="text-sm text-slate-400 max-w-3xl leading-relaxed">
|
|
{prompt.description}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Full Prompt Container */}
|
|
<div className="p-6 sm:p-8 rounded-3xl bg-slate-900/60 border border-slate-800 space-y-4 shadow-2xl">
|
|
<div className="flex items-center justify-between">
|
|
<h2 className="text-base font-bold text-white flex items-center gap-2">
|
|
<Sparkles className="w-4 h-4 text-red-400" />
|
|
<span>AI System Prompt Content</span>
|
|
</h2>
|
|
|
|
<button
|
|
onClick={handleCopyPrompt}
|
|
className="px-4 py-2 bg-red-600 hover:bg-red-500 text-white text-xs font-bold rounded-xl flex items-center gap-2 shadow-lg shadow-red-600/30 transition-all"
|
|
>
|
|
{copied ? (
|
|
<>
|
|
<Check className="w-4 h-4 text-emerald-300" />
|
|
<span>Copied to Clipboard!</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Copy className="w-4 h-4" />
|
|
<span>Copy Full Prompt</span>
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
|
|
<div className="p-6 bg-slate-950 rounded-2xl border border-slate-800 font-mono text-xs text-slate-200 leading-relaxed overflow-x-auto">
|
|
<pre className="whitespace-pre-wrap">{prompt.content}</pre>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
);
|
|
}
|