Skip to content

Commit 6b60da1

Browse files
committed
Use loading spinner for loading status
1 parent fbbfb30 commit 6b60da1

File tree

6 files changed

+35
-59
lines changed

6 files changed

+35
-59
lines changed

packages/ui/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
"@solana/wallet-adapter-react": "catalog:module-manager",
8080
"@solana/wallet-standard": "catalog:module-manager",
8181
"@swc/helpers": "catalog:repo",
82-
"blurhash": "^2.0.5",
8382
"copy-to-clipboard": "3.3.3",
8483
"core-js": "catalog:repo",
8584
"csstype": "3.1.3",

packages/ui/src/components/OrganizationProfile/OrganizationProfileAvatarUploader.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import { localizationKeys } from '../../localization';
1010
export const OrganizationProfileAvatarUploader = (
1111
props: Omit<AvatarUploaderProps, 'avatarPreview' | 'title'> & {
1212
organization: Partial<OrganizationResource>;
13-
/** A data URL to show as a placeholder while the image is loading (e.g., decoded blurhash) */
14-
blurHashPlaceholder?: string;
13+
/** Shows a loading spinner while the image is loading */
14+
showLoadingSpinner?: boolean;
1515
},
1616
) => {
17-
const { organization, blurHashPlaceholder, ...rest } = props;
17+
const { organization, showLoadingSpinner, ...rest } = props;
1818

1919
return (
2020
<Col elementDescriptor={descriptors.organizationAvatarUploaderContainer}>
@@ -32,7 +32,7 @@ export const OrganizationProfileAvatarUploader = (
3232
avatarPreview={
3333
<OrganizationAvatar
3434
size={theme => theme.sizes.$16}
35-
blurHashPlaceholder={blurHashPlaceholder}
35+
showLoadingSpinner={showLoadingSpinner}
3636
{...organization}
3737
/>
3838
}

packages/ui/src/components/SessionTasks/tasks/TaskChooseOrganization/CreateOrganizationScreen.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useOrganizationList } from '@clerk/shared/react';
22
import type { CreateOrganizationParams, OrganizationCreationDefaultsResource } from '@clerk/shared/types';
3-
import { useMemo, useState } from 'react';
3+
import { useState } from 'react';
44

55
import { useEnvironment } from '@/ui/contexts';
66
import { useSessionTasksContext, useTaskChooseOrganizationContext } from '@/ui/contexts/components/SessionTasks';
@@ -12,7 +12,6 @@ import { FormContainer } from '@/ui/elements/FormContainer';
1212
import { Header } from '@/ui/elements/Header';
1313
import { IconButton } from '@/ui/elements/IconButton';
1414
import { Upload } from '@/ui/icons';
15-
import { decodeBlurHash } from '@/ui/utils/blurhash';
1615
import { createSlug } from '@/ui/utils/createSlug';
1716
import { handleError } from '@/ui/utils/errorHandler';
1817
import { useFormControl } from '@/ui/utils/useFormControl';
@@ -101,10 +100,6 @@ export const CreateOrganizationScreen = (props: CreateOrganizationScreenProps) =
101100

102101
const isSubmitButtonDisabled = !nameField.value || !isLoaded;
103102
const defaultLogoUrl = file === undefined ? props.organizationCreationDefaults?.form.logo : undefined;
104-
const blurHashPlaceholder = useMemo(
105-
() => decodeBlurHash(props.organizationCreationDefaults?.form.blurHash),
106-
[props.organizationCreationDefaults?.form.blurHash],
107-
);
108103

109104
return (
110105
<>
@@ -123,7 +118,7 @@ export const CreateOrganizationScreen = (props: CreateOrganizationScreenProps) =
123118
organization={{ name: nameField.value, imageUrl: defaultLogoUrl ?? undefined }}
124119
onAvatarChange={async file => await setFile(file)}
125120
onAvatarRemove={file || defaultLogoUrl ? onAvatarRemove : null}
126-
blurHashPlaceholder={defaultLogoUrl ? blurHashPlaceholder : undefined}
121+
showLoadingSpinner={!!defaultLogoUrl}
127122
avatarPreviewPlaceholder={
128123
<IconButton
129124
variant='ghost'

packages/ui/src/elements/Avatar.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22

3-
import { Box, descriptors, Flex, Image, Text } from '../customizables';
3+
import { Box, descriptors, Flex, Image, Spinner, Text } from '../customizables';
44
import type { ElementDescriptor } from '../customizables/elementDescriptors';
55
import type { InternalTheme } from '../foundations';
66
import type { PropsOfComponent } from '../styledSystem';
@@ -15,8 +15,8 @@ type AvatarProps = PropsOfComponent<typeof Flex> & {
1515
rounded?: boolean;
1616
boxElementDescriptor?: ElementDescriptor;
1717
imageElementDescriptor?: ElementDescriptor;
18-
/** A data URL to show as a placeholder while the image is loading (e.g., decoded blurhash) */
19-
blurHashPlaceholder?: string;
18+
/** Shows a loading spinner while the image is loading */
19+
showLoadingSpinner?: boolean;
2020
};
2121

2222
export const Avatar = (props: AvatarProps) => {
@@ -30,7 +30,7 @@ export const Avatar = (props: AvatarProps) => {
3030
sx,
3131
boxElementDescriptor,
3232
imageElementDescriptor,
33-
blurHashPlaceholder,
33+
showLoadingSpinner = false,
3434
} = props;
3535
const [error, setError] = React.useState(false);
3636
const [loaded, setLoaded] = React.useState(false);
@@ -41,6 +41,8 @@ export const Avatar = (props: AvatarProps) => {
4141
setError(false);
4242
}, [imageUrl]);
4343

44+
const isLoading = showLoadingSpinner && imageUrl && !loaded && !error;
45+
4446
const ImgOrFallback =
4547
initials && (!imageUrl || error) ? (
4648
<InitialsAvatarFallback initials={initials} />
@@ -54,7 +56,7 @@ export const Avatar = (props: AvatarProps) => {
5456
objectFit: 'cover',
5557
width: '100%',
5658
height: '100%',
57-
opacity: loaded ? 1 : 0,
59+
opacity: showLoadingSpinner ? (loaded ? 1 : 0) : 1,
5860
transition: 'opacity 0.2s ease-in-out',
5961
}}
6062
onError={() => setError(true)}
@@ -78,19 +80,30 @@ export const Avatar = (props: AvatarProps) => {
7880
backgroundColor: t.colors.$avatarBackground,
7981
backgroundClip: 'padding-box',
8082
position: 'relative',
81-
...(blurHashPlaceholder && !loaded && imageUrl
82-
? {
83-
backgroundImage: `url(${blurHashPlaceholder})`,
84-
backgroundSize: 'cover',
85-
backgroundPosition: 'center',
86-
}
87-
: {}),
8883
}),
8984
sx,
9085
]}
9186
>
9287
{ImgOrFallback}
9388

89+
{isLoading && (
90+
<Flex
91+
as='span'
92+
sx={t => ({
93+
position: 'absolute',
94+
inset: 0,
95+
alignItems: 'center',
96+
justifyContent: 'center',
97+
backgroundColor: t.colors.$avatarBackground,
98+
})}
99+
>
100+
<Spinner
101+
size='sm'
102+
colorScheme='neutral'
103+
/>
104+
</Flex>
105+
)}
106+
94107
{/* /**
95108
* This Box is the "shimmer" effect for the avatar.
96109
* The ":after" selector is responsible for the border shimmer animation.

packages/ui/src/elements/OrganizationAvatar.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ import { Avatar } from './Avatar';
55

66
type OrganizationAvatarProps = PropsOfComponent<typeof Avatar> &
77
Partial<Pick<OrganizationResource, 'name' | 'imageUrl'>> & {
8-
/** A data URL to show as a placeholder while the image is loading (e.g., decoded blurhash) */
9-
blurHashPlaceholder?: string;
8+
/** Shows a loading spinner while the image is loading */
9+
showLoadingSpinner?: boolean;
1010
};
1111

1212
export const OrganizationAvatar = (props: OrganizationAvatarProps) => {
13-
const { name = '', imageUrl, blurHashPlaceholder, ...rest } = props;
13+
const { name = '', imageUrl, showLoadingSpinner, ...rest } = props;
1414
return (
1515
<Avatar
1616
title={name}
1717
initials={(name || ' ')[0]}
1818
imageUrl={imageUrl}
19-
blurHashPlaceholder={blurHashPlaceholder}
19+
showLoadingSpinner={showLoadingSpinner}
2020
rounded={false}
2121
{...rest}
2222
/>

packages/ui/src/utils/blurhash.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)