mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-16 17:46:18 +08:00
feat: add invite dialog
This commit is contained in:
@@ -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',
|
||||
};
|
||||
});
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user