"use client"; import { useEffect, useRef, useState, type ReactNode } from "react"; import { createPortal } from "react-dom"; import { DownloadIcon } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { ExportLanguageToggle, useExportLanguage, type ExportLanguage, } from "@/components/public/export-language"; import { Spinner } from "@/components/ui/spinner"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { cn } from "@/lib/utils"; const EXPORT_WIDTH = 1200; function withoutNotesFileName(fileName: string): string { return /\.[^.]+$/u.test(fileName) ? fileName.replace(/(\.[^.]+)$/u, "-without-notes$1") : `${fileName}-without-notes`; } function downloadFileName(value: string): string { return value.replace(/[\\/:*?"<>|]/gu, "-"); } export function imageExportFileName( fileName: string, language: ExportLanguage, withoutNotes: boolean, localized = true, ): string { const selectedFileName = withoutNotes ? withoutNotesFileName(fileName) : fileName; const languageFileName = localized ? (/\.[^.]+$/u.test(selectedFileName) ? selectedFileName.replace(/(\.[^.]+)$/u, `-${language}$1`) : `${selectedFileName}-${language}`) : selectedFileName; return downloadFileName(languageFileName); } export function GuideImageExport({ children, fileName, width = EXPORT_WIDTH, height, format = "png", disabled = false, allowWithoutNotes = true, captureClassName, buttonLabel = "ส่งออกภาพ", mobileIconOnly = false, language: controlledLanguage, showLanguageSelector = true, promptForLanguage = false, localizeFileName = true, modeSelection = "dialog", }: { children: ReactNode; fileName: string; width?: number; height?: number; format?: "png" | "webp"; disabled?: boolean; allowWithoutNotes?: boolean; captureClassName?: string; buttonLabel?: string; mobileIconOnly?: boolean; language?: ExportLanguage; showLanguageSelector?: boolean; promptForLanguage?: boolean; localizeFileName?: boolean; modeSelection?: "dialog" | "inline"; }) { const captureRef = useRef(null); const [captureMode, setCaptureMode] = useState< "with-notes" | "without-notes" | null >(null); const capturing = captureMode !== null; const [storedLanguage, setStoredLanguage] = useExportLanguage(); const language = controlledLanguage ?? storedLanguage; const [selectedMode, setSelectedMode] = useState<"with-notes" | "without-notes">( "with-notes", ); const [modeDialogOpen, setModeDialogOpen] = useState(false); function requestCapture() { setModeDialogOpen(false); setCaptureMode(selectedMode); } function exportButton(label: string) { return ( ); } const exportSettings = ( <> {showLanguageSelector || promptForLanguage ? (

ภาษาในภาพ

) : null} {allowWithoutNotes ? (

โน้ต

{ const next = values[0]; if (next === "with-notes" || next === "without-notes") setSelectedMode(next); }} > รวมโน้ต ไม่รวมโน้ต
) : null} ); useEffect(() => { if (!capturing) return; let cancelled = false; async function capture() { try { const node = captureRef.current; if (!node) throw new Error("Capture target is unavailable"); if (captureMode === "without-notes") { node.querySelectorAll("[data-export-note]").forEach((note) => { note.style.display = "none"; }); // A note can be the only remaining content in the artifact right column. const right = node.querySelector(".artifact-export-right"); if (right) { const sections = right.querySelectorAll( "[data-artifact-export-section]", ); const hasVisibleSection = Array.from(sections).some( (section) => getComputedStyle(section).display !== "none", ); if (!hasVisibleSection) right.style.display = "none"; } } const { domToBlob, waitUntilLoad } = await import("modern-screenshot"); await Promise.all([document.fonts.ready, waitUntilLoad(node)]); const blob = await domToBlob(node, { backgroundColor: getComputedStyle(node).backgroundColor, type: `image/${format}`, scale: 1, width, height, }); if (cancelled) return; const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.download = imageExportFileName( fileName, language, captureMode === "without-notes", localizeFileName, ); link.href = url; document.body.append(link); link.click(); link.remove(); window.setTimeout(() => URL.revokeObjectURL(url), 0); } catch { if (!cancelled) toast.error("ส่งออกภาพไม่สำเร็จ กรุณาลองอีกครั้ง"); } finally { if (!cancelled) setCaptureMode(null); } } void capture(); return () => { cancelled = true; }; }, [capturing, captureMode, fileName, format, height, language, localizeFileName, width]); return ( <> {modeSelection === "inline" ? ( exportSettings ) : (
{exportButton(buttonLabel)}
)} {modeSelection === "dialog" ? ( ตั้งค่าการส่งออกภาพ เลือกตัวเลือกที่ต้องการก่อนส่งออกภาพ {exportSettings} ) : null} {capturing ? createPortal( , document.body, ) : null} ); }