-
Notifications
You must be signed in to change notification settings - Fork 13
fix: [avatar] order-sensitive getAvatarColor hash, add palette option #933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
aa66fe1
28821d8
5bb0840
5bdf673
3ecd1b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,7 @@ | ||
| export { Avatar, AvatarGroup } from './avatar'; | ||
| export { getAvatarColor } from './utils'; | ||
| export { | ||
| AVATAR_COLORS, | ||
| type AvatarColor, | ||
| type GetAvatarColorOptions, | ||
| getAvatarColor | ||
| } from './utils'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| export const COLORS = [ | ||
| export const AVATAR_COLORS = [ | ||
| 'indigo', | ||
| 'orange', | ||
| 'mint', | ||
|
|
@@ -14,10 +14,27 @@ export const COLORS = [ | |
| 'gold' | ||
| ] as const; | ||
|
|
||
| export type AVATAR_COLORS = (typeof COLORS)[number]; | ||
| export type AvatarColor = (typeof AVATAR_COLORS)[number]; | ||
|
|
||
| export function getAvatarColor(str: string): AVATAR_COLORS { | ||
| const hash = str.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0); | ||
| const index = hash % COLORS.length; | ||
| return COLORS[index]; | ||
| export interface GetAvatarColorOptions { | ||
| /** Restricts the result to these colors. Order matters. If empty, all colors are used. */ | ||
| palette?: readonly AvatarColor[]; | ||
| } | ||
|
|
||
| export function getAvatarColor( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's move the FNV-1a loop inline in getAvatarColor function. Let's not make a separate export for it
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. The loop and the bit-mix are inline in |
||
| str: string, | ||
| { palette }: GetAvatarColorOptions = {} | ||
| ): AvatarColor { | ||
| const colors = palette?.length ? palette : AVATAR_COLORS; | ||
| // 32-bit FNV-1a | ||
| let hash = 0x811c9dc5; | ||
| for (let i = 0; i < str.length; i++) { | ||
| hash ^= str.charCodeAt(i); | ||
| hash = Math.imul(hash, 0x01000193); | ||
| } | ||
| // The lowest bit of FNV-1a is an XOR of each character's lowest bit, so it | ||
| // ignores order. Mixing the high bits in keeps a 2-color palette order-sensitive. | ||
| hash ^= hash >>> 16; | ||
| hash = Math.imul(hash, 0x45d9f3b) >>> 0; | ||
| return colors[hash % colors.length]; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go easy on the tests which are doing same things multiple times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. The suite is down to 7 tests: anagrams (default and 2-color palette), a known value, empty string, palette membership, full color coverage, and a variant class for every color.