From 4b14bb26dd410e73a0db4d98e5c0de92fab5282f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=E6=82=A6?= Date: Mon, 27 Oct 2025 09:42:16 +0800 Subject: [PATCH] =?UTF-8?q?=20-=20=E5=9C=A8=20index.html:47-51=20=E7=BB=99?= =?UTF-8?q?=20main=20=E5=92=8C=E5=B7=A6=E4=BE=A7=E9=9D=A2=E6=9D=BF?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20min-h-0=EF=BC=8C=E5=85=81=E8=AE=B8?= =?UTF-8?q?=E7=BD=91=E6=A0=BC=E5=AD=90=E9=A1=B9=E5=9C=A8=E7=88=B6=E7=BA=A7?= =?UTF-8?q?=20flex=20=E5=AE=B9=E5=99=A8=E4=B8=AD=E9=87=8A=E6=94=BE?= =?UTF-8?q?=E9=AB=98=E5=BA=A6=EF=BC=8C=E7=A1=AE=E4=BF=9D=20=20=20=20=20#ch?= =?UTF-8?q?at-history=20=E7=9A=84=20overflow-y-auto=20=E7=94=9F=E6=95=88?= =?UTF-8?q?=EF=BC=9B=E5=8F=B3=E4=BE=A7=E5=B1=95=E7=A4=BA=E5=8C=BA=E5=90=8C?= =?UTF-8?q?=E6=A0=B7=E8=AE=BE=E7=BD=AE=20min-h-0=EF=BC=8C=E9=98=B2?= =?UTF-8?q?=E6=AD=A2=20SVG=20=E5=8C=BA=E5=9F=9F=E8=A2=AB=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E6=8B=89=E4=BC=B8=E3=80=82=20=20=20-=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=90=8E=EF=BC=8C=E9=95=BF=E5=AF=B9=E8=AF=9D=E4=BC=9A=E4=BF=9D?= =?UTF-8?q?=E6=8C=81=E9=9D=A2=E6=9D=BF=E5=9B=BA=E5=AE=9A=E9=AB=98=E5=BA=A6?= =?UTF-8?q?=EF=BC=8C=E6=BB=9A=E5=8A=A8=E6=9D=A1=E6=89=BF=E8=BD=BD=E5=A4=9A?= =?UTF-8?q?=E4=BD=99=E5=86=85=E5=AE=B9=EF=BC=8C=E4=B8=8D=E5=86=8D=E6=8A=8A?= =?UTF-8?q?=E6=95=B4=E4=B8=AA=E9=A1=B5=E9=9D=A2=E6=92=91=E5=87=BA=E8=A7=86?= =?UTF-8?q?=E7=AA=97=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/style.css | 26 ++++++++++++++++++++++++-- index.html | 7 ++++--- js/app.js | 18 +++++++++++------- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/css/style.css b/css/style.css index 534f3ce..dc6a774 100644 --- a/css/style.css +++ b/css/style.css @@ -2,6 +2,15 @@ body { font-family: 'Inter', sans-serif; } +/* 统一处理 Iconify 图标的对齐方式,避免在按钮与文字中出现垂直偏移 */ +iconify-icon { + display: inline-flex; + align-items: center; + justify-content: center; + vertical-align: middle; + line-height: 1; +} + /* 狂野线条效果 */ .wild-border { border: 3px solid; @@ -223,9 +232,22 @@ body { transition: color 0.2s ease; } +.svg-placeholder-block { + position: relative; +} + +@keyframes svg-active-pulse { + 0% { box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35), 0 6px 12px rgba(15, 23, 42, 0.15); } + 50% { box-shadow: 0 0 0 6px rgba(37, 99, 235, 0.15), 0 10px 18px rgba(15, 23, 42, 0.2); } + 100% { box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.35), 0 6px 12px rgba(15, 23, 42, 0.15); } +} + .svg-placeholder-active { - border-color: #2563eb; - box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2); + border-color: #1d4ed8; + background: linear-gradient(135deg, #e0f2fe 0%, #dbeafe 100%); + color: #1e3a8a; + transform: translateY(-2px); + /* animation: svg-active-pulse 1.6s ease-in-out infinite; */ } .svg-content-wrapper { diff --git a/index.html b/index.html index ea09c65..6ed2897 100644 --- a/index.html +++ b/index.html @@ -25,6 +25,7 @@
@@ -43,10 +44,10 @@ -
+
-
+
@@ -85,7 +86,7 @@
-
+
diff --git a/js/app.js b/js/app.js index c32a068..95aeff0 100644 --- a/js/app.js +++ b/js/app.js @@ -26,6 +26,8 @@ class ProductCanvasApp { this.pendingSvgId = null; this.pendingCancel = false; this.copyClipboardSupported = typeof ClipboardItem !== 'undefined' && !!navigator.clipboard; + const deviceScale = typeof window !== 'undefined' ? (window.devicePixelRatio || 1) : 1; + this.imageExportScale = Math.min(4, Math.max(2, deviceScale)); this.initElements(); this.initEventListeners(); @@ -1214,7 +1216,7 @@ class ProductCanvasApp { }); } - async convertSvgToPngBlob(svgContent) { + async convertSvgToPngBlob(svgContent, options = {}) { const { width, height } = this.parseSvgDimensions(svgContent); const svgBlob = new Blob([svgContent], { type: 'image/svg+xml' }); const url = URL.createObjectURL(svgBlob); @@ -1222,14 +1224,16 @@ class ProductCanvasApp { try { const img = await this.loadImageFromUrl(url); const canvas = document.createElement('canvas'); - const canvasWidth = Math.max(1, img.naturalWidth || width || 1024); - const canvasHeight = Math.max(1, img.naturalHeight || height || 768); - canvas.width = canvasWidth; - canvas.height = canvasHeight; + const baseWidth = Math.max(1, img.naturalWidth || width || 1024); + const baseHeight = Math.max(1, img.naturalHeight || height || 768); + const preferredScale = options.scale || this.imageExportScale || 1; + const exportScale = Math.min(4, Math.max(1, preferredScale)); + canvas.width = Math.round(baseWidth * exportScale); + canvas.height = Math.round(baseHeight * exportScale); const ctx = canvas.getContext('2d'); - ctx.clearRect(0, 0, canvasWidth, canvasHeight); - ctx.drawImage(img, 0, 0, canvasWidth, canvasHeight); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); return await new Promise((resolve, reject) => { canvas.toBlob((blob) => {