on 368f024 help sign in
bridge/src/components/Passport.js
240 lines 6.6 kB history raw
1import React, { useMemo } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
3import ob from 'urbit-ob';
4import BN from 'bn.js';
5import 'style/anim.css';
6import { sigil, reactRenderer } from 'urbit-sigil-js';
7import { Icon } from '@tlon/indigo-react';
9import { chunkStr, Matrix, walk, rand } from 'lib/card';
10import { useSyncDetails } from 'lib/useSyncPoints';
12import './SigilMini.scss';
14function makeSigil(size, patp, colors) {
15 const config = {
16 margin: 0,
17 renderer: reactRenderer,
18 full: true,
19 patp,
20 colors,
21 size,
22 };
24 return sigil(config);
27const symbols = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
29/**
30 * Address is Maybe<string>
31 * point is Maybe<string>
32 * animationMode is 'slide' | 'step' | 'none'
33 *
34 */
35function Passport({
36 address,
37 point,
38 inverted = false,
39 animationMode = 'none',
40 keyType = '',
41}) {
42 const [cols, rows, tile] = [35, 12, 12];
44 const loading = Nothing.hasInstance(address) || Nothing.hasInstance(point);
45 const defaultMatrix = () => {
46 return Matrix.new(rows, cols);
47 };
49 const patp = ob.patp(point.value);
51 const makeMatrix = azimuthPoint => {
52 // convert point to hex
53 const azimuthPointHex = azimuthPoint.toString(16);
55 // make bigNum from hex
56 const int = new BN(azimuthPointHex, 16);
58 // make a bigger number
59 const big = int.pow(new BN(100));
60 // parse that to a string and pad
61 const b10 = big.toString(10).padStart(32, '0');
62 // split the big number into parts
63 const chunkSize = Math.ceil(b10.length / 8);
64 const chunks = chunkStr(b10, chunkSize).map(c => new BN(c));
65 // generate an empty matrix
66 const startMatrix = Matrix.new(rows, cols);
67 // do a few random walks starting at diff coordinates
68 const [, matrix] = chunks.reduce((acc, chunk) => {
69 return walk(chunk, acc[1]);
70 // start with the 'random' points (not actually random, they are deterministic)
71 }, rand(big, startMatrix));
73 return matrix;
74 };
76 const matrix = point.matchWith({
77 Just: ({ value }) => makeMatrix(value),
78 Nothing: defaultMatrix,
79 });
81 const bgColor = inverted ? 'white' : 'black';
83 const fgColor = inverted ? 'black' : 'white';
85 const sigil = useMemo(
86 () => Just.hasInstance(point) && makeSigil(64, patp, [bgColor, fgColor]),
87 [patp, point, bgColor, fgColor]
88 );
89 return (
90 <div
91 style={{
92 fontFamily: 'Inter',
93 backgroundColor: bgColor,
94 border: inverted ? '2px solid #E6E6E6' : '2px solid black',
95 borderRadius: '20px',
96 marginBottom: '16px',
97 width: `${16 + 16 + cols * tile}px`,
98 minWidth: `${16 + 16 + cols * tile}px`,
99 display: 'flex',
100 flexDirection: 'column',
101 }}>
102 <div
103 style={{
104 height: '64px',
105 padding: '16px',
106 display: 'flex',
107 }}>
108 <div
109 style={{
110 width: '100%',
111 display: 'flex',
112 alignItems: 'center',
113 }}>
114 {sigil}
115 <div
116 style={{
117 marginLeft: '16px',
118 }}>
119 <div
120 style={{
121 fontWeight: '600',
122 color: fgColor,
123 fontSize: '16px',
124 fontFamily: 'Source Code Pro',
125 }}>
126 {Just.hasInstance(point) && patp}
127 </div>
128 {keyType !== '' ? (
129 <div
130 style={{
131 marginTop: '8px',
132 fontWeight: '500',
133 color: fgColor,
134 fontSize: '14px',
135 fontFamily: 'Source Code Pro',
136 }}>
137 {keyType}
138 </div>
139 ) : (
140 <div />
141 )}
142 </div>
143 </div>
144 </div>
145 <div
146 style={{
147 display: 'flex',
148 flexDirection: 'column',
149 padding: '16px',
150 paddingTop: '0px',
151 filter: inverted ? 'invert(1)' : '',
152 }}>
153 {matrix.map((row, _row) => {
154 return (
155 <div
156 key={`card:row:${_row}`}
157 style={{ display: 'flex', justifyContent: 'space-between' }}>
158 {row.map((v, _col) => {
159 return (
160 <Cell
161 row={_row}
162 col={_col}
163 value={typeof symbols[v] === 'undefined' ? 13 : v}
164 spriteSheet={'a'}
165 spriteSheetHeight={12}
166 spriteSheetWidth={168}
167 inverted={inverted}
168 loading={loading}
169 animationMode={animationMode}
170 key={`cell-${_col}`}
171 />
172 );
173 })}
174 </div>
175 );
176 })}
177 </div>
178 </div>
179 );
182const Cell = props => {
183 return (
184 <div
185 key={`card:cell:${props.row}:${props.col}:${props.value}`}
186 className={
187 props.loading
188 ? 'blink'
189 : props.animationMode === 'none'
190 ? ''
191 : `${props.animationMode}-h-${props.value}`
192 }
193 style={{
194 backgroundImage: `url(/spritesheet_a.png)`,
195 backgroundPosition:
196 props.animationMode === 'none'
197 ? `-${props.spriteSheetHeight * props.value}px 0px`
198 : '',
199 backgroundSize: `${props.spriteSheetWidth}px ${props.spriteSheetHeight}px`,
200 width: `${props.spriteSheetHeight}px`,
201 maxWidth: `${props.spriteSheetHeight}px`,
202 height: `${props.spriteSheetHeight}px`,
203 maxHeight: `${props.spriteSheetHeight}px`,
204 animationDelay: `${props.value * 50}ms`,
205 }}
206 />
207 );
208};
210/**
211 * point is number
212 *
213 */
214function MiniPassport({ point, inverted, locked = false, ...rest }) {
215 useSyncDetails([point]);
216 // const { wallet } = useWallet();
217 // const address = need.addressFromWallet(wallet);
218 // const permissions = usePermissionsForPoint(address, point);
219 // const keyType = buildKeyType(permissions);
220 const patp = ob.patp(point);
222 const contrast = locked ? '#666666' : 'black';
224 const sigil = useMemo(
225 () =>
226 makeSigil(50, patp, inverted ? ['white', contrast] : [contrast, 'white']),
227 [inverted, patp, contrast]
228 );
229 return (
230 <div {...rest} className="sigil-mini">
231 <div className={`sigil ${locked ? 'locked' : ''}`}>{sigil}</div>
232 <span className="patp">{patp}</span>
233 {locked && <Icon color="white" icon="Locked" className="lock" />}
234 </div>
235 );
238Passport.Mini = MiniPassport;
240export default Passport;