From 27b3c5e324224109c4282f308f009f6ddf9c8ad1 Mon Sep 17 00:00:00 2001 From: anime Date: Mon, 7 Jul 2025 18:33:51 +0800 Subject: [PATCH] feat(email encrypt): implement CanvasEmail component for obfuscation of display email text - Add new CanvasEmail component that renders email on canvas - Replace plain email text with CanvasEmail in Footer --- components/CanvasEmail.js | 95 ++++++++++++++++++++++++++++ themes/commerce/components/Footer.js | 3 +- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 components/CanvasEmail.js diff --git a/components/CanvasEmail.js b/components/CanvasEmail.js new file mode 100644 index 00000000..1de23fee --- /dev/null +++ b/components/CanvasEmail.js @@ -0,0 +1,95 @@ +import { useEffect, useRef, useState } from 'react' + +const CanvasEmail = ({ email, className = '' }) => { + const canvasRef = useRef(null) + const textRef = useRef(null) + const [isCopied, setIsCopied] = useState(false) + + useEffect(() => { + if (!textRef.current || !canvasRef.current) return + + const canvas = canvasRef.current + const ctx = canvas.getContext('2d') + const textElement = textRef.current + + // Get computed styles from the hidden text element + const style = window.getComputedStyle(textElement) + const font = style.font + const color = style.color + + // Set canvas font and measure text + ctx.font = font + const metrics = ctx.measureText(email) + const fontSize = parseInt(style.fontSize) + const lineHeight = fontSize * 1.2 + + // Set canvas dimensions + const scale = window.devicePixelRatio || 1 + canvas.width = metrics.width * scale + canvas.height = lineHeight * scale + canvas.style.width = `${metrics.width}px` + canvas.style.height = `${lineHeight}px` + + // Redraw with high DPI support + ctx.scale(scale, scale) + ctx.font = font + ctx.fillStyle = color + ctx.textBaseline = 'top' // Changed to 'top' for better vertical alignment + ctx.fillText(email, 0, 0) + + // Handle copy to clipboard + const handleCopy = e => { + e.preventDefault() + navigator.clipboard.writeText(email).then(() => { + setIsCopied(true) + setTimeout(() => setIsCopied(false), 2000) + }) + } + + canvas.style.cursor = 'pointer' + canvas.addEventListener('click', handleCopy) + return () => canvas.removeEventListener('click', handleCopy) + }, [email]) + + return ( + + {/* Hidden span for measuring text metrics */} + + + {/* Canvas that displays the text */} + + + ) +} + +export default CanvasEmail diff --git a/themes/commerce/components/Footer.js b/themes/commerce/components/Footer.js index aff2cec4..0db4f1f7 100644 --- a/themes/commerce/components/Footer.js +++ b/themes/commerce/components/Footer.js @@ -6,6 +6,7 @@ import Link from 'next/link' import CONFIG from '../config' import { decryptEmail, handleEmailClick } from '@/lib/plugins/mailEncrypt' import { useRef } from 'react' +import CanvasEmail from '@/components/CanvasEmail' /** * 页脚 @@ -143,7 +144,7 @@ const Footer = props => { className='cursor-pointer' ref={emailIcon}> {' '} - {decryptEmail(CONTACT_EMAIL)} + )}