yeas
This commit is contained in:
2
posts/pinned.json
Normal file
2
posts/pinned.json
Normal file
@@ -0,0 +1,2 @@
|
||||
[
|
||||
]
|
||||
@@ -61,6 +61,7 @@ export default function AdminPage() {
|
||||
}
|
||||
return [];
|
||||
});
|
||||
const [pinFeedback, setPinFeedback] = useState<string | null>(null);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -300,14 +301,45 @@ export default function AdminPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handlePin = (slug: string) => {
|
||||
setPinned((prev) =>
|
||||
prev.includes(slug) ? prev.filter((s) => s !== slug) : [slug, ...prev]
|
||||
);
|
||||
const handlePin = async (slug: string) => {
|
||||
setPinned((prev) => {
|
||||
const newPinned = prev.includes(slug)
|
||||
? prev.filter((s) => s !== slug)
|
||||
: [slug, ...prev];
|
||||
// Update pinned.json on the server
|
||||
fetch('/api/admin/posts', {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ pinned: newPinned }),
|
||||
})
|
||||
.then((res) => {
|
||||
if (!res.ok) {
|
||||
res.json().then((data) => {
|
||||
setPinFeedback(data.error || 'Failed to update pinned posts');
|
||||
});
|
||||
} else {
|
||||
setPinFeedback(
|
||||
newPinned.includes(slug)
|
||||
? 'Post pinned!'
|
||||
: 'Post unpinned!'
|
||||
);
|
||||
setTimeout(() => setPinFeedback(null), 2000);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setPinFeedback('Failed to update pinned posts');
|
||||
});
|
||||
return newPinned;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 p-8">
|
||||
{pinFeedback && (
|
||||
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 bg-blue-600 text-white px-6 py-2 rounded shadow-lg z-50">
|
||||
{pinFeedback}
|
||||
</div>
|
||||
)}
|
||||
{!isAuthenticated ? (
|
||||
<div className="max-w-md mx-auto bg-white p-8 rounded-lg shadow-md">
|
||||
<h1 className="text-2xl font-bold mb-6">Admin Login</h1>
|
||||
@@ -598,10 +630,15 @@ export default function AdminPage() {
|
||||
key={post.slug}
|
||||
className={`border rounded-lg p-3 flex items-center gap-3 justify-between ${pinned.includes(post.slug) ? 'bg-yellow-100 border-yellow-400' : ''}`}
|
||||
>
|
||||
<div className="flex-1 text-left">
|
||||
<div className="font-semibold">{post.title}</div>
|
||||
<div className="text-xs text-gray-500">{post.date}</div>
|
||||
<div className="text-xs text-gray-400">{post.summary}</div>
|
||||
<div className="flex-1 text-left flex items-center gap-2">
|
||||
{pinned.includes(post.slug) && (
|
||||
<span title="Pinned" className="text-xl">📌</span>
|
||||
)}
|
||||
<div>
|
||||
<div className="font-semibold">{post.title}</div>
|
||||
<div className="text-xs text-gray-500">{post.date}</div>
|
||||
<div className="text-xs text-gray-400">{post.summary}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handlePin(post.slug)}
|
||||
|
||||
@@ -36,4 +36,23 @@ export async function POST(request: Request) {
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function PATCH(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { pinned } = body; // expects an array of slugs
|
||||
if (!Array.isArray(pinned)) {
|
||||
return NextResponse.json({ error: 'Invalid pinned data' }, { status: 400 });
|
||||
}
|
||||
const pinnedPath = path.join(postsDirectory, 'pinned.json');
|
||||
fs.writeFileSync(pinnedPath, JSON.stringify(pinned, null, 2), 'utf8');
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Error updating pinned.json:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Error updating pinned.json' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user