From 5c9fe9b20a1498e89125c2de9641bc1fd821f7cd Mon Sep 17 00:00:00 2001 From: "chanki.kim" Date: Wed, 5 Feb 2025 15:44:12 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=E2=9C=A8=20feat=20:=20=EC=95=9E=EA=B8=80?= =?UTF-8?q?=EC=9E=90=20=EC=9C=A0=EB=8B=88=EC=BD=94=EB=93=9C=EB=A1=9C=20?= =?UTF-8?q?=EC=83=89=EC=83=81=20=EC=84=A0=ED=83=9D=20=ED=97=AC=ED=8D=BC=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/colors.ts | 1 + src/utils/helper.ts | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 src/constants/colors.ts diff --git a/src/constants/colors.ts b/src/constants/colors.ts new file mode 100644 index 0000000..c578e26 --- /dev/null +++ b/src/constants/colors.ts @@ -0,0 +1 @@ +export const DEFAULT_COLORS = ['#7AC555', '#760DDE', '#FFA500', '#76A5EA', '#E876EA']; diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 2819a83..b4de34b 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -4,3 +4,9 @@ import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } + +export function getColorByString(value: string, colorArray: string[]) { + const charCode = value.toLowerCase().charCodeAt(0); + const index = charCode % colorArray.length; + return colorArray[index]; +} From 4c821d578a2df459ebf78fb9aec34665c094e05d Mon Sep 17 00:00:00 2001 From: "chanki.kim" Date: Wed, 5 Feb 2025 16:55:32 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=92=84=20feat=20:=20avatar=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/Avatar/Avatar.tsx | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/components/ui/Avatar/Avatar.tsx diff --git a/src/components/ui/Avatar/Avatar.tsx b/src/components/ui/Avatar/Avatar.tsx new file mode 100644 index 0000000..b7eea99 --- /dev/null +++ b/src/components/ui/Avatar/Avatar.tsx @@ -0,0 +1,70 @@ +'use client'; + +import { DEFAULT_COLORS } from '@/constants/colors'; +import { cn, getColorByString } from '@/utils/helper'; +import { cva, VariantProps } from 'class-variance-authority'; +import Image from 'next/image'; +import { HTMLAttributes, useState } from 'react'; + +/** + * 커스터마이징 가능한 기본 공용 Avatar 컴포넌트입니다. + * + * ### Variants: + * - `size`: + * - `default`: width:38px, font-size:16px; + * - `md`: width:34px, font-size:16px; + * - `sm`: width:24px, font-size:12px; + * + * ### Default Variants (기본 스타일): + * - `size`: `default` + * + * + * @example + * + * + * 반응형으로 쓰고 싶을땐, classname을 추가하세요 + * + */ + +const avatarVariants = cva( + //prettier-ignore + 'relative inline-flex items-center justify-center aspect-square rounded-full overflow-hidden border-2 border-white leading-none', + { + variants: { + size: { + default: 'w-[38px] text-lg', + md: 'w-[34px] text-lg', + sm: 'w-6 text-xs', + }, + }, + + defaultVariants: { + size: 'default', + }, + }, +); + +interface AvatarProps extends HTMLAttributes, VariantProps { + email: string; + profileImageUrl?: string; +} + +export default function Avatar({ email, profileImageUrl, size, className, ...props }: AvatarProps) { + const [imgError, setImgError] = useState(false); + const colorCode = getColorByString(email, DEFAULT_COLORS); + const firstChar = email.charAt(0); + + const isFallback = !profileImageUrl || imgError; + + return ( +
+ {!isFallback ? ( + {email} setImgError(true)} /> + ) : ( + + {firstChar} + + )} +
+ ); +} From 93859d67f52b0e8e3f7b6db4ac7f8bf562d3a122 Mon Sep 17 00:00:00 2001 From: "chanki.kim" Date: Wed, 5 Feb 2025 16:55:47 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=92=84=20feat=20:=20stack=20avatar=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/Avatar/StackAvatars.tsx | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/components/ui/Avatar/StackAvatars.tsx diff --git a/src/components/ui/Avatar/StackAvatars.tsx b/src/components/ui/Avatar/StackAvatars.tsx new file mode 100644 index 0000000..df31494 --- /dev/null +++ b/src/components/ui/Avatar/StackAvatars.tsx @@ -0,0 +1,26 @@ +import Avatar from './Avatar'; + +interface StackAvatarsProps { + members: { email: string; profileImageUrl?: string }[]; + visibleCount: number; +} + +export default function StackAvatars({ members, visibleCount = 3 }: StackAvatarsProps) { + const chunkedMembers = members.slice(0, visibleCount); + const restMembersCount = members.length - visibleCount; + + return ( +
    + {chunkedMembers.map((member) => ( +
  • + +
  • + ))} + {restMembersCount > 0 && ( +
  • + +{restMembersCount} +
  • + )} +
+ ); +} From 1200ef6dd04004bc3233fbb6ab590ac3f5c023d8 Mon Sep 17 00:00:00 2001 From: "chanki.kim" Date: Wed, 5 Feb 2025 16:56:14 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=94=A7=20chore=20:=20image=20remote?= =?UTF-8?q?=20pattern=20=EC=9E=84=EC=8B=9C=EC=B6=94=EA=B0=80=20-=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=9A=A9=20=EC=96=B8=EC=8A=A4?= =?UTF-8?q?=ED=94=8C=EB=9E=98=EC=8B=9C=20=EC=A3=BC=EC=86=8C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/next.config.ts b/next.config.ts index 810a8dd..9d5b0f1 100644 --- a/next.config.ts +++ b/next.config.ts @@ -8,6 +8,14 @@ const nextConfig: NextConfig = { fullUrl: true, }, }, + images: { + remotePatterns: [ + { + protocol: 'https', + hostname: 'images.unsplash.com', + }, + ], + }, }; export default nextConfig; From b9678e59dc61bc9ef44710979f0c748ea52be311 Mon Sep 17 00:00:00 2001 From: "chanki.kim" Date: Wed, 5 Feb 2025 17:08:49 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor=20:=20HexColo?= =?UTF-8?q?r=20=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/colors.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/constants/colors.ts b/src/constants/colors.ts index c578e26..7abcc32 100644 --- a/src/constants/colors.ts +++ b/src/constants/colors.ts @@ -1 +1,3 @@ -export const DEFAULT_COLORS = ['#7AC555', '#760DDE', '#FFA500', '#76A5EA', '#E876EA']; +type HexColor = `#${string}`; + +export const DEFAULT_COLORS: HexColor[] = ['#7AC555', '#760DDE', '#FFA500', '#76A5EA', '#E876EA'];