Skip to content

Commit

Permalink
Merge pull request #723 from deepfence/feat/modal-slide-left
Browse files Browse the repository at this point in the history
added to slide modal from left
  • Loading branch information
milan-deepfence authored Dec 5, 2022
2 parents 83b4969 + 349c8a2 commit b2705fd
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ const Template: ComponentStory<typeof Avatar> = (args) => <Avatar {...args} />;

export const AvatarAsLetter = Template.bind({});
AvatarAsLetter.args = {
asChild: true,
children: 'M',
children: 'MR',
};

export const AvatarAsDefault = Template.bind({});
AvatarAsDefault.args = {
asChild: true,
};
AvatarAsDefault.args = {};

export const AvatarByImgSrc = Template.bind({});
AvatarByImgSrc.args = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,59 +1,50 @@
import cx from 'classnames';
import { forwardRef } from 'react';
import { IconContext } from 'react-icons';
import { HiOutlineUser } from 'react-icons/hi';
import { twMerge } from 'tailwind-merge';

import { Typography } from '@/components/typography/Typography';

type AvatarType = {
asChild?: boolean;
alt?: string;
src?: string;
className?: string;
children?: React.ReactNode;
onClick?: () => void;
};

const Child = ({ children }: { children: AvatarType['children'] }) => {
return (
<>
{children ? (
children
) : (
<IconContext.Provider
value={{
className: cx(`w-6 h-6`, {}),
}}
>
<HiOutlineUser />
</IconContext.Provider>
)}
</>
);
};

export const Avatar = (props: AvatarType) => {
const {
asChild = false,
children = undefined,
src = '',
alt = '',
className = '',
onClick,
} = props;
const DefaultIcon = () => (
<IconContext.Provider
value={{
className: cx(`w-6 h-6`, {}),
}}
>
<HiOutlineUser />
</IconContext.Provider>
);

return (
<button
onClick={onClick}
className={twMerge(
cx(
`inline-flex overflow-hidden relative justify-center items-center w-10 h-10 bg-gray-100 rounded-full dark:bg-gray-600`,
`text-gray-700 dark:text-gray-100 ${Typography.size.lg}`,
),
className,
)}
>
{!asChild ? <img src={src} alt={alt} className="p-2" /> : <Child>{children}</Child>}
</button>
);
};
export const Avatar = forwardRef<HTMLButtonElement, AvatarType>(
({ children = <DefaultIcon />, src = '', alt = '', className = '', onClick }, ref) => {
return (
<button
ref={ref}
onClick={onClick}
className={twMerge(
cx(
`inline-flex overflow-hidden relative justify-center items-center w-10 h-10 bg-gray-100 rounded-full dark:bg-gray-600`,
`text-gray-700 dark:text-gray-100 ${Typography.size.lg}`,
'outline-none focus-visible:ring-1 focus-visible:ring-gray-900 dark:focus-visible:ring-2 dark:focus-visible:ring-gray-400',
),
className,
)}
>
{!src || src.trim().length === 0 ? (
<>{children}</>
) : (
<img src={src} alt={alt} className="p-2" />
)}
</button>
);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,28 @@ export const ModalWithTrigger = () => {
);
};

export const TriggerFromLeft = () => {
const [open, setOpen] = useState(false);
const ref = useRef(null);

return (
<>
<Button color="primary" onClick={() => setOpen(true)} ref={ref}>
Click to open
</Button>
<SlidingModal
title="Modal Title"
open={open}
onOpenChange={() => setOpen(false)}
elementToFocusOnCloseRef={ref}
direction="left"
>
<div className="dark:text-white">This is a content</div>
</SlidingModal>
</>
);
};

export const WithoutTitle = () => {
const [open, setOpen] = useState(false);
const ref = useRef(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type ChildrenType = {
children: React.ReactNode;
};
export interface ModalProps extends DialogPrimitive.DialogProps {
direction?: 'left' | 'right';
width?: string;
title?: string;
footer?: React.ReactNode;
Expand Down Expand Up @@ -86,6 +87,7 @@ export const SlidingModal: FC<ModalProps> = ({
elementToFocusOnCloseRef,
open,
width = 'w-9/12', // 33.333333%
direction = 'right',
...rest
}) => {
const state = useUpdateStateIfMounted(open);
Expand All @@ -96,6 +98,14 @@ export const SlidingModal: FC<ModalProps> = ({
setWasOpen(open);
}, [open]);

let inAnimation = 'animate-slide-right-in';
let outAnimation = `animate-slide-right-out`;

if (direction === 'left') {
inAnimation = 'animate-slide-left-in';
outAnimation = 'animate-slide-left-out';
}

return (
<DialogPrimitive.Root open={wasOpen} {...rest}>
<DialogPrimitive.Portal>
Expand All @@ -107,14 +117,16 @@ export const SlidingModal: FC<ModalProps> = ({
>
<DialogPrimitive.Content
className={cx(
'flex flex-col h-[100vh] fixed -right-[100%]',
'flex flex-col h-[100vh] fixed',
'overflow-hidden focus:outline-none',
'bg-white text-gray-900',
'dark:bg-gray-700 dark:text-white',
'dark:bg-gray-700 dark:text-white ',
`${width}`,
{
'animate-slide-right-out': !wasOpen,
'animate-slide-right-in': wasOpen,
'-left-[100%]': direction === 'left',
'-right-[100%]': direction === 'right',
[inAnimation]: wasOpen,
[outAnimation]: !wasOpen,
},
)}
onCloseAutoFocus={() => elementToFocusOnCloseRef?.current?.focus()}
Expand Down
8 changes: 8 additions & 0 deletions deepfence_frontend/packages/ui-components/tailwind.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ module.exports = {
'slide-right-out': {
'0%': { right: 0 },
},
'slide-left-in': {
'100%': { left: 0 },
},
'slide-left-out': {
'0%': { left: 0 },
},
'opacity-in': {
'0%': { opacity: 0 },
'100%': { opacity: 1 },
Expand Down Expand Up @@ -102,6 +108,8 @@ module.exports = {
'pop-out': 'pop-out 0.5s ease',
'slide-right-in': 'slide-right-in 0.5s forwards',
'slide-right-out': 'slide-right-out 0.5s forwards',
'slide-left-in': 'slide-left-in 0.2s forwards',
'slide-left-out': 'slide-left-out 0.5s forwards',
'slide-opacity-out': 'slide-opacity-out 0.3s ease',
'opacity-out': 'opacity-out 0.5s ease',
'opacity-in': 'opacity-in 0.5s ease',
Expand Down

0 comments on commit b2705fd

Please sign in to comment.