Skip to content
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

💄 Update avatar colors #1351

Merged
merged 5 commits into from
Sep 17, 2024
Merged

💄 Update avatar colors #1351

merged 5 commits into from
Sep 17, 2024

Conversation

lukevella
Copy link
Owner

@lukevella lukevella commented Sep 17, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a personalized fallback avatar using a seed property based on the user's name.
    • Added a new YouAvatar component for better user representation in polls.
  • Improvements

    • Enhanced visual clarity in the poll interface by conditionally rendering avatars.
    • Updated avatar color handling for more dynamic and customizable representations.
  • Bug Fixes

    • Adjusted layout and positioning of participant avatars and vote icons for improved alignment.

Copy link

vercel bot commented Sep 17, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
app 🔄 Building (Inspect) Visit Preview 💬 Add feedback Sep 17, 2024 8:04pm
landing 🛑 Canceled (Inspect) Sep 17, 2024 8:04pm

Copy link
Contributor

coderabbitai bot commented Sep 17, 2024

Walkthrough

The changes introduce a new seed property to the AvatarFallback component in the OptimizedAvatarImage function, enhancing the avatar's fallback rendering based on the user's name. The ParticipantAvatar component is modified to use this seed instead of a color prop. A new YouAvatar component is created for better user representation in polls, replacing OptimizedAvatarImage. Additionally, the avatar color handling logic is refactored to allow for dynamic color combinations based on the seed, improving the visual representation of avatars.

Changes

Files Change Summary
apps/web/src/components/optimized-avatar-image.tsx, apps/web/src/components/participant.tsx Added seed property in AvatarFallback for personalized fallback avatars based on names; removed color prop from ParticipantAvatar, shifting to seed for rendering.
apps/web/src/components/poll/desktop-poll/participant-row-form.tsx, apps/web/src/components/poll/mobile-poll.tsx Introduced YouAvatar component to enhance user representation in polls, replacing OptimizedAvatarImage.
apps/web/src/components/poll/mobile-poll/poll-option.tsx Adjusted layout and positioning of participant avatars and vote icons for improved visual alignment without altering public entity declarations.
apps/web/src/components/poll/you-avatar.tsx Introduced a new YouAvatar component that displays the current user’s avatar with multilingual support.
packages/ui/src/avatar.tsx Refactored avatar color handling logic to use dynamic color pairs based on a seed prop, enhancing the visual representation of avatars when images are unavailable.

Possibly related PRs

🐇 In a meadow bright and fair,
New avatars with flair to share.
With names as seeds, they bloom and grow,
Personalized for all to show!
Hopping forth with colors bright,
A joyful change, a pure delight! 🌼


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    -- I pushed a fix in commit <commit_id>, please review it.
    -- Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    -- @coderabbitai generate unit testing code for this file.
    -- @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    -- @coderabbitai generate interesting stats about this repository and render them as a table.
    -- @coderabbitai read src/utils.ts and generate unit testing code.
    -- @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    -- @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.
Early access features: enabled

We are currently testing the following features in early access:

  • OpenAI o1 for code reviews: OpenAI's new o1 model is being tested for generating code suggestions in code reviews.

Note:

  • You can enable or disable early access features from the CodeRabbit UI or by updating the CodeRabbit configuration file.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Outside diff range and nitpick comments (3)
apps/web/src/components/optimized-avatar-image.tsx (1)

43-45: Consider handling size values between 25 and 47

In the className assignment for AvatarFallback, only sizes <= 24 and >= 48 have text size classes applied. For sizes between 25 and 47, no class is applied, which may lead to inconsistent styling or unexpected text sizes. Consider adding a default text size class or adjusting the conditions to ensure consistent appearance across all sizes.

apps/web/src/components/poll/mobile-poll.tsx (2)

125-125: Ensure Consistent Rendering of Participant Avatars

In the current user's participant view, you have used the YouAvatar component:

<Participant>
  <YouAvatar />
  <ParticipantName>{t("you")}</ParticipantName>
</Participant>

Elsewhere, for other participants, you use OptimizedAvatarImage with the participant's name:

<Participant>
  <OptimizedAvatarImage
    name={participant.name}
    size={20}
  />
  <ParticipantName>{participant.name}</ParticipantName>
  {session.ownsObject(participant) && (
    <Badge>
      <Trans i18nKey="you" />
    </Badge>
  )}
</Participant>

Consider whether the YouAvatar component should accept props like name and size for consistency, or if the current differentiation is intentional. Ensuring consistent avatar rendering enhances the user experience.


Line range hint 125-129: Refactor Common Participant Rendering Logic

