1
1
"use client" ;
2
2
import { hexToNumber } from "@noble/curves/abstract/utils" ;
3
3
import { useId , useMemo } from "react" ;
4
- import { type Address , numberToHex } from "viem" ;
4
+ import type { Address } from "viem" ;
5
5
6
- // Distance between 2 colors (in RGB)
7
- type Color = [ number , number , number ] ;
8
- function hexToRgb ( hex : string ) {
9
- return [
10
- Number ( hexToNumber ( hex . slice ( 0 , 2 ) ) ) ,
11
- Number ( hexToNumber ( hex . slice ( 2 , 4 ) ) ) ,
12
- Number ( hexToNumber ( hex . slice ( 4 , 6 ) ) ) ,
13
- ] satisfies [ number , number , number ] ;
14
- }
6
+ const COLOR_OPTIONS = [
7
+ [ "#fca5a5" , "#b91c1c" ] ,
8
+ [ "#fdba74" , "#c2410c" ] ,
9
+ [ "#fcd34d" , "#b45309" ] ,
10
+ [ "#fde047" , "#a16207" ] ,
11
+ [ "#a3e635" , "#4d7c0f" ] ,
12
+ [ "#86efac" , "#15803d" ] ,
13
+ [ "#67e8f9" , "#0e7490" ] ,
14
+ [ "#7dd3fc" , "#0369a1" ] ,
15
+ [ "#93c5fd" , "#1d4ed8" ] ,
16
+ [ "#a5b4fc" , "#4338ca" ] ,
17
+ [ "#c4b5fd" , "#6d28d9" ] ,
18
+ [ "#d8b4fe" , "#7e22ce" ] ,
19
+ [ "#f0abfc" , "#a21caf" ] ,
20
+ [ "#f9a8d4" , "#be185d" ] ,
21
+ [ "#fda4af" , "#be123c" ] ,
22
+ ] ;
15
23
16
24
/**
17
25
* A unique gradient avatar based on the provided address.
@@ -21,114 +29,22 @@ function hexToRgb(hex: string) {
21
29
*/
22
30
export function Blobbie ( props : { address : Address ; size : number } ) {
23
31
const id = useId ( ) ;
24
- const colors : [ string , string , string ] = useMemo ( ( ) => {
25
- const color = props . address . slice ( 2 , 8 ) ;
26
- const rgb = hexToRgb ( color ) ;
27
-
28
- // To get well-paired colors, we use the first rgb hex sequence as our main color then find its two best pairs (split color wheel into thirds)
29
- // To prevent extremely dark colors, which tend to clash, we don't allow values less than 55
30
- const pairing1 = rgb . map ( ( n ) => ( n + 85 > 255 ? n + 85 - 200 : n + 85 ) ) ;
31
- const pairing2 = rgb . map ( ( n ) => ( n - 85 < 55 ? n - 85 + 200 : n - 85 ) ) ;
32
- return [
33
- color ,
34
- pairing1 . map ( ( n ) => numberToHex ( n ) . replace ( "0x" , "" ) ) . join ( "" ) ,
35
- pairing2 . map ( ( n ) => numberToHex ( n ) . replace ( "0x" , "" ) ) . join ( "" ) ,
36
- ] ;
37
- } , [ props . address ] ) ;
38
-
39
- const positions : [ Color , Color , Color , Color , Color ] = useMemo ( ( ) => {
40
- const _positions : Color [ ] = [ ] ;
41
- let i = 8 ;
42
- while ( i < 44 ) {
43
- const values = hexToRgb ( props . address . slice ( i , i + 6 ) ) ;
44
- _positions . push ( values ) ;
45
- i += 6 ;
46
- }
47
- return _positions as [ Color , Color , Color , Color , Color ] ;
48
- } , [ props . address ] ) ;
49
-
50
- console . log ( colors ) ;
32
+ const colors = useMemo (
33
+ ( ) =>
34
+ COLOR_OPTIONS [
35
+ Number ( hexToNumber ( props . address . slice ( 2 , 4 ) ) ) % COLOR_OPTIONS . length
36
+ ] as [ string , string ] ,
37
+ [ props . address ] ,
38
+ ) ;
51
39
52
40
return (
53
- < svg
54
- height = { `${ props . size } px` }
55
- style = { { background : "#FFFFFF" } }
56
- width = { `${ props . size } px` }
57
- role = "presentation"
58
- viewBox = "0 0 500 500"
59
- xmlns = "http://www.w3.org/2000/svg"
60
- >
61
- < defs >
62
- { colors . map ( ( color , idx ) => {
63
- return (
64
- < radialGradient
65
- id = { `${ id } _grad${ idx + 1 } ` }
66
- cx = "50%"
67
- cy = "50%"
68
- r = "50%"
69
- key = { `grad${
70
- // biome-ignore lint/suspicious/noArrayIndexKey: Jonas said so
71
- idx
72
- } `}
73
- >
74
- < stop
75
- offset = "0%"
76
- style = { { stopColor : `#${ color } ` , stopOpacity : 0.9 } }
77
- />
78
- < stop
79
- offset = "100%"
80
- style = { { stopColor : `#${ color } ` , stopOpacity : 0 } }
81
- />
82
- </ radialGradient >
83
- ) ;
84
- } ) }
85
- </ defs >
86
-
87
- < ellipse
88
- cx = "250"
89
- cy = "250"
90
- rx = "500"
91
- ry = "500"
92
- fill = { `url(#${ id } _grad1)` }
93
- opacity = { 0.5 }
94
- />
95
- < ellipse
96
- cx = { 400 + positions [ 0 ] [ 0 ] }
97
- cy = { 400 + positions [ 0 ] [ 1 ] }
98
- rx = { 350 + positions [ 0 ] [ 2 ] }
99
- ry = { 350 + positions [ 0 ] [ 2 ] }
100
- fill = { `url(#${ id } _grad1)` }
101
- />
102
- < ellipse
103
- cx = { positions [ 1 ] [ 0 ] }
104
- cy = { positions [ 1 ] [ 1 ] }
105
- rx = { 350 + positions [ 1 ] [ 2 ] }
106
- ry = { 350 + positions [ 1 ] [ 2 ] }
107
- fill = { `url(#${ id } _grad2)` }
108
- />
109
- < ellipse
110
- cx = { 400 + positions [ 2 ] [ 0 ] }
111
- cy = { positions [ 2 ] [ 1 ] }
112
- rx = { 350 + positions [ 2 ] [ 2 ] }
113
- ry = { 350 + positions [ 2 ] [ 2 ] }
114
- fill = { `url(#${ id } _grad3)` }
115
- />
116
- < ellipse
117
- cx = { positions [ 3 ] [ 0 ] }
118
- cy = { positions [ 3 ] [ 1 ] }
119
- rx = { 100 + positions [ 3 ] [ 2 ] }
120
- ry = { 100 + positions [ 3 ] [ 2 ] }
121
- fill = { `url(#${ id } _grad2)` }
122
- opacity = { 0.5 }
123
- />
124
- < ellipse
125
- cx = { positions [ 4 ] [ 0 ] }
126
- cy = { positions [ 4 ] [ 1 ] }
127
- rx = { 100 + positions [ 4 ] [ 2 ] }
128
- ry = { 100 + positions [ 4 ] [ 2 ] }
129
- fill = { `url(#${ id } _grad3)` }
130
- opacity = { 0.5 }
131
- />
132
- </ svg >
41
+ < div
42
+ id = { id }
43
+ style = { {
44
+ width : `${ props . size } px` ,
45
+ height : `${ props . size } px` ,
46
+ backgroundImage : `radial-gradient(ellipse at left bottom, ${ colors [ 0 ] } , ${ colors [ 1 ] } )` ,
47
+ } }
48
+ />
133
49
) ;
134
50
}
0 commit comments