1
0
forked from maik/IPFS-portal

feat: initial IPFS Portal — Next.js frontend for remote IPFS node management

Multi-file upload with Quick Upload + Crypto Payment tabs.
Dashboard with live IPFS metrics, Explorer, Peers, Pins, History, Settings pages.
Docker deploy (standalone output), full test suite (16 Playwright tests).
Payment integration via IPFSPortalPayment + MockUSDC contracts on zkSync.
This commit is contained in:
maikrolf
2026-06-25 19:47:57 +02:00
commit 1ddc89479c
42 changed files with 8383 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
'use client';
import { useState } from 'react';
import { CheckCircle, Pin } from 'lucide-react';
import { addPin } from '@/lib/api';
interface PinBadgeProps {
cid: string;
isPinned: boolean;
onPin: (cid: string) => void;
}
export default function PinBadge({ cid, isPinned, onPin }: PinBadgeProps) {
const [pinning, setPinning] = useState(false);
async function handlePin() {
setPinning(true);
try {
await addPin(cid);
onPin(cid);
} catch {
// pin failed silently
} finally {
setPinning(false);
}
}
if (isPinned) {
return (
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-accent-green/10 text-accent-green text-xs font-medium">
<CheckCircle className="w-3.5 h-3.5" />
Pinned
</span>
);
}
return (
<button
onClick={handlePin}
disabled={pinning}
className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg border border-surface-600 text-surface-300 text-xs font-medium hover:bg-surface-700 hover:border-surface-500 transition-colors disabled:opacity-50"
>
<Pin className="w-3.5 h-3.5" />
{pinning ? 'Pinning…' : 'Pin this CID'}
</button>
);
}