diff --git a/apps/web/src/components/optimized-avatar-image.tsx b/apps/web/src/components/optimized-avatar-image.tsx index e528bcae3..51b43df59 100644 --- a/apps/web/src/components/optimized-avatar-image.tsx +++ b/apps/web/src/components/optimized-avatar-image.tsx @@ -39,6 +39,7 @@ export function OptimizedAvatarImage({ ) : null} {!src || !isLoaded ? ( = 48, diff --git a/apps/web/src/components/participant.tsx b/apps/web/src/components/participant.tsx index 1cdffa8ac..940cf9bbe 100644 --- a/apps/web/src/components/participant.tsx +++ b/apps/web/src/components/participant.tsx @@ -1,5 +1,5 @@ import { cn } from "@rallly/ui"; -import { Avatar, AvatarFallback, getColor } from "@rallly/ui/avatar"; +import { Avatar, AvatarFallback } from "@rallly/ui/avatar"; import React from "react"; export function Participant({ children }: { children: React.ReactNode }) { @@ -13,11 +13,9 @@ export const ParticipantAvatar = ({ size?: number; name: string; }) => { - const color = getColor(name); - return ( - + {name[0]?.toUpperCase()} diff --git a/apps/web/src/components/poll/desktop-poll/participant-row-form.tsx b/apps/web/src/components/poll/desktop-poll/participant-row-form.tsx index e64a7354e..4b6ca5d27 100644 --- a/apps/web/src/components/poll/desktop-poll/participant-row-form.tsx +++ b/apps/web/src/components/poll/desktop-poll/participant-row-form.tsx @@ -15,6 +15,7 @@ import { Controller } from "react-hook-form"; import { OptimizedAvatarImage } from "@/components/optimized-avatar-image"; import { Participant, ParticipantName } from "@/components/participant"; import { useVotingForm } from "@/components/poll/voting-form"; +import { YouAvatar } from "@/components/poll/you-avatar"; import { Trans } from "@/components/trans"; import { usePoll } from "../../poll-context"; @@ -60,7 +61,11 @@ const ParticipantRowForm = ({ >
- + {name ? ( + + ) : ( + + )} {participantName} {!isNew ? ( diff --git a/apps/web/src/components/poll/mobile-poll.tsx b/apps/web/src/components/poll/mobile-poll.tsx index 7b6aee7dd..010be35b2 100644 --- a/apps/web/src/components/poll/mobile-poll.tsx +++ b/apps/web/src/components/poll/mobile-poll.tsx @@ -20,6 +20,7 @@ import { OptimizedAvatarImage } from "@/components/optimized-avatar-image"; import { Participant, ParticipantName } from "@/components/participant"; import { ParticipantDropdown } from "@/components/participant-dropdown"; import { useVotingForm } from "@/components/poll/voting-form"; +import { YouAvatar } from "@/components/poll/you-avatar"; import { useOptions, usePoll } from "@/components/poll-context"; import { Trans } from "@/components/trans"; import { usePermissions } from "@/contexts/permissions"; @@ -121,7 +122,7 @@ const MobilePoll: React.FunctionComponent = () => { ) : (
- + {t("you")}
diff --git a/apps/web/src/components/poll/mobile-poll/poll-option.tsx b/apps/web/src/components/poll/mobile-poll/poll-option.tsx index b179f2dbf..7065fdd9a 100644 --- a/apps/web/src/components/poll/mobile-poll/poll-option.tsx +++ b/apps/web/src/components/poll/mobile-poll/poll-option.tsx @@ -61,8 +61,6 @@ const PollOptionVoteSummary: React.FunctionComponent<{ optionId: string }> = ({
{name}
))} - -
{participantsWhoVotedIfNeedBe.map(({ name }, i) => (
@@ -70,12 +68,14 @@ const PollOptionVoteSummary: React.FunctionComponent<{ optionId: string }> = ({
{name}
))} +
+
{participantsWhoVotedNo.map(({ name }, i) => (
@@ -83,7 +83,7 @@ const PollOptionVoteSummary: React.FunctionComponent<{ optionId: string }> = ({
{name}
diff --git a/apps/web/src/components/poll/you-avatar.tsx b/apps/web/src/components/poll/you-avatar.tsx new file mode 100644 index 000000000..44a4ff0a4 --- /dev/null +++ b/apps/web/src/components/poll/you-avatar.tsx @@ -0,0 +1,11 @@ +import { useTranslation } from "@/app/i18n/client"; + +export function YouAvatar() { + const { t } = useTranslation(); + + return ( +
+ {t("you")[0]} +
+ ); +} diff --git a/packages/ui/src/avatar.tsx b/packages/ui/src/avatar.tsx index b7986a7fe..60b8085bc 100644 --- a/packages/ui/src/avatar.tsx +++ b/packages/ui/src/avatar.tsx @@ -2,24 +2,9 @@ import * as React from "react"; import * as AvatarPrimitive from "@radix-ui/react-avatar"; -import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@rallly/ui"; -export const avatarColors = [ - "indigo", - "green", - "blue", - "purple", - "emerald", - "violet", - "sky", - "cyan", - "pink", -] as const; - -export type AvatarColor = (typeof avatarColors)[number]; - const Avatar = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { @@ -50,47 +35,54 @@ const AvatarImage = React.forwardRef< )); AvatarImage.displayName = AvatarPrimitive.Image.displayName; -const avatarFallbackVariants = cva( - "flex h-full w-full items-center justify-center rounded-full font-medium", - { - variants: { - color: { - indigo: "bg-indigo-50 text-indigo-600", - green: "bg-green-50 text-green-600", - blue: "bg-blue-50 text-blue-600", - purple: "bg-purple-50 text-purple-600", - emerald: "bg-emerald-50 text-emerald-600", - violet: "bg-violet-50 text-violet-600", - sky: "bg-sky-50 text-sky-600", - cyan: "bg-cyan-50 text-cyan-600", - pink: "bg-pink-50 text-pink-600", - }, - }, - defaultVariants: { - color: "indigo", - }, - }, -); +const colorPairs = [ + { bg: "#E6F4FF", text: "#0065BD" }, // Light blue + { bg: "#DCFCE7", text: "#15803D" }, // Light green + { bg: "#FFE6F4", text: "#BD007A" }, // Light pink + { bg: "#F4E6FF", text: "#6200BD" }, // Light purple + { bg: "#FFE6E6", text: "#BD0000" }, // Light red + { bg: "#FFE6FF", text: "#A300A3" }, // Bright pink + { bg: "#F0E6FF", text: "#5700BD" }, // Lavender + { bg: "#FFE6F9", text: "#BD0066" }, // Rose + { bg: "#E6E6FF", text: "#0000BD" }, // Periwinkle + { bg: "#FFE6EC", text: "#BD001F" }, // Salmon pink + { bg: "#EBE6FF", text: "#4800BD" }, // Light indigo +]; -export function getColor(seed: string): AvatarColor { +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 }; } const AvatarFallback = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps ->(({ className, color, ...props }, ref) => ( - -)); + React.ComponentPropsWithoutRef & { + seed: string; + } +>(({ className, seed, ...props }, ref) => { + const { bgColor, textColor } = getColor(seed); + return ( + + ); +}); AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; export { Avatar, AvatarImage, AvatarFallback };