Files
wehub-resource-sync e30e75b5d4
Code Quality / Oxlint + Oxfmt (push) Waiting to run
Code Quality / Template Sync (push) Waiting to run
Code Quality / Build Changed Packages (push) Waiting to run
Code Quality / Test Changed Packages (push) Waiting to run
Deploy Expo Example / Deploy Production (push) Waiting to run
Deploy Ink Example / Deploy Production (push) Waiting to run
Python Tests / pytest (assistant-stream, 3.10) (push) Waiting to run
Python Tests / pytest (assistant-stream, 3.12) (push) Waiting to run
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Waiting to run
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Waiting to run
Deploy Shadcn Registry / Deploy Production (push) Waiting to run
Template Metrics / LOC + Bundle Size (push) Waiting to run
Changesets / Create Version PR (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:40:13 +08:00

80 lines
2.2 KiB
TypeScript

"use client";
import { useState, useCallback } from "react";
import { Check, Link2 } from "lucide-react";
import { cn } from "@/lib/utils";
import { analytics } from "@/lib/analytics";
interface ShareButtonProps {
className?: string;
}
export function ShareButton({ className }: ShareButtonProps) {
const [copied, setCopied] = useState(false);
const handleShare = useCallback(async () => {
analytics.builder.shareClicked();
const url = window.location.href;
// Try Web Share API on mobile
if (navigator.share && /mobile|android/i.test(navigator.userAgent)) {
try {
await navigator.share({
title: "assistant-ui Playground",
text: "Check out my chat UI configuration",
url,
});
return;
} catch {
// User cancelled or not supported, fall through to copy
}
}
// Copy to clipboard
try {
await navigator.clipboard.writeText(url);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
// Fallback for older browsers
const textArea = document.createElement("textarea");
textArea.value = url;
textArea.style.position = "fixed";
textArea.style.left = "-9999px";
document.body.appendChild(textArea);
textArea.select();
document.execCommand("copy");
document.body.removeChild(textArea);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
}, []);
return (
<button
type="button"
onClick={handleShare}
className={cn(
"flex items-center gap-1.5 rounded-md px-2.5 py-1 text-xs font-medium transition-colors",
copied
? "bg-green-500/10 text-green-600 dark:text-green-400"
: "text-muted-foreground hover:text-foreground",
className,
)}
title={copied ? "Link copied to clipboard" : "Copy shareable link"}
>
{copied ? (
<>
<Check className="size-3.5" />
<span className="hidden sm:inline">Copied!</span>
</>
) : (
<>
<Link2 className="size-3.5" />
<span className="hidden sm:inline">Share</span>
</>
)}
</button>
);
}