/** * Client-side print export for the personal report. * * Deliberately print-only: `await document.fonts.ready` then `window.print()`. * It never requests a server-side PDF endpoint, never launches a headless * browser, and never rasterizes pixels: the user's own browser and OS render * the PDF. */ export interface PrintPersonalReportOptions { /** Title used as the browser's default PDF filename (document.title). */ title?: string; } /** Sanitize a report id into a safe PDF filename fragment (no path/query chars). */ export function safeReportFilename(reportId: string): string { const cleaned = String(reportId ?? "") .replace(/[^a-zA-Z0-9_-]+/g, "-") .replace(/^-+|-+$/g, "") .slice(0, 64); return cleaned.length > 0 ? `jyotisha-report-${cleaned}` : "jyotisha-report"; } export function isPrintSupported(): boolean { return typeof window !== "undefined" && typeof window.print === "function"; } /** * Detect environments whose built-in browser cannot print reliably. * WeChat's in-app browser is the known case; it should ask users to open the * page in the system browser instead of producing a broken printout. */ export function detectPrintRestriction(userAgent?: string): { restricted: boolean; message?: string; } { const ua = typeof userAgent === "string" ? userAgent : typeof navigator !== "undefined" ? navigator.userAgent : ""; if (/MicroMessenger/i.test(ua)) { return { restricted: true, message: "微信内置浏览器可能无法完整打印,请在系统浏览器中打开本页后打印。", }; } return { restricted: false }; } /** * Wait for web fonts, then open the browser print dialog. * The page/PDF layout is computed on the user's device; nothing is uploaded. */ export async function printPersonalReport(options: PrintPersonalReportOptions = {}): Promise { if (typeof window === "undefined" || typeof window.print !== "function") { return; } const fonts = typeof document !== "undefined" ? document.fonts : undefined; if (fonts && typeof fonts.ready?.then === "function") { await fonts.ready; } const previousTitle = typeof document !== "undefined" ? document.title : ""; const requested = typeof options.title === "string" ? options.title.trim() : ""; if (typeof document !== "undefined" && requested.length > 0) { // Browsers derive the default PDF filename from document.title. document.title = requested; } try { window.print(); } finally { if (typeof document !== "undefined") { document.title = previousTitle; } } }