chrysopedia/frontend/src/components/CopyLinkButton.tsx
jlightner 4b0914b12b fix: restore complete project tree from ub01 canonical state
Auto-mode commit 7aa33cd accidentally deleted 78 files (14,814 lines) during M005
execution. Subsequent commits rebuilt some frontend files but backend/, alembic/,
tests/, whisper/, docker configs, and prompts were never restored in this repo.

This commit restores the full project tree by syncing from ub01's working directory,
which has all M001-M007 features running in production containers.

Restored: backend/ (config, models, routers, database, redis, search_service, worker),
alembic/ (6 migrations), docker/ (Dockerfiles, nginx, compose), prompts/ (4 stages),
tests/, whisper/, README.md, .env.example, chrysopedia-spec.md
2026-03-31 02:10:41 +00:00

58 lines
1.9 KiB
TypeScript

/**
* Inline copy-link button — click to copy the current page URL.
* Shows a brief "Copied" tooltip on success.
* Styled as a subtle icon that appears on hover of the parent.
*/
import { useState, useCallback } from "react";
interface CopyLinkButtonProps {
url?: string; // defaults to window.location.href
className?: string;
}
export default function CopyLinkButton({ url, className = "" }: CopyLinkButtonProps) {
const [copied, setCopied] = useState(false);
const handleCopy = useCallback(async (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
const target = url || window.location.href;
try {
await navigator.clipboard.writeText(target);
} catch {
// Fallback for non-HTTPS
const ta = document.createElement("textarea");
ta.value = target;
ta.style.position = "fixed";
ta.style.opacity = "0";
document.body.appendChild(ta);
ta.select();
document.execCommand("copy");
document.body.removeChild(ta);
}
setCopied(true);
setTimeout(() => setCopied(false), 1500);
}, [url]);
return (
<button
className={`copy-link-btn ${className}`}
onClick={handleCopy}
title="Copy link"
aria-label="Copy link to clipboard"
>
{copied ? (
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polyline points="20 6 9 17 4 12" />
</svg>
) : (
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
</svg>
)}
{copied && <span className="copy-link-btn__tooltip">Copied</span>}
</button>
);
}