forked from PinSpace-Org/GistPin
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChartExportCard.tsx
More file actions
138 lines (127 loc) 路 4.03 KB
/
Copy pathChartExportCard.tsx
File metadata and controls
138 lines (127 loc) 路 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
'use client';
import type { ReactNode } from 'react';
import { useRef, useState } from 'react';
import { copyChartImage, downloadChartImage, type ExportBackground } from '@/lib/chart-export';
interface ChartExportCardProps {
title: string;
children: ReactNode;
}
export default function ChartExportCard({ title, children }: ChartExportCardProps) {
const captureRef = useRef<HTMLDivElement>(null);
const [background, setBackground] = useState<ExportBackground>('white');
const [status, setStatus] = useState<string | null>(null);
const withElement = async (action: (element: HTMLElement) => Promise<void>) => {
if (!captureRef.current) {
return;
}
await action(captureRef.current);
};
return (
<section
style={{
background: '#ffffff',
borderRadius: 24,
padding: '24px 24px 28px',
border: '1px solid rgba(148,163,184,0.16)',
boxShadow: '0 16px 40px rgba(15,23,42,0.08)',
}}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
gap: 16,
marginBottom: 14,
flexWrap: 'wrap',
}}
>
<div>
<h2 style={{ margin: 0, fontSize: 24 }}>{title}</h2>
<div style={{ color: '#64748b', fontSize: 13, marginTop: 6 }}>
Export this chart as a high-resolution PNG or copy it to the clipboard.
</div>
</div>
<div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: '#475569' }}>
<span>Background</span>
<select
value={background}
onChange={(event) => setBackground(event.target.value as ExportBackground)}
style={{
borderRadius: 12,
border: '1px solid #cbd5e1',
padding: '8px 10px',
fontSize: 13,
background: '#ffffff',
}}
>
<option value="white">White</option>
<option value="transparent">Transparent</option>
</select>
</label>
<button
type="button"
onClick={() =>
withElement(async (element) => {
await downloadChartImage(title, element, background);
setStatus('PNG downloaded successfully.');
})
}
style={{
border: 'none',
borderRadius: 999,
background: '#1d4ed8',
color: '#ffffff',
padding: '10px 14px',
fontWeight: 700,
cursor: 'pointer',
}}
>
Download PNG
</button>
<button
type="button"
onClick={() =>
withElement(async (element) => {
try {
await copyChartImage(element, background);
setStatus('PNG copied to clipboard.');
} catch (error) {
setStatus(error instanceof Error ? error.message : 'Clipboard copy failed.');
}
})
}
style={{
border: '1px solid #bfdbfe',
borderRadius: 999,
background: '#eff6ff',
color: '#1d4ed8',
padding: '10px 14px',
fontWeight: 700,
cursor: 'pointer',
}}
>
Copy Image
</button>
</div>
</div>
{status && (
<div style={{ marginBottom: 12, fontSize: 13, color: '#0f766e' }}>
{status}
</div>
)}
<div
ref={captureRef}
style={{
background: background === 'white' ? '#ffffff' : 'transparent',
borderRadius: 18,
padding: 12,
}}
>
<div style={{ fontSize: 18, fontWeight: 800, marginBottom: 12 }}>{title}</div>
{children}
</div>
</section>
);
}