There is duplicated code in how participants are rendered, with slight variations for the current user and others. To improve maintainability and reduce duplication, consider refactoring the common elements into a shared component or function.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 554e4fe and 6381dfe.

Files selected for processing (7)
  • apps/web/src/components/optimized-avatar-image.tsx (1 hunks)
  • apps/web/src/components/participant.tsx (2 hunks)
  • apps/web/src/components/poll/desktop-poll/participant-row-form.tsx (2 hunks)
  • apps/web/src/components/poll/mobile-poll.tsx (2 hunks)
  • apps/web/src/components/poll/mobile-poll/poll-option.tsx (1 hunks)
  • apps/web/src/components/poll/you-avatar.tsx (1 hunks)
  • packages/ui/src/avatar.tsx (1 hunks)
Additional comments not posted (8)
apps/web/src/components/poll/you-avatar.tsx (1)

3-5: Component implementation looks good

The YouAvatar component is well-implemented, and the use of the useTranslation hook is appropriate for internationalization.

apps/web/src/components/optimized-avatar-image.tsx (1)

42-42: Change looks good

The addition of seed={name} to AvatarFallback enhances the component by allowing for more personalized fallback avatars based on the user's name.

apps/web/src/components/participant.tsx (1)

18-20: Change to AvatarFallback is appropriate

The switch from using the color prop with getColor(name) to using the seed prop with name in AvatarFallback appears correct. This should ensure consistent avatar representations based on the participant's name.

packages/ui/src/avatar.tsx (1)

38-50: LGTM! The color pairs are well-defined and enhance visual appeal

The colorPairs array provides a diverse set of background and text color combinations that will improve the visual aesthetics of the avatar component.

apps/web/src/components/poll/desktop-poll/participant-row-form.tsx (2)

64-68: Conditional rendering logic is correct

The conditional rendering based on the presence of name is appropriate. It enhances the user interface by displaying a personalized avatar for participants and a distinct avatar for the current user.


18-18: Verify the import of 'YouAvatar' component

Ensure that the YouAvatar component exists at the specified path and is correctly exported from @/components/poll/you-avatar.

You can run the following script to confirm the existence and export of YouAvatar:

Verification successful

To further investigate the issue and locate the correct file, I'll run additional scripts to search for the 'YouAvatar' component.


To complete our verification, we need to examine the contents of the 'you-avatar.tsx' file to understand how 'YouAvatar' is exported.


Based on the analysis, we can now provide a final response regarding the verification of the 'YouAvatar' import.

Import of 'YouAvatar' component is correct

The 'YouAvatar' component is correctly defined and exported from '@/components/poll/you-avatar.tsx'. The import statement in 'participant-row-form.tsx' matches the export, using the correct named import syntax. No issues were found with the import of the 'YouAvatar' component.

  • The component is exported as a named function: export function YouAvatar() { ... }
  • The import statement import { YouAvatar } from "@/components/poll/you-avatar"; correctly references this export
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that 'YouAvatar' is exported from '@/components/poll/you-avatar'.

# Test: Search for the export statement of 'YouAvatar'. Expect: At least one match.
ast-grep --lang tsx --pattern 'export const YouAvatar = $_' src/components/poll/you-avatar.tsx

Length of output: 178


Script:

#!/bin/bash
# Search for 'you-avatar.tsx' file in the repository
fd -e tsx -e ts 'you-avatar' 

# If the above doesn't find anything, search for files containing 'YouAvatar'
rg -l 'YouAvatar'

# If a file is found, check for the export of 'YouAvatar'
# Note: This command will run for all matching files, which might not be ideal if there are many matches
fd -e tsx -e ts 'you-avatar' -x ast-grep --lang tsx --pattern 'export const YouAvatar = $_' {}

Length of output: 343


Script:

#!/bin/bash
# Display the contents of the you-avatar.tsx file
cat apps/web/src/components/poll/you-avatar.tsx

# Search for any export statements related to YouAvatar
rg 'export.*YouAvatar' apps/web/src/components/poll/you-avatar.tsx

Length of output: 429

apps/web/src/components/poll/mobile-poll/poll-option.tsx (1)

77-77: Adjustment of closing </div> tag is appropriate

The closing </div> tag at line 77 correctly aligns with the modified JSX structure, ensuring proper rendering of the component.

apps/web/src/components/poll/mobile-poll.tsx (1)

23-23: Import of YouAvatar Component Is Correct

The import statement for the YouAvatar component is appropriately added and follows the project's conventions.


