"use client"; import { exportDeck } from "./storage"; import { showToast } from "./toast"; import type { Deck, HomeworkRecord } from "./schemas"; import { t } from "./i18n"; /** * Web Share with graceful fallbacks: file share (deck JSON) where the browser * supports it, text share otherwise, clipboard copy as the last resort. */ type ShareNavigator = Navigator & { canShare?: (data: { files?: File[]; text?: string; title?: string }) => boolean; share?: (data: { files?: File[]; text?: string; title?: string }) => Promise; }; function deckFile(deck: Deck): File { return new File([exportDeck(deck)], `${deck.title.replace(/[^\p{L}\p{N} _-]/gu, "").trim() || "deck"}.json`, { type: "application/json", }); } async function copyText(text: string): Promise { try { if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(text); return true; } } catch { /* fall through */ } return false; } export async function shareDeck(deck: Deck): Promise { const nav = navigator as ShareNavigator; const file = deckFile(deck); try { if (nav.share && nav.canShare?.({ files: [file] })) { await nav.share({ files: [file], title: deck.title }); return; } if (nav.share) { await nav.share({ title: deck.title, text: deck.title }); return; } } catch (error) { // The user cancelling the share sheet is not an error. if (error instanceof DOMException && error.name === "AbortError") return; } if (await copyText(exportDeck(deck))) showToast({ message: t("share.copied") }); else showToast({ message: t("share.failed") }); } export async function shareHomework(record: HomeworkRecord): Promise { const nav = navigator as ShareNavigator; const text = record.mode === "make" ? record.answer : record.steps.map((step, index) => `${index + 1}. ${step.title}`).join("\n"); try { if (nav.share) { await nav.share({ title: record.title, text }); return; } } catch (error) { if (error instanceof DOMException && error.name === "AbortError") return; } if (await copyText(text)) showToast({ message: t("share.copied") }); else showToast({ message: t("share.failed") }); }