5
5
*
6
6
* Copyright Oxide Computer Company
7
7
*/
8
+ import md5 from 'md5'
8
9
import { useMemo } from 'react'
9
10
10
- import { generateIdenticon , md5 } from '@oxide/identicon'
11
+ type Rectangle = { x : number ; y : number ; isOn : boolean }
12
+
13
+ const getPixels = ( s : string ) => {
14
+ const hash = md5 ( s )
15
+ const buffer : Rectangle [ ] = [ ]
16
+
17
+ for ( let i = 0 ; i < 18 ; i ++ ) {
18
+ const isOn = hash . charCodeAt ( i ) % 2 === 0
19
+
20
+ if ( i < 3 ) {
21
+ // Start with the two central columns
22
+ buffer . push ( { x : 2 , y : i , isOn } )
23
+ buffer . push ( { x : 3 , y : i , isOn } )
24
+ } else if ( i < 6 ) {
25
+ // Move out to the columns one from the edge
26
+ buffer . push ( { x : 1 , y : i - 3 , isOn } )
27
+ buffer . push ( { x : 4 , y : i - 3 , isOn } )
28
+ } else if ( i < 9 ) {
29
+ // Fill the outside columns
30
+ buffer . push ( { x : 0 , y : i - 6 , isOn } )
31
+ buffer . push ( { x : 5 , y : i - 6 , isOn } )
32
+ }
33
+ }
34
+
35
+ return buffer
36
+ }
11
37
12
38
type IdenticonProps = {
13
39
/** string used to generate the graphic */
@@ -16,6 +42,19 @@ type IdenticonProps = {
16
42
}
17
43
18
44
export function Identicon ( { name, className } : IdenticonProps ) {
19
- const content = useMemo ( ( ) => generateIdenticon ( md5 ( name ) ) , [ name ] )
20
- return < div className = { className } dangerouslySetInnerHTML = { { __html : content } } />
45
+ const pixels = useMemo ( ( ) => getPixels ( name ) , [ name ] )
46
+ return (
47
+ < div className = { className } >
48
+ < svg xmlns = "http://www.w3.org/2000/svg" width = "28" height = "28" >
49
+ < g fill = "currentColor" >
50
+ { pixels . map ( ( pixel ) => {
51
+ if ( ! pixel . isOn ) return null
52
+ const x = pixel . x * 3 + 2 * pixel . x
53
+ const y = pixel . y * 8 + 2 * pixel . y
54
+ return < rect key = { `${ x } |${ y } ` } x = { x } y = { y } width = "3" height = "8" />
55
+ } ) }
56
+ </ g >
57
+ </ svg >
58
+ </ div >
59
+ )
21
60
}
0 commit comments