Migrated sources to here

This commit is contained in:
2024-09-18 17:54:26 +05:30
parent 117193bd6c
commit 19b6551a16
2 changed files with 303 additions and 0 deletions

51
src/Avatar.component.scss Executable file
View File

@@ -0,0 +1,51 @@
.ar-Avatar {
transition: border-color 0.3s;
&.xsmall {
font-size: .75em;
}
&:hover {
border-color: #1677ff !important;
}
&.FAILED {
color: #ff4d4f;
border-color: #ff4d4f !important;
}
.ar-Avatar__actions {
transition: background-color 0.3s ease-in, opacity 0.3s;
opacity: 0;
&.show {
opacity: 1;
background-color: var(--ar-bg-avatar-hover);
}
}
&.rect {
border-radius: 10px;
}
&.xsmall {
width: 3rem;
height: 3rem;
}
&.small {
width: 5rem;
height: 5rem;
}
&.regular {
width: 7rem;
height: 7rem;
}
&.large {
width: 10rem;
height: 10rem;
font-size: 1.3rem;
line-height: 1.5rem;
}
&.xlarge {
width: 15rem;
height: 15rem;
font-size: 1.7rem;
line-height: 1.9rem;
}
}

252
src/Avatar.tsx Executable file
View File

@@ -0,0 +1,252 @@
import { memo, useEffect, useState } from "react"
import {
AvatarProps,
ArProgress,
ArSizes,
ImageProps,
UploadResult,
} from "@armco/types"
import { Icon } from "@armco/icon"
import { ImageEditor } from "@armco/imageeditor"
import { Image, ProgressIndicator, Text } from "@armco/shared-components"
import "./Avatar.component.scss"
const AVATAR_SIZES = {
xsmall: "1.5rem",
small: "2.5rem",
regular: "3rem",
large: "4.5rem",
xlarge: "7rem",
}
const ACTION_ICON_SIZES = {
xsmall: "0.75rem",
small: "1.25rem",
regular: "1.6rem",
large: "2.3rem",
xlarge: "3.2rem",
}
const Avatar = memo(
(props: AvatarProps) => {
const {
classes,
clearImage,
demo,
item,
onChange,
onCommit,
size = ArSizes.REGULAR,
uploadButtonText = "Upload",
uploadingButtonText = "Uploading...",
variant = "circle",
viewOnly,
} = props
const [hovered, setHovered] = useState<boolean>()
const [displayed, show] = useState<boolean>()
const [localItem, setLocalItem] = useState<UploadResult>()
useEffect(() => {
setTimeout(() => show(hovered), 10)
}, [hovered])
useEffect(() => {
setLocalItem(item)
}, [item])
const hasFailed = localItem?.status === ArProgress.FAILED
const hasCompleted =
localItem?.status === ArProgress.COMPLETED ||
localItem?.status === ArProgress.FAILED
const hasPassed = localItem?.status === ArProgress.COMPLETED
const isInProgress = localItem?.status === ArProgress.IN_PROGRESS
const color = hasFailed ? "#ff4d4f" : hovered ? "#1677ff" : "#000000aa"
const isSmall = size === ArSizes.SMALL || size === ArSizes.XSMALL
return (
<span
className={`ar-Avatar bg cursor-pointer${size ? " " + size : ""}${
localItem ? " " + localItem.status : ""
}${variant === "circle" ? " border-radius-50" : ""} ${
isSmall ? "p-1" : "p-2"
} ${hasCompleted ? "border" : "dashed-border"} ${variant}${
classes ? " " + classes : ""
}`}
style={{ color }}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
<div className="position-relative flex-center flex-column w-100 h-100">
<Icon
attributes={{
classes:
!isSmall && !localItem
? size === ArSizes.XLARGE
? "mb-2"
: "mb-1"
: "",
size: localItem ? "0rem" : AVATAR_SIZES[size],
colors: { fillColor: color },
}}
icon="io5.IoPersonAddOutline"
/>
{
<span
className={`ar-Avatar__prompt flex-center flex-column w-100${
hasPassed ? " h-100 border overflow-hidden" : ""
}${
variant === "circle"
? " border-radius-50"
: " border-radius-6px"
}`}
>
{isInProgress && (
<>
<span
className={`${
size === ArSizes.XLARGE
? "mb-2"
: size === ArSizes.LARGE
? "mb-1"
: ""
} mw-100 overflow-hidden`}
>
{uploadingButtonText}
</span>
<ProgressIndicator
progress={localItem?.progress}
demo={demo}
minimal
/>
</>
)}
{hasFailed && (
<>
<Icon
attributes={{
colors: { fillColor: #ff4d4f },
classes: isSmall ? "" : "mb-2",
size: AVATAR_SIZES[size],
}}
icon="fa.FaRegImage"
/>
{!isSmall && (
<Text
classes="mxw-65pct hover-underline text-center"
demo={demo}
descriptor={{
id: "temp-text-id",
order: 0,
name: "Text",
text: localItem?.file.name,
chunks: {},
}}
overflowEllipsis
overflowTooltip
/>
)}
</>
)}
{hasPassed && (
<Image
classes="text-center mw-100"
image={localItem.url || ""}
fill
{...item?.imageProps}
/>
)}
{!localItem && !isSmall && uploadButtonText}
</span>
}
{hovered && localItem && (
<div
className={`ar-Avatar__actions w-100 h-100 position-absolute flex-center${
displayed ? " show" : ""
}${variant === "circle" ? " border-radius-50" : ""}`}
>
{hasPassed && (
<Icon
icon="io5.IoEyeSharp"
attributes={{
colors: { fillColor: "white" },
size: ACTION_ICON_SIZES[size],
}}
events={{
onClick: (e) => {
e.stopPropagation()
localItem.url &&
dispatch(
setModalState({
modalClasses: "full-dimensions",
content: (
<ImageEditor
image={localItem.url}
onChange={(imageProps: Partial<ImageProps>) => {
if (item) {
const itemClone = { ...item }
itemClone.imageProps = imageProps
setLocalItem(itemClone)
onChange && onChange(imageProps)
}
}}
onCommit={onCommit}
viewOnly={viewOnly}
/>
),
show: true,
hideClose: true,
shouldScale: true,
shouldFadeIn: true,
closeHandler: () => {
dispatch(
setModalState({
content: null,
show: false,
}),
)
},
}),
)
},
}}
/>
)}
{!viewOnly && (
<LoadableIcon
classes={
hasPassed
? isSmall
? size === ArSizes.XSMALL
? ""
: "ms-1"
: "ms-2"
: ""
}
icon="ri.RiDeleteBin6Fill"
color="white"
size={ACTION_ICON_SIZES[size]}
onClick={(e) => {
e.stopPropagation()
setLocalItem(undefined)
clearImage && clearImage()
}}
/>
)}
</div>
)}
</div>
</span>
)
},
(prevProps, props) => {
return (
prevProps.variant === props.variant &&
prevProps.classes === props.classes &&
prevProps.viewOnly === props.viewOnly &&
JSON.stringify(prevProps.item) === JSON.stringify(props.item) &&
prevProps.size === props.size
)
},
)
export default Avatar