Migrated sources to here
This commit is contained in:
51
src/Avatar.component.scss
Executable file
51
src/Avatar.component.scss
Executable 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
252
src/Avatar.tsx
Executable 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
|
||||
Reference in New Issue
Block a user