Skip to content

Commit

Permalink
feat: update avatar api (#464)
Browse files Browse the repository at this point in the history
* feat: update avatar api

* refactor: add avatar status, migrate avatar api

* fix: eslint erro

* fix: test error

* fix: migrate avatar api on rebase

* fix: add outline small src

* fix: add changeset
  • Loading branch information
tonible14012002 authored Dec 21, 2023
1 parent 62b7ad9 commit 3641b29
Show file tree
Hide file tree
Showing 18 changed files with 290 additions and 150 deletions.
9 changes: 9 additions & 0 deletions .changeset/smooth-readers-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@mochi-ui/profile-badge': minor
'@mochi-ui/avatar': minor
'@mochi-ui/input': minor
'@mochi-ui/theme': minor
'@mochi-ui/core': minor
---

update avatar api
20 changes: 7 additions & 13 deletions apps/mochi-web/components/Feed/Row.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
/* eslint-disable react/jsx-key */
import { ArrowRightLine } from '@mochi-ui/icons'
import { Avatar, Badge } from '@mochi-ui/core'
import { Avatar, AvatarSmallImage, Badge } from '@mochi-ui/core'
import React from 'react'
import { Tx } from './store'
import RowCell from './RowCell'

export default function Row({ tx, colWidth }: { tx: Tx; colWidth: string[] }) {
return [
<RowCell className="flex gap-x-2 items-center" width="">
<Avatar
smallSrc={tx.platformIcon}
src={tx.fromAvatar}
fallback={tx.from}
size="sm"
/>
<Avatar src={tx.fromAvatar} fallback={tx.from} size="sm">
<AvatarSmallImage src={tx.platformIcon} />
</Avatar>
<div className="flex flex-col justify-between min-w-0">
<span className="text-sm leading-5 break-words truncate text-white-pure">
{tx.from}
Expand All @@ -26,12 +23,9 @@ export default function Row({ tx, colWidth }: { tx: Tx; colWidth: string[] }) {
</div>
</RowCell>,
<RowCell className="flex gap-x-2 items-center" width="">
<Avatar
smallSrc={tx.toPlatformIcon}
src={tx.toAvatar}
fallback={tx.to}
size="sm"
/>
<Avatar src={tx.toAvatar} fallback={tx.to} size="sm">
<AvatarSmallImage src={tx.toPlatformIcon} />
</Avatar>
<div className="flex flex-col justify-between min-w-0">
<span className="text-sm leading-5 break-words truncate text-white-pure">
{tx.to}
Expand Down
5 changes: 3 additions & 2 deletions apps/mochi-web/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,10 @@ const MobileHeader = ({ onClose }: { onClose: () => void }) => {
<div className="flex relative z-10 gap-4 items-center p-4 w-full h-full text-white">
<Avatar
fallback={profile?.profile_name}
/* smallSrc={me?.platformIcon} */
src={profile?.avatar as string}
/>
>
{/* <AvatarSmallImage src={me?.platformIcon} /> */}
</Avatar>
<div className="flex flex-1 items-center font-medium">
<span className="inline-block w-max whitespace-nowrap max-w-40 truncate">
{profile?.profile_name}
Expand Down
10 changes: 4 additions & 6 deletions apps/mochi-web/components/PayRequest/UpperBody.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Typography, Avatar } from '@mochi-ui/core'
import { Typography, Avatar, AvatarSmallImage } from '@mochi-ui/core'
import clsx from 'clsx'
import Image from 'next/image'
import { coinIcon } from '~utils/image'
Expand Down Expand Up @@ -42,11 +42,9 @@ export default function UpperBody({

return (
<div className="flex flex-col items-center">
<Avatar
size="lg"
src={avatarUrl || '/logo.png'}
smallSrc={avatarPlatform}
/>
<Avatar size="lg" src={avatarUrl || '/logo.png'}>
<AvatarSmallImage src={avatarPlatform} />
</Avatar>
{/* TODO */}
<Typography
level="p6"
Expand Down
13 changes: 11 additions & 2 deletions apps/mochi-web/components/Profile/PaymeRequestsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Avatar, Button, ColumnProps, Table, Typography } from '@mochi-ui/core'
import {
Avatar,
AvatarSmallImage,
Button,
ColumnProps,
Table,
Typography,
} from '@mochi-ui/core'
import { useFetchPayRequests } from '~hooks/profile/useFetchPayRequests'
import { useProfileStore } from '~store'
import { ModelPayRequest } from '~types/mochi-pay-schema'
Expand All @@ -20,7 +27,9 @@ const Sender: ColumnProps<ModelPayRequest>['cell'] = (props) => {

return (
<div className="flex items-center space-x-3.5">
<Avatar size="base" smallSrc={platformIcon} src={toAvatar} />
<Avatar size="base" src={toAvatar}>
<AvatarSmallImage src={platformIcon} />
</Avatar>
<div>
<Typography level="h8">{to}</Typography>
<Typography level="p6" color="textSecondary">
Expand Down
6 changes: 4 additions & 2 deletions apps/mochi-web/components/Receipt/Template.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Avatar } from '@mochi-ui/core'
import { Avatar, AvatarSmallImage } from '@mochi-ui/core'
import Image from 'next/image'
import { hpbd, appreciation, achievement, wedding } from '~utils/image'

Expand Down Expand Up @@ -49,7 +49,9 @@ export default function Template({
alt={title}
/>
<div className="absolute bottom-0 left-1/2 p-1 rounded-full -translate-x-1/2 translate-y-1/2 bg-inherit">
<Avatar size="xl" src={avatar} smallSrc={platformIcon} />
<Avatar size="xl" src={avatar}>
<AvatarSmallImage src={platformIcon} />
</Avatar>
</div>
</div>
)
Expand Down
10 changes: 4 additions & 6 deletions apps/mochi-web/components/Receipt/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Image from 'next/image'
import useSWR from 'swr'
import { API } from '~constants/api'
import { coinIcon } from '~utils/image'
import { Avatar, Badge, Typography } from '@mochi-ui/core'
import { Avatar, Typography, Badge, AvatarSmallImage } from '@mochi-ui/core'
import clsx from 'clsx'
import { truncate } from '@dwarvesf/react-utils'
import { useDisclosure } from '@dwarvesf/react-hooks'
Expand Down Expand Up @@ -68,11 +68,9 @@ export default function Receipt({ id, data: _data }: Props) {
<div className="flex flex-col gap-y-12 py-3 px-4 pb-6 md:px-6 !text-neutral-600">
<div className="flex relative flex-col items-center">
{data.data.template ? null : (
<Avatar
smallSrc={data.platformIcon}
size="xl"
src={data.senderAvatar}
/>
<Avatar size="xl" src={data.senderAvatar}>
<AvatarSmallImage src={data.platformIcon} />
</Avatar>
)}
<div className="mt-2 text-sm">
<span className="font-medium">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const TransactionUsernameCell = (props: ModelProfileTransaction) => {
return (
<div className="flex gap-[14px] items-center">
<div className="relative h-10">
<Avatar src={from_profile?.avatar ?? ''} smallSrc="" />
<Avatar src={from_profile?.avatar ?? ''} />
<div
className={clsx(
'absolute h-4 w-4',
Expand Down
22 changes: 11 additions & 11 deletions apps/mochi-web/components/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Platform, utils as mochiUtils } from '@consolelabs/mochi-ui'
import { Icon } from '@iconify/react'
import { Stats } from '@consolelabs/mochi-rest'
import { discordLogo, telegramLogo } from '~utils/image'
import { Avatar } from '@mochi-ui/core'
import { Avatar, AvatarSmallImage } from '@mochi-ui/core'
import { Pagination } from './Dashboard/Pagination'
import { NativeImage } from './NativeImage'

Expand Down Expand Up @@ -144,11 +144,11 @@ export default function Profile() {
<Box
icon={
stats?.most_send.profile.platformIcon ? (
<Avatar
src={stats.most_send.profile.avatar}
smallSrc={stats.most_send.profile.platformIcon}
size="sm"
/>
<Avatar src={stats.most_send.profile.avatar} size="sm">
<AvatarSmallImage
src={stats.most_send.profile.platformIcon}
/>
</Avatar>
) : null
}
>
Expand All @@ -171,11 +171,11 @@ export default function Profile() {
<Box
icon={
stats?.most_receive.profile.platformIcon ? (
<Avatar
src={stats?.most_receive.profile.avatar}
smallSrc={stats.most_receive.profile.platformIcon}
size="sm"
/>
<Avatar src={stats?.most_receive.profile.avatar} size="sm">
<AvatarSmallImage
src={stats.most_receive.profile.platformIcon}
/>
</Avatar>
) : null
}
>
Expand Down
20 changes: 10 additions & 10 deletions packages/components/avatar/__tests__/avatar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { cleanup, render } from '@testing-library/react'
import Avatar from '../src/avatar'
import Avatar, { AvatarSmallImage } from '../src/avatar'
import { boringAvatar } from '../src/util'

describe('Avatar', () => {
afterEach(cleanup)
Expand All @@ -8,22 +9,21 @@ describe('Avatar', () => {
<Avatar
size="sm"
src="https://ui-avatars.com/api/?name=John+Doe"
smallSrc="https://ui-avatars.com/api/?name=Adam+Smith"
/>,
fallback="fallback"
>
<AvatarSmallImage src="https://ui-avatars.com/api/?name=Adam+Smith" />
</Avatar>,
)
expect(container.querySelector('svg')).toBeInTheDocument()
const images = container.querySelectorAll('image')
expect(container.querySelector('img')).toBeInTheDocument()
const images = container.querySelectorAll('img')
expect(images.length).toBe(2)

const [image1, image2] = Array.from(images)
expect(image1).toHaveAttribute(
'xlink:href',
'https://ui-avatars.com/api/?name=John+Doe',
)
expect(image2).toHaveAttribute(
'xlink:href',
'src',
'https://ui-avatars.com/api/?name=Adam+Smith',
)
expect(image2).toHaveAttribute('src', boringAvatar('fallback'))
})

it('renders correctly with fallback name', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/components/avatar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"react-dom": "^18.2.0"
},
"devDependencies": {
"@mochi-ui/icons": "workspace:*",
"clean-package": "^2.2.0",
"eslint-config-custom": "workspace:*",
"prettier": "^3.0.3",
Expand Down
120 changes: 74 additions & 46 deletions packages/components/avatar/src/avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,70 +1,98 @@
import * as RadixAvatar from '@radix-ui/react-avatar'
import { useId } from 'react'
import { avatar, AvatarStylesProps } from '@mochi-ui/theme'
import {
HTMLAttributes,
ImgHTMLAttributes,
PropsWithChildren,
ReactNode,
} from 'react'
import {
avatar,
AvatarStylesProps,
AvatarSmallImgStyleProps,
AvatarStatusStyleProps,
} from '@mochi-ui/theme'
import { boringAvatar } from './util'

const { avatarCva, avatarImgClsx } = avatar
const { avatarCva, avatarImgClsx, avatarSmallImgCva, avatarStatusWrapperCva } =
avatar

interface AvatarProps extends AvatarStylesProps {
type AvatarProps = PropsWithChildren<AvatarStylesProps> & {
src: string
smallSrc?: string
fallback?: string
className?: string
}
onLoadingStatusChange?: RadixAvatar.AvatarImageProps['onLoadingStatusChange']
delayMs?: RadixAvatar.AvatarFallbackProps['delayMs']
} & HTMLAttributes<HTMLDivElement>

export default function Avatar({
size,
src,
smallSrc,
fallback = '',
onLoadingStatusChange,
delayMs,
className,
children,
...props
}: AvatarProps) {
const id = useId()
const fallbackUrl = boringAvatar(fallback)

if (smallSrc) {
return (
<div className={avatarCva({ size, className })}>
<svg height="100%" role="none" viewBox="0 0 100 100" width="100%">
<mask id={`circle-mask-${id}`}>
<circle cx="50%" cy="50%" fill="white" r="50%" />
<circle cx="80%" cy="80%" fill="black" r="24%" />
</mask>
<image
height="100%"
mask={`url(#circle-mask-${id})`}
onError={(e) => {
;(e.target as SVGImageElement).setAttribute(
'xlink:href',
fallbackUrl,
)
}}
width="100%"
xlinkHref={src}
className="overflow-hidden"
/>
<image
height="40%"
width="40%"
x="60%"
xlinkHref={smallSrc}
y="60%"
/>
</svg>
</div>
)
}

return (
<RadixAvatar.Root
className={avatarCva({ size, className: `${className} overflow-hidden` })}
>
<RadixAvatar.Image src={src} className={avatarImgClsx} />
<RadixAvatar.Fallback>
<RadixAvatar.Root className={avatarCva({ size, className })} {...props}>
<RadixAvatar.Image
className={avatarImgClsx}
onLoadingStatusChange={onLoadingStatusChange}
src={src}
/>
{children}
<RadixAvatar.Fallback delayMs={delayMs}>
<img alt="fallback" src={fallbackUrl} />
</RadixAvatar.Fallback>
</RadixAvatar.Root>
)
}

export type AvatarSmallImageProps = AvatarSmallImgStyleProps & {
src?: string
className?: string
} & ImgHTMLAttributes<HTMLImageElement>

export const AvatarSmallImage = (props: AvatarSmallImageProps) => {
const { src, position = 'bottom-right', className, alt, ...restProps } = props
return (
<img
className={avatarSmallImgCva({ position, className })}
src={src}
alt={alt}
{...restProps}
/>
)
}

export type AvatarStatusProps = AvatarStatusStyleProps & {
className?: string
children?: ReactNode
} & HTMLAttributes<HTMLDivElement>

export const AvatarStatus = (props: AvatarStatusProps) => {
const {
position = 'bottom-right',
color = 'success',
className,
children,
...restProps
} = props
return (
<div
className={avatarStatusWrapperCva({ color, className, position })}
{...restProps}
>
{children || (
<svg height="100%" width="100%">
<circle r="50%" cx="50%" cy="50%" fill="currentColor" />
</svg>
)}
</div>
)
}

export { type AvatarProps }
Loading

1 comment on commit 3641b29

@vercel
Copy link

@vercel vercel bot commented on 3641b29 Dec 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

websites-mochi – ./apps/mochi-web

websites-mochi-git-main-consolelabs.vercel.app
websites-mochi-consolelabs.vercel.app
beta.mochi.gg
websites-mochi.vercel.app

Please sign in to comment.