From 3079747c83d909b22a0dc2230fe479f79cd86056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20M?= Date: Mon, 10 Jul 2023 20:24:09 +0200 Subject: [PATCH] feat: colored avatar (#554) * feat: colored avatar * fix: use id instead of name & remove unused * fix: remove unused * Allow empty ID to avoid empty string * Fix tests * Add person chip story --------- Co-authored-by: Emilien --- .../CommentThreadRelationPicker.tsx | 2 +- .../components/comment/CommentHeader.tsx | 8 +-- .../components/CompanyAccountOwnerCell.tsx | 5 +- .../companies/components/CompanyChip.tsx | 7 ++- .../components/CompanyEditableNameCell.tsx | 2 +- .../__stories__/CompanyChip.stories.tsx | 25 ++++++---- .../people/components/PeopleCompanyCell.tsx | 2 +- .../modules/people/components/PersonChip.tsx | 14 +++--- .../__stories__/PeopleChip.stories.tsx | 47 ++++++++++++++++++ .../people/components/person-placeholder.png | Bin 14342 -> 0 bytes .../components/MultipleEntitySelect.tsx | 1 + .../components/SingleEntitySelectBase.tsx | 1 + .../layout/show-page/ShowPageSummaryCard.tsx | 15 ++++-- front/src/modules/users/components/Avatar.tsx | 29 ++++++----- front/src/modules/utils/string-to-hsl.ts | 13 +++++ .../components/WorkspaceMemberCard.tsx | 3 +- front/src/pages/companies/CompanyShow.tsx | 1 + front/src/pages/people/PersonShow.tsx | 1 + 18 files changed, 129 insertions(+), 47 deletions(-) create mode 100644 front/src/modules/people/components/__stories__/PeopleChip.stories.tsx delete mode 100644 front/src/modules/people/components/person-placeholder.png create mode 100644 front/src/modules/utils/string-to-hsl.ts diff --git a/front/src/modules/comments/components/comment-thread/CommentThreadRelationPicker.tsx b/front/src/modules/comments/components/comment-thread/CommentThreadRelationPicker.tsx index 3c465d006..4eb623301 100644 --- a/front/src/modules/comments/components/comment-thread/CommentThreadRelationPicker.tsx +++ b/front/src/modules/comments/components/comment-thread/CommentThreadRelationPicker.tsx @@ -10,7 +10,7 @@ import { import { useHandleCheckableCommentThreadTargetChange } from '@/comments/hooks/useHandleCheckableCommentThreadTargetChange'; import { CommentableEntityForSelect } from '@/comments/types/CommentableEntityForSelect'; -import CompanyChip from '@/companies/components/CompanyChip'; +import { CompanyChip } from '@/companies/components/CompanyChip'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { PersonChip } from '@/people/components/PersonChip'; diff --git a/front/src/modules/comments/components/comment/CommentHeader.tsx b/front/src/modules/comments/components/comment/CommentHeader.tsx index 3de95b834..c856f8126 100644 --- a/front/src/modules/comments/components/comment/CommentHeader.tsx +++ b/front/src/modules/comments/components/comment/CommentHeader.tsx @@ -8,7 +8,6 @@ import { beautifyExactDate, beautifyPastDateRelativeToNow, } from '@/utils/datetime/date-utils'; -import { isNonEmptyString } from '@/utils/type-guards/isNonEmptyString'; type OwnProps = { comment: Pick; @@ -74,17 +73,14 @@ export function CommentHeader({ comment, actionBar }: OwnProps) { const avatarUrl = author.avatarUrl; const commentId = comment.id; - const capitalizedFirstUsernameLetter = isNonEmptyString(authorName) - ? authorName.toLocaleUpperCase()[0] - : ''; - return ( {authorName} {showDate && ( diff --git a/front/src/modules/companies/components/CompanyAccountOwnerCell.tsx b/front/src/modules/companies/components/CompanyAccountOwnerCell.tsx index 2dbf0b1ff..51a07641a 100644 --- a/front/src/modules/companies/components/CompanyAccountOwnerCell.tsx +++ b/front/src/modules/companies/components/CompanyAccountOwnerCell.tsx @@ -16,7 +16,10 @@ export function CompanyAccountOwnerCell({ company }: OwnProps) { editModeContent={} nonEditModeContent={ company.accountOwner?.displayName ? ( - + ) : ( <> ) diff --git a/front/src/modules/companies/components/CompanyChip.tsx b/front/src/modules/companies/components/CompanyChip.tsx index 91e3cf94f..73610d726 100644 --- a/front/src/modules/companies/components/CompanyChip.tsx +++ b/front/src/modules/companies/components/CompanyChip.tsx @@ -5,7 +5,7 @@ import styled from '@emotion/styled'; import { Avatar } from '@/users/components/Avatar'; export type CompanyChipPropsType = { - id?: string; + id: string; name: string; picture?: string; }; @@ -50,7 +50,7 @@ const StyledContainerNoLink = styled.div` ${baseStyle} `; -function CompanyChip({ id, name, picture }: CompanyChipPropsType) { +export function CompanyChip({ id, name, picture }: CompanyChipPropsType) { const ContainerComponent = id ? StyledContainerLink : StyledContainerNoLink; return ( @@ -58,6 +58,7 @@ function CompanyChip({ id, name, picture }: CompanyChipPropsType) { {picture && ( ); } - -export default CompanyChip; diff --git a/front/src/modules/companies/components/CompanyEditableNameCell.tsx b/front/src/modules/companies/components/CompanyEditableNameCell.tsx index 12d888ba7..94047aa6e 100644 --- a/front/src/modules/companies/components/CompanyEditableNameCell.tsx +++ b/front/src/modules/companies/components/CompanyEditableNameCell.tsx @@ -8,7 +8,7 @@ import { useUpdateCompanyMutation, } from '~/generated/graphql'; -import CompanyChip from './CompanyChip'; +import { CompanyChip } from './CompanyChip'; type OwnProps = { company: Pick< diff --git a/front/src/modules/companies/components/__stories__/CompanyChip.stories.tsx b/front/src/modules/companies/components/__stories__/CompanyChip.stories.tsx index 54c37f3dd..119682e99 100644 --- a/front/src/modules/companies/components/__stories__/CompanyChip.stories.tsx +++ b/front/src/modules/companies/components/__stories__/CompanyChip.stories.tsx @@ -1,9 +1,10 @@ +import { BrowserRouter } from 'react-router-dom'; import styled from '@emotion/styled'; import type { Meta, StoryObj } from '@storybook/react'; import { getRenderWrapperForComponent } from '~/testing/renderWrappers'; -import CompanyChip from '../CompanyChip'; +import { CompanyChip } from '../CompanyChip'; const meta: Meta = { title: 'Modules/Companies/CompanyChip', @@ -32,10 +33,13 @@ const TestCellContainer = styled.div` export const SmallName: Story = { render: getRenderWrapperForComponent( - + + + , ), }; @@ -43,10 +47,13 @@ export const SmallName: Story = { export const BigName: Story = { render: getRenderWrapperForComponent( - + + + , ), }; diff --git a/front/src/modules/people/components/PeopleCompanyCell.tsx b/front/src/modules/people/components/PeopleCompanyCell.tsx index 4df2f1602..1b90c62ed 100644 --- a/front/src/modules/people/components/PeopleCompanyCell.tsx +++ b/front/src/modules/people/components/PeopleCompanyCell.tsx @@ -1,4 +1,4 @@ -import CompanyChip from '@/companies/components/CompanyChip'; +import { CompanyChip } from '@/companies/components/CompanyChip'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { EditableCell } from '@/ui/components/editable-cell/EditableCell'; diff --git a/front/src/modules/people/components/PersonChip.tsx b/front/src/modules/people/components/PersonChip.tsx index e7b656ceb..012bb145a 100644 --- a/front/src/modules/people/components/PersonChip.tsx +++ b/front/src/modules/people/components/PersonChip.tsx @@ -3,10 +3,10 @@ import { Link } from 'react-router-dom'; import { Theme } from '@emotion/react'; import styled from '@emotion/styled'; -import PersonPlaceholder from './person-placeholder.png'; +import { Avatar } from '@/users/components/Avatar'; export type PersonChipPropsType = { - id?: string; + id: string; name: string; picture?: string; }; @@ -52,10 +52,12 @@ export function PersonChip({ id, name, picture }: PersonChipPropsType) { const ContainerComponent = id ? StyledContainerLink : StyledContainerNoLink; return ( - person {name} diff --git a/front/src/modules/people/components/__stories__/PeopleChip.stories.tsx b/front/src/modules/people/components/__stories__/PeopleChip.stories.tsx new file mode 100644 index 000000000..b3ca5a646 --- /dev/null +++ b/front/src/modules/people/components/__stories__/PeopleChip.stories.tsx @@ -0,0 +1,47 @@ +import { BrowserRouter } from 'react-router-dom'; +import styled from '@emotion/styled'; +import type { Meta, StoryObj } from '@storybook/react'; + +import { getRenderWrapperForComponent } from '~/testing/renderWrappers'; + +import { PersonChip } from '../PersonChip'; + +const meta: Meta = { + title: 'Modules/Companies/PersonChip', + component: PersonChip, +}; + +export default meta; +type Story = StoryObj; + +const TestCellContainer = styled.div` + align-items: center; + background: ${({ theme }) => theme.background.primary}; + display: flex; + height: fit-content; + justify-content: space-between; + max-width: 250px; + min-width: 250px; + overflow: hidden; + text-wrap: nowrap; +`; + +export const SmallName: Story = { + render: getRenderWrapperForComponent( + + + + + , + ), +}; + +export const BigName: Story = { + render: getRenderWrapperForComponent( + + + + + , + ), +}; diff --git a/front/src/modules/people/components/person-placeholder.png b/front/src/modules/people/components/person-placeholder.png deleted file mode 100644 index 8beb87a117f76a6d853a1d9ed7ad2a4f8f7ed829..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14342 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 diff --git a/front/src/modules/relation-picker/components/MultipleEntitySelect.tsx b/front/src/modules/relation-picker/components/MultipleEntitySelect.tsx index 53b47d4f9..9d44f9d24 100644 --- a/front/src/modules/relation-picker/components/MultipleEntitySelect.tsx +++ b/front/src/modules/relation-picker/components/MultipleEntitySelect.tsx @@ -71,6 +71,7 @@ export function MultipleEntitySelect< > diff --git a/front/src/modules/users/components/Avatar.tsx b/front/src/modules/users/components/Avatar.tsx index 9612d1f80..99b170404 100644 --- a/front/src/modules/users/components/Avatar.tsx +++ b/front/src/modules/users/components/Avatar.tsx @@ -1,5 +1,6 @@ import styled from '@emotion/styled'; +import { stringToHslColor } from '@/utils/string-to-hsl'; import { isNonEmptyString } from '@/utils/type-guards/isNonEmptyString'; export type AvatarType = 'squared' | 'rounded'; @@ -8,26 +9,23 @@ type OwnProps = { avatarUrl: string | null | undefined; size: number; placeholder: string; + colorId?: string; type?: AvatarType; }; -export const StyledAvatar = styled.div>` +export const StyledAvatar = styled.div` align-items: center; - background-color: ${(props) => - !isNonEmptyString(props.avatarUrl) - ? props.theme.background.tertiary - : 'none'}; - ${(props) => - isNonEmptyString(props.avatarUrl) - ? `background-image: url(${props.avatarUrl});` - : ''} + background-color: ${({ avatarUrl, colorId }) => + !isNonEmptyString(avatarUrl) ? stringToHslColor(colorId, 75, 85) : 'none'}; + ${({ avatarUrl }) => + isNonEmptyString(avatarUrl) ? `background-image: url(${avatarUrl});` : ''} background-size: cover; border-radius: ${(props) => (props.type === 'rounded' ? '50%' : '2px')}; - color: ${({ theme }) => theme.font.color.primary}; + color: ${({ colorId }) => stringToHslColor(colorId, 75, 25)}; display: flex; flex-shrink: 0; - font-size: ${({ theme }) => theme.font.size.sm}; + font-size: ${({ theme }) => theme.font.size.xs}; font-weight: ${({ theme }) => theme.font.weight.medium}; height: ${(props) => props.size}px; @@ -39,12 +37,19 @@ export function Avatar({ avatarUrl, size, placeholder, + colorId = placeholder, type = 'squared', }: OwnProps) { const noAvatarUrl = !isNonEmptyString(avatarUrl); return ( - + {noAvatarUrl && placeholder[0]?.toLocaleUpperCase()} ); diff --git a/front/src/modules/utils/string-to-hsl.ts b/front/src/modules/utils/string-to-hsl.ts new file mode 100644 index 000000000..87ab93281 --- /dev/null +++ b/front/src/modules/utils/string-to-hsl.ts @@ -0,0 +1,13 @@ +export function stringToHslColor( + str: string, + saturation: number, + lightness: number, +) { + let hash = 0; + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + + const h = hash % 360; + return 'hsl(' + h + ', ' + saturation + '%, ' + lightness + '%)'; +} diff --git a/front/src/modules/workspace/components/WorkspaceMemberCard.tsx b/front/src/modules/workspace/components/WorkspaceMemberCard.tsx index 74cc05f05..b5ca0a4ec 100644 --- a/front/src/modules/workspace/components/WorkspaceMemberCard.tsx +++ b/front/src/modules/workspace/components/WorkspaceMemberCard.tsx @@ -33,7 +33,7 @@ const EmailText = styled.span` type OwnProps = { workspaceMember: { - user: Pick; + user: Pick; }; accessory?: React.ReactNode; }; @@ -43,6 +43,7 @@ export function WorkspaceMemberCard({ workspaceMember, accessory }: OwnProps) {