return (
<div className="inline-flex size-5 items-center justify-center rounded-full bg-gray-200 text-xs font-medium">
{t("you")[0]}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential localization issue when extracting the first character

Using t("you")[0] extracts the first character of the translated word for "you". This approach may not work correctly in all languages, especially those with non-Latin scripts or where the word for "you" is more than one character. This could lead to incorrect or unintelligible displays for users in different locales.

Consider the following alternatives:

  • Use an Icon: Replace the text with a user icon that universally represents the current user.

    -      {t("you")[0]}
    +      <UserIcon />
  • Display the Full Word: Show the entire translated word to ensure clarity across all languages.

    -      {t("you")[0]}
    +      {t("you")}
  • Use Initials with Caution: If initials are important, implement a function that handles locale-specific considerations, possibly using libraries that support transliteration.

Ensure that the chosen solution provides a consistent and understandable experience for all users regardless of their language settings.

Committable suggestion was skipped due to low confidence.

Comment on lines +69 to +85
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> & {
seed: string;
}
>(({ className, seed, ...props }, ref) => {
const { bgColor, textColor } = getColor(seed);
return (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full font-medium",
className,
)}
style={{ backgroundColor: bgColor, color: textColor }}
{...props}
/>
);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the seed prop optional in AvatarFallback for consistency

Since the getColor function handles an undefined seed by providing default colors, making the seed prop optional in AvatarFallback would align the component's behavior with the function. This enhances flexibility and avoids potential errors if seed isn't provided.

Apply this diff to update the prop type:

 React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> & {
-  seed: string;
+  seed?: string;
 }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> & {
seed: string;
}
>(({ className, seed, ...props }, ref) => {
const { bgColor, textColor } = getColor(seed);
return (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full font-medium",
className,
)}
style={{ backgroundColor: bgColor, color: textColor }}
{...props}
/>
);
});
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> & {
seed?: string;
}
>(({ className, seed, ...props }, ref) => {
const { bgColor, textColor } = getColor(seed);
return (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full font-medium",
className,
)}
style={{ backgroundColor: bgColor, color: textColor }}
{...props}
/>
);
});

Comment on lines +52 to +64
export function getColor(seed?: string): {
bgColor: string;
textColor: string;
} {
if (!seed) {
return { bgColor: "#E6F4FF", textColor: "#0065BD" };
}
let hash = 0;
for (let i = 0; i < seed.length; i++) {
hash = seed.charCodeAt(i) + ((hash << 5) - hash);
}
return avatarColors[Math.abs(hash) % avatarColors.length];
const colorPair = colorPairs[Math.abs(hash) % colorPairs.length];
return { bgColor: colorPair.bg, textColor: colorPair.text };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using a more robust hash function for better color distribution

The current hash function may lead to uneven color distribution for similar seed strings, resulting in less variation than expected. Utilizing a more robust hashing algorithm could improve the randomness and ensure a more uniform assignment of colors.

Apply this diff to update the hash function:

+import crypto from 'crypto';

 export function getColor(seed?: string): {
   bgColor: string;
   textColor: string;
 } {
   if (!seed) {
     return { bgColor: "#E6F4FF", textColor: "#0065BD" };
   }
-  let hash = 0;
-  for (let i = 0; i < seed.length; i++) {
-    hash = seed.charCodeAt(i) + ((hash << 5) - hash);
-  }
-  const colorPair = colorPairs[Math.abs(hash) % colorPairs.length];
+  const hash = crypto.createHash('sha256').update(seed).digest('hex');
+  const hashInt = parseInt(hash.substring(0, 8), 16);
+  const colorPair = colorPairs[hashInt % colorPairs.length];
   return { bgColor: colorPair.bg, textColor: colorPair.text };
 }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function getColor(seed?: string): {
bgColor: string;
textColor: string;
} {
if (!seed) {
return { bgColor: "#E6F4FF", textColor: "#0065BD" };
}
let hash = 0;
for (let i = 0; i < seed.length; i++) {
hash = seed.charCodeAt(i) + ((hash << 5) - hash);
}
return avatarColors[Math.abs(hash) % avatarColors.length];
const colorPair = colorPairs[Math.abs(hash) % colorPairs.length];
return { bgColor: colorPair.bg, textColor: colorPair.text };
import crypto from 'crypto';
export function getColor(seed?: string): {
bgColor: string;
textColor: string;
} {
if (!seed) {
return { bgColor: "#E6F4FF", textColor: "#0065BD" };
}
const hash = crypto.createHash('sha256').update(seed).digest('hex');
const hashInt = parseInt(hash.substring(0, 8), 16);
const colorPair = colorPairs[hashInt % colorPairs.length];
return { bgColor: colorPair.bg, textColor: colorPair.text };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant