Skip to content

Commit

Permalink
Use Element Compound colours for avatars (#850)
Browse files Browse the repository at this point in the history
* Use Element Compound colours for Avatars

Signed-off-by: Michael Weimann <michael.weimann@nordeck.net>
  • Loading branch information
weeman1337 authored Nov 15, 2024
1 parent acd251f commit cde8b5b
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 40 deletions.
5 changes: 5 additions & 0 deletions .changeset/wicked-geese-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@matrix-widget-toolkit/mui': patch
---

Align avatar colours with current Element Web
14 changes: 13 additions & 1 deletion example-widget-mui/src/ThemePage/ThemePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,19 @@ export function AvatarsDemo() {
<p>Avatars can be used together with users or rooms.</p>
<Stack direction="row" gap={1} my={1}>
<ElementAvatar userId="@user:matrix.org" /> Avatar without image and
name
name (@user:matrix.org)
</Stack>
<Stack direction="row" gap={1} my={1}>
<ElementAvatar userId="@alice:matrix.org" /> Avatar without image and
name (@alice:matrix.org)
</Stack>
<Stack direction="row" gap={1} my={1}>
<ElementAvatar userId="@bob:matrix.org" /> Avatar without image and name
(@bob:matrix.org)
</Stack>
<Stack direction="row" gap={1} my={1}>
<ElementAvatar userId="@charlie:matrix.org" /> Avatar without image and
name (@charlie:matrix.org)
</Stack>
<Stack direction="row" gap={1} my={1}>
<ElementAvatar userId="@user:matrix.org" displayName="Display Name" />
Expand Down
55 changes: 50 additions & 5 deletions packages/mui/src/components/ElementAvatar/ElementAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,49 @@
import { Avatar, AvatarProps, styled } from '@mui/material';
import { forwardRef } from 'react';
import { createAvatarUrl } from './createAvatarUrl';
import { getColor } from './getColor';
import { getInitialLetter } from './getInitialLetter';
import { isColorHash, useIdColorHash } from './useIdColorHash';

/**
* {@link https://github.com/element-hq/compound-design-tokens}
*/
const bgColors = {
dark: {
1: '#002600',
2: '#001b4e',
3: '#37004e',
4: '#22006a',
5: '#450018',
6: '#470000',
},
light: {
1: '#e0f8d9',
2: '#e3f5f8',
3: '#faeefb',
4: '#f1efff',
5: '#ffecf0',
6: '#ffefe4',
},
};

const colors = {
dark: {
1: '#56c02c',
2: '#21bacd',
3: '#d991de',
4: '#ad9cfe',
5: '#fe84a2',
6: '#f6913d',
},
light: {
1: '#005f00',
2: '#00548c',
3: '#822198',
4: '#5d26cd',
5: '#9f0850',
6: '#9b2200',
},
};

/**
* Props for the {@link ElementAvatar} component.
Expand Down Expand Up @@ -46,13 +87,17 @@ export type ElementAvatarProps = {

const StyledAvatar = styled(Avatar, {
shouldForwardProp: (p) => p !== 'color',
})<{ color: string }>(({ theme, color }) => ({
})<{ colorHash: number }>(({ theme, colorHash }) => ({
// increase the specificity of the css selector to override styles of
// chip or button components that provide their own css for avatars.
'&, &&.MuiChip-avatar': {
fontSize: 18,
background: color,
color: theme.palette.common.white,
background: isColorHash(colorHash)
? bgColors[theme.palette.mode][colorHash]
: bgColors[theme.palette.mode][1],
color: isColorHash(colorHash)
? colors[theme.palette.mode][colorHash]
: colors[theme.palette.mode][1],
},

width: 24,
Expand All @@ -77,7 +122,7 @@ export const ElementAvatar = forwardRef<HTMLDivElement, ElementAvatarProps>(
alt=""
aria-hidden
src={src}
color={getColor(userId)}
colorHash={useIdColorHash(userId)}
{...props}
>
{getInitialLetter(name)}
Expand Down
28 changes: 0 additions & 28 deletions packages/mui/src/components/ElementAvatar/getColor.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@
*/

import { describe, expect, it } from 'vitest';
import { getColor } from './getColor';
import { useIdColorHash } from './useIdColorHash';

describe('getColor', () => {
it('should generate stable colors from ids', () => {
expect(getColor('@oliver.sand:matrix.org')).toBe('#ac3ba8');
expect(getColor('!OFRzoSUQYSjIXMEZDS:datanauten.de')).toBe('#368bd6');
expect(getColor('!vbSFpwCIcbnazhtFTT:matrix.org')).toBe('#007a61');
describe('useIdColorHash', () => {
it('should generate stable hashes from ids', () => {
expect(useIdColorHash('@oliver.sand:matrix.org')).toMatchInlineSnapshot(
`3`,
);
expect(
useIdColorHash('!OFRzoSUQYSjIXMEZDS:datanauten.de'),
).toMatchInlineSnapshot(`5`);
expect(
useIdColorHash('!vbSFpwCIcbnazhtFTT:matrix.org'),
).toMatchInlineSnapshot(`1`);
});
});
39 changes: 39 additions & 0 deletions packages/mui/src/components/ElementAvatar/useIdColorHash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2024 Nordeck IT + Consulting GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Determines a number for a given Matrix ID or room ID, helps disambiguating users
* who are trying to impersonate someone else.
*
* {@link https://github.com/element-hq/compound-web/blob/5950e6827aaaca5a0b2540093f0b168ca590e8ca/src/components/Avatar/useIdColorHash.ts#L23}
* @copyright Copyright 2023 New Vector Ltd
*
* @param id - a Matrix ID or room ID
* @returns a hash of the ID provided
*/
export function useIdColorHash(id: string): number {
const MIN = 1;
const MAX = 6;
// Sum up the values of all the char codes in the string
const charCodeSum = id.split('').reduce((sum, char) => {
return sum + char.charCodeAt(0);
}, 0);
return (charCodeSum % MAX) + MIN;
}

export const isColorHash = (value: number): value is 1 | 2 | 3 | 4 | 5 | 6 => {
return [1, 2, 3, 4, 5, 6].includes(value);
};

0 comments on commit cde8b5b

Please sign in to comment.