55 *
66 * Copyright Oxide Computer Company
77 */
8+ import md5 from 'md5'
89import { useMemo } from 'react'
910
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+ }
1137
1238type IdenticonProps = {
1339 /** string used to generate the graphic */
@@ -16,6 +42,19 @@ type IdenticonProps = {
1642}
1743
1844export 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+ )
2160}
0 commit comments