diff --git a/packages/app/src/components/invite-members/index.tsx b/packages/app/src/components/invite-members/index.tsx new file mode 100644 index 0000000000..3376c9b0ea --- /dev/null +++ b/packages/app/src/components/invite-members/index.tsx @@ -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 = 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(true); + const [showMember, setShowMember] = useState(true); + const [showTip, setShowTip] = useState(true); + + const InputChange = (value: string) => { + setShowMember(true); + if (gmailReg.test(value)) { + setShowTip(false); + } + }; + return ( +
+ + +
+ { + onClose(); + }} + /> +
+ + Invite members + + { + setShowMember(false); + }} + placeholder="Search mail (Gmail support only)" + > + {showMember ? ( + + {showTip ? ( + Non-Gmail is not supported + ) : ( + + + + + huojoe@gmail.com +
invited
+
+ )} +
+ ) : ( + <> + )} +
+
+
+ +
+
+
+
+ ); +}; + +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', + }; +}); diff --git a/packages/app/src/ui/input/input.tsx b/packages/app/src/ui/input/input.tsx index 5cda33d51e..920599881d 100644 --- a/packages/app/src/ui/input/input.tsx +++ b/packages/app/src/ui/input/input.tsx @@ -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(valueProp || ''); const handleChange: InputHTMLAttributes['onChange'] = e => { setValue(e.target.value); onChange && onChange(e.target.value); }; + const handleBlur: InputHTMLAttributes['onBlur'] = e => { + onBlur && onBlur(e); + }; return ( { width={width} maxLength={maxLength} onChange={handleChange} + onBlur={handleBlur} > ); };