|
1 | 1 | import { SoftBottom } from '@/components/others/SoftBottom'; |
2 | 2 | import { Button } from '@/components/ui/button'; |
3 | | -import { saveAs } from 'file-saver'; |
4 | | -import { toPng } from 'html-to-image'; |
| 3 | +import { snapdom } from '@zumer/snapdom'; |
5 | 4 | import { Link, Save } from 'lucide-react'; |
6 | 5 | import moment from 'moment'; |
7 | | -import { useTranslation } from 'react-i18next'; |
8 | 6 | import { useState } from 'react'; |
| 7 | +import { useTranslation } from 'react-i18next'; |
9 | 8 | import QRCode from 'react-qr-code'; |
| 9 | + |
10 | 10 | import { toast } from 'sonner'; |
11 | 11 | import AttachmentsGrid from './AttachmentsGrid'; |
12 | 12 |
|
@@ -51,33 +51,19 @@ function RoteShareCard({ rote }: any) { |
51 | 51 | setIsGenerating(true); |
52 | 52 | const element: any = document.querySelector('#shareCanva'); |
53 | 53 | if (element) { |
54 | | - // 获取元素的宽度和高度 |
55 | | - const width = element.clientWidth; |
56 | | - const height = element.clientHeight; |
57 | | - |
58 | | - // 配置 html2canvas 选项 |
59 | | - const options: any = { |
60 | | - width: width, |
61 | | - height: height, |
62 | | - canvasWidth: (width * 720) / width, |
63 | | - canvasHeight: (height * 720) / width, |
64 | | - backgroundColor: null, |
65 | | - cacheBust: true, |
66 | | - }; |
67 | | - |
68 | | - const dataUrl = await toPng(element, options); |
69 | | - |
70 | | - if (!dataUrl) { |
71 | | - toast.error(t('imageGenerationFailed')); |
72 | | - setIsGenerating(false); |
73 | | - return; |
74 | | - } |
75 | | - |
76 | | - if (window.saveAs) { |
77 | | - window.saveAs(dataUrl, `${rote.id}.png`); |
78 | | - } else { |
79 | | - saveAs(dataUrl, `${rote.id}.png`); |
80 | | - } |
| 54 | + await snapdom.download(element, { |
| 55 | + scale: 3, |
| 56 | + format: 'png', |
| 57 | + filename: `rote-${rote.id}.png`, |
| 58 | + crossOrigin: (url) => { |
| 59 | + // Use credentials for same-origin images |
| 60 | + if (url.startsWith(window.location.origin)) { |
| 61 | + return 'use-credentials'; |
| 62 | + } |
| 63 | + // Use anonymous for cross-origin images |
| 64 | + return 'anonymous'; |
| 65 | + }, |
| 66 | + }); |
81 | 67 |
|
82 | 68 | toast.success(t('imageSaved')); |
83 | 69 | setIsGenerating(false); |
@@ -123,11 +109,11 @@ function RoteShareCard({ rote }: any) { |
123 | 109 | <div className="font-sm opacity-60"> |
124 | 110 | {moment().utc(rote.createdAt).format('YYYY/MM/DD HH:mm:ss')} |
125 | 111 | </div> |
126 | | - <div className="font-serif leading-7 font-light tracking-wide break-words whitespace-pre-line md:text-lg"> |
| 112 | + <div className="leading-7 font-light tracking-wide break-words whitespace-pre-line md:text-lg"> |
127 | 113 | {rote.content} |
128 | 114 | </div> |
129 | | - <AttachmentsGrid attachments={rote.attachments} /> |
130 | | - <div className="md:text-md flex flex-wrap items-center gap-2 font-serif text-xs"> |
| 115 | + <AttachmentsGrid attachments={rote.attachments} withTimeStamp={true} /> |
| 116 | + <div className="md:text-md flex flex-wrap items-center gap-2 text-sm"> |
131 | 117 | {rote.tags.map((tag: any) => ( |
132 | 118 | <span |
133 | 119 | className={`rounded-md px-2 py-1 md:px-3 ${themes[themeIndex].tagClass}`} |
|
0 commit comments