← snapshot
1170 bytes
"use client";
import Link from "next/link";
import { useState } from "react";
const PREFIX_LEN = 12;
/**
* A content address, shown short, carried full. Short forms are display
* only — never compare them — so the full id rides in the title and the
* clipboard.
*/
export function IdChip({
id,
kind,
href,
}: {
id: string;
/** Display prefix: snap, dec, att, tree, blob. */
kind?: string;
href?: string;
}) {
const [copied, setCopied] = useState(false);
const short = `${kind ? `${kind}:` : ""}${id.slice(0, PREFIX_LEN)}`;
async function copy() {
try {
await navigator.clipboard.writeText(id);
setCopied(true);
setTimeout(() => setCopied(false), 1200);
} catch {
// clipboard unavailable — the title still shows the full id
}
}
if (href) {
return (
<Link href={href} className="jac-chip" title={id}>
{short}
</Link>
);
}
return (
<button type="button" className="jac-chip" title={`${id} — click to copy`} onClick={copy}>
{short}
<span className="jac-small" aria-live="polite">
{copied ? "copied" : ""}
</span>
</button>
);
}