on master help sign in
bridge/src/components/DownloadSigilButton.jsx
72 lines 2.1 kB history raw
1import React, { useRef, useState } from 'react';
2import * as ob from 'urbit-ob';
3import { saveAs } from 'file-saver';
4import { sigil, stringRenderer } from 'urbit-sigil-js';
6import { dataURItoBlob, loadImg, initCanvas } from 'lib/SigilDownloader';
8import { DownloadButton } from 'components/Buttons';
10export default function DownloadSigilButton({
11 point,
12 children = 'Download Sigil',
13 ...rest
14}) {
15 const [downloaded, setDownloaded] = useState(false);
16 const downloadSigil = () => {
17 const patp = ob.patp(point);
19 const _size = 1024 / window.devicePixelRatio;
20 const pngSize = 1024;
22 const DATA_URI_PREFIX = 'data:image/svg+xml;base64,';
24 // initialize canvas element
25 const canvas = initCanvas(canvasRef.current, { x: _size, y: _size });
26 const ctx = canvas.getContext('2d');
28 // make sigil svg and encoded into base64
29 const svg = sigil({
30 patp,
31 renderer: stringRenderer,
32 size: _size,
33 colors: ['#FFFFFF', '#000000'],
34 margin: (54 / 256) * _size,
35 });
37 // FF rendering hack
38 const svgDocument = new DOMParser().parseFromString(svg, 'image/svg+xml');
39 svgDocument.documentElement.width.baseVal.valueAsString = `${pngSize}px`;
40 svgDocument.documentElement.height.baseVal.valueAsString = `${pngSize}px`;
41 const svgText = new XMLSerializer().serializeToString(svgDocument);
42 const svg64 = btoa(svgText);
44 const pngTask = loadImg(DATA_URI_PREFIX + svg64, _size, _size).then(img => {
45 ctx.drawImage(img, 0, 0, _size, _size);
46 const png = dataURItoBlob(canvas.toDataURL('image/png'));
47 saveAs(png, `${patp.slice(1)}-sigil.png`);
48 ctx.clearRect(0, 0, pngSize, pngSize);
50 setDownloaded(true);
51 });
53 return pngTask;
54 };
55 const canvasRef = useRef(null);
57 return (
58 <>
59 <DownloadButton
60 as="span"
61 disabled={downloaded}
62 onClick={downloadSigil}
63 detail={
64 downloaded ? 'Downloaded!' : 'Download the sigil for this point'
65 }
66 {...rest}>
67 {children}
68 </DownloadButton>
69 <canvas style={{ display: 'none' }} ref={canvasRef} />
70 </>
71 );