@@ -0,0 +1,125 @@
1+import React, { useRef, useCallback } from 'react';
2+import { Grid, Flex } from 'indigo-react';
3+import * as ob from 'urbit-ob';
4+import { FORM_ERROR } from 'final-form';
5+import { colors } from 'indigo-tokens';
6+
7+import { usePointCursor } from 'store/pointCursor';
8+
9+import View from 'components/View';
10+import Sigil from 'components/Sigil';
11+
12+import * as need from 'lib/need';
13+import { useLocalRouter } from 'lib/LocalRouter';
14+import useSigilDownloader from 'lib/useSigilDownloader';
15+
16+import { composeValidator, buildNumberValidator } from 'form/validators';
17+import BridgeForm from 'form/BridgeForm';
18+import FormError from 'form/FormError';
19+import SubmitButton from 'form/SubmitButton';
20+import { NumberInput } from 'form/Inputs';
21+import ColorInput from 'form/ColorInput';
22+
23+const BG_COLORS = [
24+ colors.black,
25+ colors.white,
26+ colors.blue,
27+ colors.blueLight,
28+ colors.blueDark,
29+ colors.redLight,
30+ colors.red,
31+ colors.redDark,
32+ colors.greenLight,
33+ colors.green,
34+ colors.greenDark,
35+ colors.yellowLight,
36+ colors.yellow,
37+ colors.yellowDark,
38+];
39+
40+const FG_COLORS = [colors.black, colors.white];
41+
42+export default function SigilGenerator() {
43+ const { pop } = useLocalRouter();
44+ const { pointCursor } = usePointCursor();
45+
46+ const validate = composeValidator({ size: buildNumberValidator(16) });
47+ const point = need.point(pointCursor);
48+
49+ const canvasRef = useRef(null);
50+
51+ const { downloadSigil } = useSigilDownloader(canvasRef);
52+ const onSubmit = useCallback(
53+ async (values, form) => {
54+ const error = await downloadSigil(point, values.colors, values.size);
55+ if (error) {
56+ return { [FORM_ERROR]: error };
57+ }
58+ // reset on next tick
59+ setTimeout(() => form.reset(values));
60+ },
61+ [point, downloadSigil]
62+ );
63+ return (
64+ <View pop={pop}>
65+ <BridgeForm
66+ validate={validate}
67+ initialValues={{
68+ size: 256,
69+ fgColor: '#FFFFFF',
70+ bgColor: '#000000',
71+ }}
72+ onSubmit={onSubmit}>
73+ {({ handleSubmit, values }) => (
74+ <Grid gap={6}>
75+ <Grid.Item full className="f7">
76+ Sigil
77+ </Grid.Item>
78+ <Grid.Item fourth={1}>
79+ <Sigil
80+ size={50}
81+ patp={ob.patp(point)}
82+ colors={[values.bgColor, values.fgColor]}
83+ />
84+ </Grid.Item>
85+
86+ <Grid.Item full as={Flex} col>
87+ <Flex.Item className="mb1">Urbit ID</Flex.Item>
88+ <Flex.Item className="mono">{ob.patp(point)}</Flex.Item>
89+ </Grid.Item>
90+ <Grid.Item
91+ fourth={1}
92+ as={NumberInput}
93+ name="size"
94+ label="Size (px)"
95+ />
96+ <Grid.Item
97+ full
98+ as={ColorInput}
99+ name="bgColor"
100+ label="Background Color"
101+ colors={BG_COLORS}
102+ />
103+ <Grid.Item
104+ full
105+ as={ColorInput}
106+ name="fgColor"
107+ label="Foreground Color"
108+ colors={FG_COLORS}
109+ />
110+ <Grid.Item
111+ full
112+ as={SubmitButton}
113+ handleSubmit={handleSubmit}
114+ accessory="↓">
115+ Download Sigil
116+ </Grid.Item>
117+ <Grid.Item full as={FormError} />
118+ </Grid>
119+ )}
120+ </BridgeForm>
121+
122+ <canvas style={{ display: 'none' }} ref={canvasRef} />
123+ </View>
124+ );
125+}