-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
style: new avatar and avatar group components (#2584)
* style: new avatar components * chore: bug fixes * chore: add pixel to size * chore: add comments to helper functions * fix: build errors
- Loading branch information
Showing
52 changed files
with
555 additions
and
1,825 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import React from "react"; | ||
// ui | ||
import { Tooltip } from "../tooltip"; | ||
// types | ||
import { TAvatarSize, getSizeInfo, isAValidNumber } from "./avatar"; | ||
|
||
type Props = { | ||
/** | ||
* The children of the avatar group. | ||
* These should ideally should be `Avatar` components | ||
*/ | ||
children: React.ReactNode; | ||
/** | ||
* The maximum number of avatars to display. | ||
* If the number of children exceeds this value, the additional avatars will be replaced by a count of the remaining avatars. | ||
* @default 2 | ||
*/ | ||
max?: number; | ||
/** | ||
* Whether to show the tooltip or not | ||
* @default true | ||
*/ | ||
showTooltip?: boolean; | ||
/** | ||
* The size of the avatars | ||
* Possible values: "sm", "md", "base", "lg" | ||
* @default "md" | ||
*/ | ||
size?: TAvatarSize; | ||
}; | ||
|
||
export const AvatarGroup: React.FC<Props> = (props) => { | ||
const { children, max = 2, showTooltip = true, size = "md" } = props; | ||
|
||
// calculate total length of avatars inside the group | ||
const totalAvatars = React.Children.toArray(children).length; | ||
|
||
// slice the children to the maximum number of avatars | ||
const avatars = React.Children.toArray(children).slice(0, max); | ||
|
||
// assign the necessary props from the AvatarGroup component to the Avatar components | ||
const avatarsWithUpdatedProps = avatars.map((avatar) => { | ||
const updatedProps: Partial<Props> = { | ||
showTooltip, | ||
size, | ||
}; | ||
|
||
return React.cloneElement(avatar as React.ReactElement, updatedProps); | ||
}); | ||
|
||
// get size details based on the size prop | ||
const sizeInfo = getSizeInfo(size); | ||
|
||
return ( | ||
<div className={`flex ${sizeInfo.spacing}`}> | ||
{avatarsWithUpdatedProps.map((avatar, index) => ( | ||
<div key={index} className="ring-1 ring-custom-border-200 rounded-full"> | ||
{avatar} | ||
</div> | ||
))} | ||
{max < totalAvatars && ( | ||
<Tooltip | ||
tooltipContent={`${totalAvatars} total`} | ||
disabled={!showTooltip} | ||
> | ||
<div | ||
className={`${ | ||
!isAValidNumber(size) ? sizeInfo.avatarSize : "" | ||
} ring-1 ring-custom-border-200 bg-custom-primary-500 text-white rounded-full grid place-items-center text-[9px]`} | ||
style={ | ||
isAValidNumber(size) | ||
? { | ||
width: `${size}px`, | ||
height: `${size}px`, | ||
} | ||
: {} | ||
} | ||
> | ||
+{totalAvatars - max} | ||
</div> | ||
</Tooltip> | ||
)} | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import React from "react"; | ||
// ui | ||
import { Tooltip } from "../tooltip"; | ||
|
||
export type TAvatarSize = "sm" | "md" | "base" | "lg" | number; | ||
|
||
type Props = { | ||
/** | ||
* The name of the avatar which will be displayed on the tooltip | ||
*/ | ||
name?: string; | ||
/** | ||
* The background color if the avatar image fails to load | ||
*/ | ||
fallbackBackgroundColor?: string; | ||
/** | ||
* The text to display if the avatar image fails to load | ||
*/ | ||
fallbackText?: string; | ||
/** | ||
* The text color if the avatar image fails to load | ||
*/ | ||
fallbackTextColor?: string; | ||
/** | ||
* Whether to show the tooltip or not | ||
* @default true | ||
*/ | ||
showTooltip?: boolean; | ||
/** | ||
* The size of the avatars | ||
* Possible values: "sm", "md", "base", "lg" | ||
* @default "md" | ||
*/ | ||
size?: TAvatarSize; | ||
/** | ||
* The shape of the avatar | ||
* Possible values: "circle", "square" | ||
* @default "circle" | ||
*/ | ||
shape?: "circle" | "square"; | ||
/** | ||
* The source of the avatar image | ||
*/ | ||
src?: string; | ||
}; | ||
|
||
/** | ||
* Get the size details based on the size prop | ||
* @param size The size of the avatar | ||
* @returns The size details | ||
*/ | ||
export const getSizeInfo = (size: TAvatarSize) => { | ||
switch (size) { | ||
case "sm": | ||
return { | ||
avatarSize: "h-4 w-4", | ||
fontSize: "text-xs", | ||
spacing: "-space-x-1", | ||
}; | ||
case "md": | ||
return { | ||
avatarSize: "h-5 w-5", | ||
fontSize: "text-xs", | ||
spacing: "-space-x-1", | ||
}; | ||
case "base": | ||
return { | ||
avatarSize: "h-6 w-6", | ||
fontSize: "text-sm", | ||
spacing: "-space-x-1.5", | ||
}; | ||
case "lg": | ||
return { | ||
avatarSize: "h-7 w-7", | ||
fontSize: "text-sm", | ||
spacing: "-space-x-1.5", | ||
}; | ||
default: | ||
return { | ||
avatarSize: "h-5 w-5", | ||
fontSize: "text-xs", | ||
spacing: "-space-x-1", | ||
}; | ||
} | ||
}; | ||
|
||
/** | ||
* Get the border radius based on the shape prop | ||
* @param shape The shape of the avatar | ||
* @returns The border radius | ||
*/ | ||
export const getBorderRadius = (shape: "circle" | "square") => { | ||
switch (shape) { | ||
case "circle": | ||
return "rounded-full"; | ||
case "square": | ||
return "rounded-md"; | ||
default: | ||
return "rounded-full"; | ||
} | ||
}; | ||
|
||
/** | ||
* Check if the value is a valid number | ||
* @param value The value to check | ||
* @returns Whether the value is a valid number or not | ||
*/ | ||
export const isAValidNumber = (value: any) => { | ||
return typeof value === "number" && !isNaN(value); | ||
}; | ||
|
||
export const Avatar: React.FC<Props> = (props) => { | ||
const { | ||
name, | ||
fallbackBackgroundColor, | ||
fallbackText, | ||
fallbackTextColor, | ||
showTooltip = true, | ||
size = "md", | ||
shape = "circle", | ||
src, | ||
} = props; | ||
|
||
// get size details based on the size prop | ||
const sizeInfo = getSizeInfo(size); | ||
|
||
return ( | ||
<Tooltip | ||
tooltipContent={fallbackText ?? name ?? "?"} | ||
disabled={!showTooltip} | ||
> | ||
<div | ||
className={`${ | ||
!isAValidNumber(size) ? sizeInfo.avatarSize : "" | ||
} overflow-hidden grid place-items-center ${getBorderRadius(shape)}`} | ||
style={ | ||
isAValidNumber(size) | ||
? { | ||
height: `${size}px`, | ||
width: `${size}px`, | ||
} | ||
: {} | ||
} | ||
> | ||
{src ? ( | ||
<img | ||
src={src} | ||
className={`h-full w-full ${getBorderRadius(shape)}`} | ||
alt={name} | ||
/> | ||
) : ( | ||
<div | ||
className={`${ | ||
sizeInfo.fontSize | ||
} grid place-items-center h-full w-full ${getBorderRadius(shape)}`} | ||
style={{ | ||
backgroundColor: | ||
fallbackBackgroundColor ?? "rgba(var(--color-primary-500))", | ||
color: fallbackTextColor ?? "#ffffff", | ||
}} | ||
> | ||
{name ? name[0].toUpperCase() : fallbackText ?? "?"} | ||
</div> | ||
)} | ||
</div> | ||
</Tooltip> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./avatar-group"; | ||
export * from "./avatar"; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
export * from "./avatar"; | ||
export * from "./breadcrumbs"; | ||
export * from "./button"; | ||
export * from "./dropdowns"; | ||
export * from "./form-fields"; | ||
export * from "./icons"; | ||
export * from "./progress"; | ||
export * from "./spinners"; | ||
export * from "./loader"; | ||
export * from "./tooltip"; | ||
export * from "./icons"; | ||
export * from "./breadcrumbs"; | ||
export * from "./dropdowns"; | ||
export * from "./loader"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
export * from "./date-filter-modal"; | ||
export * from "./date-filter-select"; | ||
export * from "./filters-list"; | ||
export * from "./workspace-filters-list"; |
Oops, something went wrong.