feat: button add loading

This commit is contained in:
MingLiang Wang
2022-12-27 18:21:32 +08:00
parent a86d29ef16
commit 54a6f8658f
7 changed files with 110 additions and 27 deletions
@@ -3,7 +3,7 @@ import { FC, useRef, ChangeEvent, ReactElement } from 'react';
import { styled } from '@/styles';
interface Props {
uploadType?: string;
view?: ReactElement;
children?: ReactElement;
accept?: string;
fileChange: (file: File) => void;
}
@@ -28,7 +28,7 @@ export const Upload: FC<Props> = props => {
};
return (
<UploadStyle onClick={_chooseFile}>
{props.view ?? <Button>Upload</Button>}
{props.children ?? <Button>Upload</Button>}
<input
ref={input_ref}
type="file"
@@ -39,6 +39,7 @@ export const GeneralPage = ({
} = useAppState();
const [showDelete, setShowDelete] = useState<boolean>(false);
const [showLeave, setShowLeave] = useState<boolean>(false);
const [uploading, setUploading] = useState<boolean>(false);
const [workspaceName, setWorkspaceName] = useState<string>(
workspaces[workspace.id]?.meta.name ||
(workspace.type === WorkspaceType.Private && user ? user.name : '')
@@ -75,11 +76,17 @@ export const GeneralPage = ({
};
const fileChange = async (file: File) => {
setUploading(true);
const blob = new Blob([file], { type: file.type });
const blobId = await uploadBlob({ blob });
currentWorkspace?.meta.setAvatar(blobId);
workspaces[workspace.id]?.meta.setAvatar(blobId);
debouncedRefreshWorkspacesMeta();
const blobId = await uploadBlob({ blob }).finally(() => {
setUploading(false);
});
if (blobId) {
currentWorkspace?.meta.setAvatar(blobId);
workspaces[workspace.id]?.meta.setAvatar(blobId);
setUploading(false);
debouncedRefreshWorkspacesMeta();
}
};
return workspace ? (
@@ -99,7 +106,9 @@ export const GeneralPage = ({
<Upload
accept="image/gif,image/jpeg,image/jpg,image/png,image/svg"
fileChange={fileChange}
></Upload>
>
<Button loading={uploading}>Upload</Button>
</Upload>
{/* TODO: add upload logic */}
{/* {isOwner ? (
<StyledAvatarUploadBtn shape="round">upload</StyledAvatarUploadBtn>
@@ -29,7 +29,7 @@ const DefaultHeadImgColors = [
export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => {
const [workspaceName, setWorkspaceId] = useState<string>('');
const [canCreate, setCanCreate] = useState<boolean>(false);
const [creating, setCreating] = useState<boolean>(false);
const { refreshWorkspacesMeta } = useAppState();
const handlerInputChange = (workspaceName: string) => {
setWorkspaceId(workspaceName);
@@ -64,22 +64,26 @@ export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => {
});
};
const handleCreateWorkspace = async () => {
setCanCreate(true);
const blobId = await createDefaultHeadImg(workspaceName);
createWorkspace({ name: workspaceName, avatar: blobId })
.then(async data => {
await refreshWorkspacesMeta();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
router.push(`/workspace/${data.id}`);
onClose();
})
.catch(err => {
console.log(err, 'err');
})
.finally(() => {
setCanCreate(false);
});
setCreating(true);
const blobId = await createDefaultHeadImg(workspaceName).catch(() => {
setCreating(false);
});
if (blobId) {
createWorkspace({ name: workspaceName, avatar: blobId })
.then(async data => {
await refreshWorkspacesMeta();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
router.push(`/workspace/${data.id}`);
onClose();
})
.catch(err => {
console.log(err, 'err');
})
.finally(() => {
setCreating(false);
});
}
};
return (
<Modal open={open} onClose={onClose}>
@@ -99,8 +103,9 @@ export const WorkspaceCreate = ({ open, onClose }: WorkspaceCreateProps) => {
</StyledInputContent>
<StyledButtonContent>
<StyledButton
disabled={!workspaceName.length || canCreate}
disabled={!workspaceName.length || creating}
onClick={handleCreateWorkspace}
loading={creating}
>
Create
</StyledButton>
+2
View File
@@ -57,6 +57,8 @@ const Affine = () => {
<Button icon={<FavouritedIcon />}></Button>
<Button icon={<FavouritedIcon />} shape="round"></Button>
<Button loading={true}></Button>
<Button loading={true} type="primary"></Button>
</>
);
};
+8 -2
View File
@@ -3,6 +3,7 @@ import { StyledButton } from './styles';
import { ButtonProps } from './interface';
import { getSize } from './utils';
import { Loading } from './loading';
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(
@@ -17,6 +18,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
type = 'default',
children,
bold = false,
loading = false,
...props
},
ref
@@ -38,12 +40,16 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
bold={bold}
{...props}
>
{icon &&
{loading ? (
<Loading type={type}></Loading>
) : (
icon &&
cloneElement(Children.only(icon), {
width: iconSize,
height: iconSize,
className: `affine-button-icon ${icon.props.className ?? ''}`,
})}
})
)}
{children && <span>{children}</span>}
</StyledButton>
);
+1
View File
@@ -20,4 +20,5 @@ export type ButtonProps = PropsWithChildren &
shape?: 'default' | 'round' | 'circle';
type?: 'primary' | 'warning' | 'danger' | 'default';
bold?: boolean;
loading?: boolean;
};
+60
View File
@@ -0,0 +1,60 @@
import { styled } from '@/styles';
import { ButtonProps } from './interface';
import { getButtonColors } from './utils';
export const LoadingContainer = styled('div')<Pick<ButtonProps, 'type'>>(
({ theme, type = 'default' }) => {
const { color } = getButtonColors(theme, type);
return `
margin: 0px auto;
width: 38px;
text-align: center;
.load {
width: 8px;
height: 8px;
background-color: ${color};
border-radius: 100%;
display: inline-block;
-webkit-animation: bouncedelay 1.4s infinite ease-in-out;
animation: bouncedelay 1.4s infinite ease-in-out;
/* Prevent first frame from flickering when animation starts */
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.load1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
.load2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
@-webkit-keyframes bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
}
@keyframes bouncedelay {
0%, 80%, 100% {
transform: scale(0);
-webkit-transform: scale(0);
} 40% {
transform: scale(1.0);
-webkit-transform: scale(1.0);
}
}
`;
}
);
export const Loading = ({ type }: Pick<ButtonProps, 'type'>) => {
return (
<LoadingContainer type={type} className="load-container">
<div className="load load1"></div>
<div className="load load2"></div>
<div className="load"></div>
</LoadingContainer>
);
};