feat: add invite dialog

This commit is contained in:
DiamondThree
2022-12-19 23:15:29 +08:00
parent a76ab1e729
commit 5ef754823d
2 changed files with 206 additions and 0 deletions
@@ -0,0 +1,200 @@
import { EmailIcon } from '@blocksuite/icons';
import { styled } from '@/styles';
import { Modal, ModalWrapper, ModalCloseButton } from '@/ui/modal';
import { Button } from '@/ui/button';
import Input from '@/ui/input';
import { useState } from 'react';
interface LoginModalProps {
open: boolean;
onClose: () => void;
}
export const debounce = <T extends (...args: any) => any>(
fn: T,
time?: number,
immediate?: boolean
): ((...args: any) => any) => {
let timeoutId: null | number;
let defaultImmediate = immediate || false;
let delay = time || 300;
return (...args: any) => {
if (defaultImmediate) {
fn.apply(this, args); // 确保引用函数的指向正确,并且函数的参数也不变
defaultImmediate = false;
return;
}
if (timeoutId) {
clearTimeout(timeoutId);
}
// @ts-ignore
timeoutId = setTimeout(() => {
fn.apply(this, args);
timeoutId = null;
}, delay);
};
};
const gmailReg = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@gmail\.com$/;
export const InviteMembers = ({ open, onClose }: LoginModalProps) => {
const [canInvite, setCanInvite] = useState<boolean>(true);
const [showMember, setShowMember] = useState<boolean>(true);
const [showTip, setShowTip] = useState<boolean>(true);
const InputChange = (value: string) => {
setShowMember(true);
if (gmailReg.test(value)) {
setShowTip(false);
}
};
return (
<div>
<Modal open={open} onClose={onClose}>
<ModalWrapper width={460} height={236}>
<Header>
<ModalCloseButton
top={6}
right={6}
onClick={() => {
onClose();
}}
/>
</Header>
<Content>
<ContentTitle>Invite members</ContentTitle>
<InviteBox>
<Input
width={360}
onChange={InputChange}
onBlur={() => {
setShowMember(false);
}}
placeholder="Search mail (Gmail support only)"
></Input>
{showMember ? (
<Members>
{showTip ? (
<NoFind>Non-Gmail is not supported</NoFind>
) : (
<Member>
<MemberIcon>
<EmailIcon></EmailIcon>
</MemberIcon>
<Email>huojoe@gmail.com</Email>
<div>invited</div>
</Member>
)}
</Members>
) : (
<></>
)}
</InviteBox>
</Content>
<Footer>
<Button shape="circle" type="primary" disabled={canInvite}>
Invite
</Button>
</Footer>
</ModalWrapper>
</Modal>
</div>
);
};
const Header = styled('div')({
position: 'relative',
height: '44px',
});
const Content = styled('div')({
display: 'flex',
padding: '0 48px',
flexDirection: 'column',
alignItems: 'center',
gap: '16px',
});
const ContentTitle = styled('h1')({
fontSize: '20px',
lineHeight: '28px',
fontWeight: 600,
textAlign: 'center',
paddingBottom: '16px',
});
const Footer = styled('div')({
height: '70px',
paddingLeft: '24px',
marginTop: '32px',
textAlign: 'center',
});
const InviteBox = styled('div')({
position: 'relative',
});
const Members = styled('div')(({ theme }) => {
return {
position: 'absolute',
width: '100%',
background: theme.colors.pageBackground,
textAlign: 'left',
zIndex: 1,
borderRadius: '0px 10px 10px 10px',
height: '56px',
padding: '8px 12px',
input: {
'&::placeholder': {
color: theme.colors.placeHolderColor,
},
},
};
});
const NoFind = styled('div')(({ theme }) => {
return {
color: theme.colors.iconColor,
fontSize: theme.font.sm,
lineHeight: '40px',
userSelect: 'none',
width: '100%',
};
});
const Member = styled('div')(({ theme }) => {
return {
color: theme.colors.iconColor,
fontSize: theme.font.sm,
lineHeight: '40px',
userSelect: 'none',
display: 'flex',
};
});
const MemberIcon = styled('div')(({ theme }) => {
return {
width: '40px',
height: '40px',
borderRadius: '50%',
color: theme.colors.primaryColor,
background: '#F5F5F5',
marginRight: '8px',
textAlign: 'center',
lineHeight: '45px',
// icon size
fontSize: '20px',
overflow: 'hidden',
img: {
width: '100%',
height: '100%',
},
};
});
const Email = styled('div')(({ theme }) => {
return {
flex: '1',
color: theme.colors.popoverColor,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
};
});
+6
View File
@@ -8,6 +8,7 @@ type inputProps = {
width?: number;
maxLength?: number;
onChange?: (value: string) => void;
onBlur?: (e: any) => void;
};
export const Input = (props: inputProps) => {
@@ -18,12 +19,16 @@ export const Input = (props: inputProps) => {
maxLength,
width = 260,
onChange,
onBlur,
} = props;
const [value, setValue] = useState<string>(valueProp || '');
const handleChange: InputHTMLAttributes<HTMLInputElement>['onChange'] = e => {
setValue(e.target.value);
onChange && onChange(e.target.value);
};
const handleBlur: InputHTMLAttributes<HTMLInputElement>['onBlur'] = e => {
onBlur && onBlur(e);
};
return (
<StyledInput
value={value}
@@ -32,6 +37,7 @@ export const Input = (props: inputProps) => {
width={width}
maxLength={maxLength}
onChange={handleChange}
onBlur={handleBlur}
></StyledInput>
);
};