diff --git a/apps/fronted/src/components/PhotoConfigDrawer.tsx b/apps/fronted/src/components/PhotoConfigDrawer.tsx index d53d071..6248a7c 100644 --- a/apps/fronted/src/components/PhotoConfigDrawer.tsx +++ b/apps/fronted/src/components/PhotoConfigDrawer.tsx @@ -1,3 +1,4 @@ +"use client"; import React, { useState, useRef, useEffect, useMemo } from "react"; import { Drawer, @@ -47,9 +48,20 @@ const PhotoConfigDrawer: React.FC = ({ const [config, setConfig] = useState( initialConfig || DEFAULT_CONFIG ); - const isMobile = useMemo(() => { - return window.innerWidth <= 768; - }, [window.innerWidth]); + const [isMobile, setIsMobile] = useState(false); + + useEffect(() => { + const handleResize = () => { + setIsMobile(window.innerWidth <= 768); + }; + + window.addEventListener("resize", handleResize); + + return () => { + window.removeEventListener("resize", handleResize); + }; + }, []); + useEffect(() => { if (isOpen) { setConfig(initialConfig || DEFAULT_CONFIG); diff --git a/apps/fronted/src/components/PhotoSelector.tsx b/apps/fronted/src/components/PhotoSelector.tsx index 77de09d..6062672 100644 --- a/apps/fronted/src/components/PhotoSelector.tsx +++ b/apps/fronted/src/components/PhotoSelector.tsx @@ -1,3 +1,4 @@ +"use client"; import React, { useState } from "react"; import { Settings2, Image, EyeOff, Eye } from "lucide-react"; import { Button } from "@/components/ui/button"; diff --git a/apps/fronted/src/components/editor/PdfExport.tsx b/apps/fronted/src/components/editor/PdfExport.tsx index 239decd..462dffd 100644 --- a/apps/fronted/src/components/editor/PdfExport.tsx +++ b/apps/fronted/src/components/editor/PdfExport.tsx @@ -3,88 +3,85 @@ import React, { useState } from "react"; import { motion } from "framer-motion"; import { Download, Loader2 } from "lucide-react"; -import html2pdf from "html2pdf.js"; import { useResumeStore } from "@/store/useResumeStore"; +import dynamic from "next/dynamic"; + +const html2pdf = dynamic(() => import("html2pdf.js"), { + ssr: false +}); export function PdfExport() { const { basic, theme } = useResumeStore(); const [isExporting, setIsExporting] = useState(false); - const handleExport = () => { - setIsExporting(true); - const element = document.querySelector("#resume-preview"); - if (!element) { - setIsExporting(false); - return; - } - // 内容高度的问题 - const contentHeight = element.scrollHeight - 30.22; - const A4_HEIGHT_MM = 297; - const MARGINS_MM = 8; - const CONTENT_HEIGHT_MM = A4_HEIGHT_MM - MARGINS_MM; - const DPI = 96; - const MM_TO_PX = DPI / 25.4; + const handleExport = async () => { + try { + setIsExporting(true); - const pageHeightPx = Math.ceil(CONTENT_HEIGHT_MM * MM_TO_PX); - const numberOfPages = Math.ceil(contentHeight / pageHeightPx); + if (typeof window === "undefined") return; - const pageBreakLines = element.querySelectorAll(".page-break-line"); - pageBreakLines.forEach((line) => { - line.style.display = "none"; - }); + const element = document.querySelector("#resume-preview"); + if (!element) { + setIsExporting(false); + return; + } - // 导出后的清理代码 - const cleanup = () => { + const contentHeight = element.scrollHeight - 30.22; + const A4_HEIGHT_MM = 297; + const MARGINS_MM = 8; + const CONTENT_HEIGHT_MM = A4_HEIGHT_MM - MARGINS_MM; + const DPI = 96; + const MM_TO_PX = DPI / 25.4; + + const pageHeightPx = Math.ceil(CONTENT_HEIGHT_MM * MM_TO_PX); + const numberOfPages = Math.ceil(contentHeight / pageHeightPx); + + const pageBreakLines = element.querySelectorAll(".page-break-line"); + pageBreakLines.forEach((line) => { + line.style.display = "none"; + }); + + const html2pdfModule = await import("html2pdf.js"); + const html2pdfInstance = html2pdfModule.default; + + const opt = { + margin: [4, 4, 4, 4], + filename: `${basic.name}_简历.pdf`, + image: { type: "jpeg", quality: 0.98 }, + pagebreak: { + mode: ["css", "legacy"] + }, + html2canvas: { + scale: window.devicePixelRatio * 3, + letterRendering: true, + scrollY: -window.scrollY, + height: pageHeightPx * numberOfPages + }, + jsPDF: { + unit: "mm", + format: "a4", + orientation: "portrait", + putTotalPages: false + } + }; + + await html2pdfInstance().set(opt).from(element).save(); + } catch (error) { + console.error("PDF export failed:", error); + } finally { + const pageBreakLines = document.querySelectorAll(".page-break-line"); pageBreakLines.forEach((line) => { line.style.display = ""; }); setIsExporting(false); - }; - - const opt = { - margin: [4, 4, 4, 4], - filename: `${basic.name}_简历.pdf`, - image: { type: "jpeg", quality: 0.98 }, - pagebreak: { - mode: ["css", "legacy"] - }, - html2canvas: { - scale: window.devicePixelRatio * 3, - letterRendering: true, - scrollY: -window.scrollY, - height: pageHeightPx * numberOfPages - }, - jsPDF: { - unit: "mm", - format: "a4", - orientation: "portrait", - putTotalPages: false - } - }; - - html2pdf() - .set(opt) - .from(element) - .save() - .then((res: any) => { - return res; - }) - .catch((error: any) => { - console.error("PDF export failed:", error); - return { notFound: true }; - }) - .finally(() => { - setIsExporting(false); - cleanup(); - return { finally: true }; - }); + } }; return (