feat(web): native share sheet for created + saved links
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 39s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 39s
Adds a "Share link" button that invokes navigator.share() so iOS home-screen PWA users (and any platform with the Web Share API) get the system share sheet — AirDrop, Messages, Mail, WhatsApp… Falls back to copy-only on platforms without support. Wired on both CloudSharePanel (just-created link) and Settings → Shared links (re-share an existing one). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
641ec629f5
commit
48ace8af34
@ -71,6 +71,20 @@ export default function CloudSharePanel() {
|
||||
setTimeout(() => setCopied(false), 1500);
|
||||
};
|
||||
|
||||
const canShare = typeof navigator !== "undefined" && typeof navigator.share === "function";
|
||||
|
||||
const share = async (url: string, fileName: string) => {
|
||||
try {
|
||||
await navigator.share({
|
||||
title: `AnyDrop — ${fileName}`,
|
||||
text: "File shared via AnyDrop",
|
||||
url,
|
||||
});
|
||||
} catch {
|
||||
// User canceled the share sheet, or the browser rejected — nothing to do.
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="paper-panel p-4 sm:p-5">
|
||||
{stage.kind === "idle" && (
|
||||
@ -235,13 +249,27 @@ export default function CloudSharePanel() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => copy(stage.shareUrl)}
|
||||
className="w-full py-2.5 bg-ink text-paper text-sm font-medium rounded-sm
|
||||
hover:bg-signal transition-colors duration-fast ease-crisp"
|
||||
>
|
||||
{copied ? "Copied ✓" : "Copy link"}
|
||||
</button>
|
||||
<div className="flex gap-2">
|
||||
{canShare && (
|
||||
<button
|
||||
onClick={() => share(stage.shareUrl, stage.fileName)}
|
||||
className="flex-1 py-2.5 bg-ink text-paper text-sm font-medium rounded-sm
|
||||
hover:bg-signal transition-colors duration-fast ease-crisp"
|
||||
>
|
||||
Share link →
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => copy(stage.shareUrl)}
|
||||
className={`py-2.5 text-sm font-medium rounded-sm transition-colors duration-fast ease-crisp ${
|
||||
canShare
|
||||
? "flex-1 border border-paper-edge hover:border-ink text-ink"
|
||||
: "w-full bg-ink text-paper hover:bg-signal"
|
||||
}`}
|
||||
>
|
||||
{copied ? "Copied ✓" : "Copy link"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="mt-2 font-mono text-[11px] text-ink-faint break-all">
|
||||
{stage.shareUrl}
|
||||
|
||||
@ -509,6 +509,22 @@ function SharedLinksSection() {
|
||||
setTimeout(() => setCopiedId((v) => (v === item.id ? null : v)), 1500);
|
||||
};
|
||||
|
||||
const canShare = typeof navigator !== "undefined" && typeof navigator.share === "function";
|
||||
|
||||
const onShare = async (item: LinkItem) => {
|
||||
if (!item.keyFrag) return;
|
||||
const url = `${window.location.origin}/r/${item.id}#k=${item.keyFrag}`;
|
||||
try {
|
||||
await navigator.share({
|
||||
title: `AnyDrop — ${item.filename ?? "Encrypted file"}`,
|
||||
text: "File shared via AnyDrop",
|
||||
url,
|
||||
});
|
||||
} catch {
|
||||
// User canceled — no-op.
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="mb-12">
|
||||
<div className="text-xs uppercase tracking-[0.22em] text-ink-muted">
|
||||
@ -554,6 +570,14 @@ function SharedLinksSection() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-end gap-1.5 shrink-0">
|
||||
{item.keyFrag && status === "active" && canShare && (
|
||||
<button
|
||||
onClick={() => onShare(item)}
|
||||
className="text-xs text-ink hover:text-signal transition-colors"
|
||||
>
|
||||
Share →
|
||||
</button>
|
||||
)}
|
||||
{item.keyFrag && status === "active" && (
|
||||
<button
|
||||
onClick={() => onCopy(item)}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user