on master help sign in
add sigil generation on submit
commita8dd29b1f66f1e052ef2f0dd56b7a5401d7b9ee0 authorLiam Fitzgerald <liam@urizen.co> dateThu 9 Jan 2020, 16:45 (7 years ago) parent1767d41
5 files changed+97−6
src/form/Inputs.js+3−1 src/form/SubmitButton.js+3−1 src/lib/SigilDownloader.js+5 src/lib/useSigilDownloader.js+58 src/views/SigilGenerator.js+28−4
src/form/Inputs.js+3−1
@@ -221,9 +221,11 @@ export const ColorInput = ({
221221 htmlFor={name}>
222222 {label}
223223 </Flex.Item>
224− <div className="flex">
224+ <div className="flex flex-wrap">
225225 {colors.map(c => (
226226 <button
227+ type="button"
228+ key={c}
227229 className={cn('m0 p0 h7 w7 p2 flex flex-center', {
228230 'b b-black': isWhite(c),
229231 })}
src/form/SubmitButton.js+3−1
@@ -14,6 +14,7 @@ export default function SubmitButton({
1414 handleSubmit,
1515 ...rest
1616}) {
17+ const form = useFormState();
1718 const {
1819 valid,
1920 validating,
@@ -23,7 +24,8 @@ export default function SubmitButton({
2324 dirtySinceLastSubmit,
2425 submitErrors,
2526 submitSucceeded,
26− } = useFormState();
27+ } = form;
28+ console.log(form);
2729
2830 const onlyWarningInSubmitErrors = onlyHasWarning(submitErrors);
2931
src/lib/SigilDownloader.js+5
@@ -14,6 +14,11 @@ export const initCanvas = (canvas, size) => {
1414 return canvas;
1515};
1616
17+export const cleanupCanvas = canvas => {
18+ canvas.width = 0;
19+ canvas.height = 0;
20+};
21+
1722export const loadImg = src =>
1823 new Promise((resolve, reject) => {
1924 const img = new Image();
src/lib/useSigilDownloader.jsnew file+58
@@ -0,0 +1,58 @@
1+import { useCallback } from 'react';
2+import { saveAs } from 'file-saver';
3+import { sigil, stringRenderer } from 'urbit-sigil-js';
4+import * as ob from 'urbit-ob';
5+
6+import {
7+ dataURItoBlob,
8+ loadImg,
9+ initCanvas,
10+ cleanupCanvas,
11+} from 'lib/SigilDownloader';
12+
13+export default function useSigilDownloader(canvasRef) {
14+ const downloadSigil = useCallback(
15+ (point, colors, size) => {
16+ const patp = ob.patp(point);
17+
18+ const _size = size / window.devicePixelRatio;
19+
20+ const DATA_URI_PREFIX = 'data:image/svg+xml;base64,';
21+
22+ // initialize canvas element
23+ const canvas = initCanvas(canvasRef.current, { x: _size, y: _size });
24+ const ctx = canvas.getContext('2d');
25+
26+ // make sigil svg and encoded into base64
27+ const svg = sigil({
28+ patp,
29+ renderer: stringRenderer,
30+ size: _size,
31+ colors,
32+ margin: (54 / 256) * _size,
33+ });
34+
35+ // FF rendering hack
36+ const svgDocument = new DOMParser().parseFromString(svg, 'image/svg+xml');
37+ svgDocument.documentElement.width.baseVal.valueAsString = `${size}px`;
38+ svgDocument.documentElement.height.baseVal.valueAsString = `${size}px`;
39+ const svgText = new XMLSerializer().serializeToString(svgDocument);
40+ const svg64 = btoa(svgText);
41+
42+ return loadImg(DATA_URI_PREFIX + svg64, _size, _size)
43+ .then(img => {
44+ ctx.drawImage(img, 0, 0, _size, _size);
45+ const png = dataURItoBlob(canvas.toDataURL('image/png'));
46+ saveAs(png, `${patp.slice(1)}-sigil.png`);
47+ ctx.clearRect(0, 0, _size, _size);
48+ })
49+ .catch(() => 'Error generating sigil')
50+ .then(r => {
51+ cleanupCanvas(canvasRef.current);
52+ return r;
53+ });
54+ },
55+ [canvasRef]
56+ );
57+ return { downloadSigil };
58+}
src/views/SigilGenerator.js+28−4
@@ -1,6 +1,7 @@
1−import React from 'react';
1+import React, { useRef, useCallback } from 'react';
22import { Grid, Flex } from 'indigo-react';
33import * as ob from 'urbit-ob';
4+import { FORM_ERROR } from 'final-form';
45
56import { usePointCursor } from 'store/pointCursor';
67
@@ -9,6 +10,7 @@ import Sigil from 'components/Sigil';
910
1011import * as need from 'lib/need';
1112import { useLocalRouter } from 'lib/LocalRouter';
13+import useSigilDownloader from 'lib/useSigilDownloader';
1214
1315import { composeValidator, buildNumberValidator } from 'form/validators';
1416import BridgeForm from 'form/BridgeForm';
@@ -18,6 +20,7 @@ import { NumberInput, ColorInput } from 'form/Inputs';
1820
1921const BG_COLORS = [
2022 '#000000',
23+ '#FFFFFF',
2124 '#C80F34',
2225 '#EE5432',
2326 '#F8C134',
@@ -36,12 +39,26 @@ const BG_COLORS = [
3639const FG_COLORS = ['#000000', '#FFFFFF'];
3740
3841export default function SigilGenerator() {
39− const { pop, push, names } = useLocalRouter();
42+ const { pop } = useLocalRouter();
4043 const { pointCursor } = usePointCursor();
4144
4245 const validate = composeValidator({ size: buildNumberValidator(16) });
4346 const point = need.point(pointCursor);
44− const onSubmit = () => {};
47+
48+ const canvasRef = useRef(null);
49+
50+ const { downloadSigil } = useSigilDownloader(canvasRef);
51+ const onSubmit = useCallback(
52+ async (values, form) => {
53+ const error = await downloadSigil(point, values.colors, values.size);
54+ if (error) {
55+ return { [FORM_ERROR]: error };
56+ }
57+ // reset on next tick
58+ setTimeout(() => form.reset(values));
59+ },
60+ [point, downloadSigil]
61+ );
4562 return (
4663 <View pop={pop}>
4764 <BridgeForm
@@ -69,7 +86,12 @@ export default function SigilGenerator() {
6986 <Flex.Item className="mb1">Urbit ID</Flex.Item>
7087 <Flex.Item className="mono">{ob.patp(point)}</Flex.Item>
7188 </Grid.Item>
72− <Grid.Item full as={NumberInput} name="size" label="Size (px)" />
89+ <Grid.Item
90+ fourth={1}
91+ as={NumberInput}
92+ name="size"
93+ label="Size (px)"
94+ />
7395 <Grid.Item
7496 full
7597 as={ColorInput}
@@ -95,6 +117,8 @@ export default function SigilGenerator() {
95117 </Grid>
96118 )}
97119 </BridgeForm>
120+
121+ <canvas style={{ display: 'none' }} ref={canvasRef} />
98122 </View>
99123 );
100124}