From c836bbbfc2123fd04f536f6c4173e65f20df8653 Mon Sep 17 00:00:00 2001 From: nitin <142569587+ehconitin@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:07:32 +0530 Subject: [PATCH] Fixed SignInUp Modal misalignment for devices smaller than 400px width (#6386) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hi @Bonapara, Issue #6385 I encountered an issue with the Modal component where its width was fixed at 400px. While the container housing the Modal adjusted its size based on the screen width, the Modal itself remained at 400px regardless of the screen size. I have implemented a change to address this problem. Could you please review the changes and let me know your thoughts? Thank you! https://github.com/user-attachments/assets/8358aacb-d6c3-440e-895e-7abc4f8a3534 --------- Co-authored-by: Félix Malfait --- .../components/{Modal.tsx => AuthModal.tsx} | 13 +- .../components/ModalWrapper.tsx | 20 +- .../components/StepNavigationButton.tsx | 1 + .../MatchColumnsStep/MatchColumnsStep.tsx | 2 +- .../SelectHeaderStep/SelectHeaderStep.tsx | 2 +- .../SelectSheetStep/SelectSheetStep.tsx | 3 +- .../steps/components/Steps.tsx | 3 +- .../steps/components/UploadFlow.tsx | 2 +- .../components/UploadStep/UploadStep.tsx | 3 +- .../ValidationStep/ValidationStep.tsx | 2 +- .../dialog-manager/components/Dialog.tsx | 2 +- .../modal/components/ConfirmationModal.tsx | 100 +++---- .../ui/layout/modal/components/Modal.tsx | 249 ++++++++++++++---- .../layout/modal/components/ModalLayout.tsx | 173 ------------ .../components/__stories__/Modal.stories.tsx | 3 - .../__stories__/ModalLayout.stories.tsx | 36 --- .../modules/ui/layout/page/DefaultLayout.tsx | 3 +- .../src/theme/constants/BackgroundDark.ts | 3 +- .../src/theme/constants/BackgroundLight.ts | 3 +- .../twenty-ui/src/theme/constants/Modal.ts | 1 + 20 files changed, 286 insertions(+), 338 deletions(-) rename packages/twenty-front/src/modules/auth/components/{Modal.tsx => AuthModal.tsx} (51%) delete mode 100644 packages/twenty-front/src/modules/ui/layout/modal/components/ModalLayout.tsx delete mode 100644 packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/ModalLayout.stories.tsx diff --git a/packages/twenty-front/src/modules/auth/components/Modal.tsx b/packages/twenty-front/src/modules/auth/components/AuthModal.tsx similarity index 51% rename from packages/twenty-front/src/modules/auth/components/Modal.tsx rename to packages/twenty-front/src/modules/auth/components/AuthModal.tsx index f40de47cf5d..0bef31d15df 100644 --- a/packages/twenty-front/src/modules/auth/components/Modal.tsx +++ b/packages/twenty-front/src/modules/auth/components/AuthModal.tsx @@ -1,17 +1,16 @@ -import React from 'react'; +import { Modal } from '@/ui/layout/modal/components/Modal'; import styled from '@emotion/styled'; +import React from 'react'; -import { ModalLayout } from '@/ui/layout/modal/components/ModalLayout'; - -const StyledContent = styled(ModalLayout.Content)` +const StyledContent = styled(Modal.Content)` align-items: center; - width: calc(400px - ${({ theme }) => theme.spacing(10 * 2)}); + justify-content: center; `; type AuthModalProps = { children: React.ReactNode }; export const AuthModal = ({ children }: AuthModalProps) => ( - + {children} - + ); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/components/ModalWrapper.tsx b/packages/twenty-front/src/modules/spreadsheet-import/components/ModalWrapper.tsx index d9de117e241..1b69206fd81 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/components/ModalWrapper.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/components/ModalWrapper.tsx @@ -2,8 +2,8 @@ import styled from '@emotion/styled'; import { MOBILE_VIEWPORT } from 'twenty-ui'; import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal'; -import { Modal } from '@/ui/layout/modal/components/Modal'; +import { Modal } from '@/ui/layout/modal/components/Modal'; import { ModalCloseButton } from './ModalCloseButton'; const StyledModal = styled(Modal)` @@ -16,7 +16,7 @@ const StyledModal = styled(Modal)` min-width: auto; min-height: auto; width: 100%; - height: 100%; + height: 80%; } `; @@ -40,11 +40,15 @@ export const ModalWrapper = ({ const { rtl } = useSpreadsheetImportInternal(); return ( - - - - {children} - - + <> + {isOpen && ( + + + + {children} + + + )} + ); }; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/components/StepNavigationButton.tsx b/packages/twenty-front/src/modules/spreadsheet-import/components/StepNavigationButton.tsx index 85f58d92315..2f09b9f4108 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/components/StepNavigationButton.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/components/StepNavigationButton.tsx @@ -2,6 +2,7 @@ import styled from '@emotion/styled'; import { CircularProgressBar } from '@/ui/feedback/progress-bar/components/CircularProgressBar'; import { MainButton } from '@/ui/input/button/components/MainButton'; + import { Modal } from '@/ui/layout/modal/components/Modal'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx index 866ad298e6b..666af5c1f43 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx @@ -14,8 +14,8 @@ import { setSubColumn } from '@/spreadsheet-import/utils/setSubColumn'; import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { Modal } from '@/ui/layout/modal/components/Modal'; +import { Modal } from '@/ui/layout/modal/components/Modal'; import { ColumnGrid } from './components/ColumnGrid'; import { TemplateColumn } from './components/TemplateColumn'; import { UserTableColumn } from './components/UserTableColumn'; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx index 6958e32757d..a7107cb71b8 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx @@ -4,8 +4,8 @@ import { useCallback, useState } from 'react'; import { Heading } from '@/spreadsheet-import/components/Heading'; import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton'; import { ImportedRow } from '@/spreadsheet-import/types'; -import { Modal } from '@/ui/layout/modal/components/Modal'; +import { Modal } from '@/ui/layout/modal/components/Modal'; import { SelectHeaderTable } from './components/SelectHeaderTable'; const StyledHeading = styled(Heading)` diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectSheetStep/SelectSheetStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectSheetStep/SelectSheetStep.tsx index 713b17ff77b..58e61ba9723 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectSheetStep/SelectSheetStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectSheetStep/SelectSheetStep.tsx @@ -1,10 +1,11 @@ -import { useCallback, useState } from 'react'; import styled from '@emotion/styled'; +import { useCallback, useState } from 'react'; import { Heading } from '@/spreadsheet-import/components/Heading'; import { StepNavigationButton } from '@/spreadsheet-import/components/StepNavigationButton'; import { Radio } from '@/ui/input/components/Radio'; import { RadioGroup } from '@/ui/input/components/RadioGroup'; + import { Modal } from '@/ui/layout/modal/components/Modal'; const StyledContent = styled(Modal.Content)` diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/Steps.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/Steps.tsx index d478fc86e9e..1b21a981bec 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/Steps.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/Steps.tsx @@ -3,10 +3,11 @@ import { MOBILE_VIEWPORT } from 'twenty-ui'; import { useSpreadsheetImportInitialStep } from '@/spreadsheet-import/hooks/useSpreadsheetImportInitialStep'; import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal'; -import { Modal } from '@/ui/layout/modal/components/Modal'; + import { StepBar } from '@/ui/navigation/step-bar/components/StepBar'; import { useStepBar } from '@/ui/navigation/step-bar/hooks/useStepBar'; +import { Modal } from '@/ui/layout/modal/components/Modal'; import { UploadFlow } from './UploadFlow'; const StyledHeader = styled(Modal.Header)` diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx index ae84f9d794d..a74495da4fb 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx @@ -10,8 +10,8 @@ import { mapWorkbook } from '@/spreadsheet-import/utils/mapWorkbook'; import { CircularProgressBar } from '@/ui/feedback/progress-bar/components/CircularProgressBar'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { Modal } from '@/ui/layout/modal/components/Modal'; +import { Modal } from '@/ui/layout/modal/components/Modal'; import { Columns, MatchColumnsStep } from './MatchColumnsStep/MatchColumnsStep'; import { SelectHeaderStep } from './SelectHeaderStep/SelectHeaderStep'; import { SelectSheetStep } from './SelectSheetStep/SelectSheetStep'; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx index f0cdc1bb438..54f1a040371 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx @@ -1,9 +1,8 @@ -import { useCallback, useState } from 'react'; import styled from '@emotion/styled'; +import { useCallback, useState } from 'react'; import { WorkBook } from 'xlsx-ugnis'; import { Modal } from '@/ui/layout/modal/components/Modal'; - import { DropZone } from './components/DropZone'; const StyledContent = styled(Modal.Content)` diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx index fb8f15f5d3c..2c20ed969cc 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx @@ -20,9 +20,9 @@ import { addErrorsAndRunHooks } from '@/spreadsheet-import/utils/dataMutations'; import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager'; import { Button } from '@/ui/input/button/components/Button'; import { Toggle } from '@/ui/input/components/Toggle'; -import { Modal } from '@/ui/layout/modal/components/Modal'; import { isDefined } from '~/utils/isDefined'; +import { Modal } from '@/ui/layout/modal/components/Modal'; import { generateColumns } from './components/columns'; import { ImportedStructuredRowMetadata } from './types'; diff --git a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/Dialog.tsx b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/Dialog.tsx index 90e0a4d2248..c8e5d05cbd4 100644 --- a/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/Dialog.tsx +++ b/packages/twenty-front/src/modules/ui/feedback/dialog-manager/components/Dialog.tsx @@ -11,7 +11,7 @@ import { DialogHotkeyScope } from '../types/DialogHotkeyScope'; const StyledDialogOverlay = styled(motion.div)` align-items: center; - background: ${({ theme }) => theme.background.overlay}; + background: ${({ theme }) => theme.background.overlayPrimary}; display: flex; height: 100dvh; justify-content: center; diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx index 402b94c51c0..67cb20253e9 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx @@ -6,6 +6,7 @@ import { useDebouncedCallback } from 'use-debounce'; import { Button, ButtonAccent } from '@/ui/input/button/components/Button'; import { TextInput } from '@/ui/input/components/TextInput'; + import { Modal } from '@/ui/layout/modal/components/Modal'; import { Section, @@ -27,8 +28,8 @@ export type ConfirmationModalProps = { const StyledConfirmationModal = styled(Modal)` border-radius: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(6)}; width: calc(400px - ${({ theme }) => theme.spacing(32)}); + height: auto; `; const StyledCenteredButton = styled(Button)` @@ -85,54 +86,57 @@ export const ConfirmationModal = ({ return ( - { - if (isOpen) { - setIsOpen(false); - } - }} - onEnter={onConfirmClick} - > - - - - - {subtitle} - - {confirmationValue && ( -
- -
- )} - setIsOpen(false)} - variant="secondary" - title="Cancel" - fullWidth - /> - { - await onConfirmClick(); - setIsOpen(false); + {isOpen && ( + { + if (isOpen) { + setIsOpen(false); + } }} - variant="secondary" - accent={confirmButtonAccent} - title={deleteButtonText} - disabled={!isValidValue} - fullWidth - dataTestId="confirmation-modal-confirm-button" - /> - + onEnter={onConfirmClick} + isClosable={true} + padding="large" + > + + + + + {subtitle} + + {confirmationValue && ( +
+ +
+ )} + setIsOpen(false)} + variant="secondary" + title="Cancel" + fullWidth + /> + { + await onConfirmClick(); + setIsOpen(false); + }} + variant="secondary" + accent={confirmButtonAccent} + title={deleteButtonText} + disabled={!isValidValue} + fullWidth + dataTestId="confirmation-modal-confirm-button" + /> +
+ )}
); diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx index d9fd4f181c1..abd6bb2f053 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx @@ -1,46 +1,183 @@ -import { useEffect, useRef } from 'react'; -import { Key } from 'ts-key-enum'; - -import { - ModalLayout, - ModalLayoutProps, -} from '@/ui/layout/modal/components/ModalLayout'; +import { ModalHotkeyScope } from '@/ui/layout/modal/components/types/ModalHotkeyScope'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; - import { useListenClickOutsideV2 } from '@/ui/utilities/pointer-event/hooks/useListenClickOutsideV2'; -import { ModalHotkeyScope } from './types/ModalHotkeyScope'; +import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; +import styled from '@emotion/styled'; +import { motion } from 'framer-motion'; +import React, { useEffect, useRef } from 'react'; +import { Key } from 'ts-key-enum'; -type ModalProps = ModalLayoutProps & { - isOpen?: boolean; +const StyledModalDiv = styled(motion.div)<{ + size?: ModalSize; + padding?: ModalPadding; + isMobile: boolean; +}>` + display: flex; + flex-direction: column; + background: ${({ theme }) => theme.background.primary}; + color: ${({ theme }) => theme.font.color.primary}; + border-radius: ${({ theme, isMobile }) => { + if (isMobile) return `0`; + return theme.border.radius.md; + }}; + overflow: hidden; + z-index: 10000; // should be higher than Backdrop's z-index + + width: ${({ isMobile, size, theme }) => { + if (isMobile) return theme.modal.size.fullscreen; + switch (size) { + case 'small': + return theme.modal.size.sm; + case 'medium': + return theme.modal.size.md; + case 'large': + return theme.modal.size.lg; + default: + return 'auto'; + } + }}; + + padding: ${({ padding, theme }) => { + switch (padding) { + case 'none': + return theme.spacing(0); + case 'small': + return theme.spacing(2); + case 'medium': + return theme.spacing(4); + case 'large': + return theme.spacing(6); + default: + return 'auto'; + } + }}; + height: ${({ isMobile, theme }) => + isMobile ? theme.modal.size.fullscreen : 'auto'}; + max-height: ${({ isMobile }) => (isMobile ? 'none' : '90dvh')}; +`; + +const StyledHeader = styled.div` + align-items: center; + display: flex; + flex-direction: row; + height: 60px; + overflow: hidden; + padding: ${({ theme }) => theme.spacing(5)}; +`; + +const StyledContent = styled.div` + display: flex; + flex: 1; + flex: 1 1 0%; + flex-direction: column; + overflow-y: auto; + padding: ${({ theme }) => theme.spacing(10)}; +`; + +const StyledFooter = styled.div` + align-items: center; + display: flex; + flex-direction: row; + height: 60px; + overflow: hidden; + padding: ${({ theme }) => theme.spacing(5)}; +`; + +const StyledBackDrop = styled(motion.div)<{ + modalVariant: ModalVariants; +}>` + align-items: center; + background: ${({ theme, modalVariant }) => + modalVariant === 'primary' + ? theme.background.overlayPrimary + : theme.background.overlaySecondary}; + display: flex; + height: 100%; + justify-content: center; + left: 0; + position: fixed; + top: 0; + width: 100%; + z-index: 9999; + user-select: none; +`; + +type ModalHeaderProps = React.PropsWithChildren & { + className?: string; +}; + +const ModalHeader = ({ children, className }: ModalHeaderProps) => ( + {children} +); + +type ModalContentProps = React.PropsWithChildren & { + className?: string; +}; + +const ModalContent = ({ children, className }: ModalContentProps) => ( + {children} +); + +type ModalFooterProps = React.PropsWithChildren & { + className?: string; +}; + +const ModalFooter = ({ children, className }: ModalFooterProps) => ( + {children} +); + +export type ModalSize = 'small' | 'medium' | 'large'; +export type ModalPadding = 'none' | 'small' | 'medium' | 'large'; +export type ModalVariants = 'primary' | 'secondary'; + +export type ModalProps = React.PropsWithChildren & { + size?: ModalSize; + padding?: ModalPadding; + className?: string; hotkeyScope?: ModalHotkeyScope; - onClose?: () => void; onEnter?: () => void; + modalVariant?: ModalVariants; +} & ( + | { isClosable: true; onClose: () => void } + | { isClosable?: false; onClose?: never } + ); + +const modalAnimation = { + hidden: { opacity: 0 }, + visible: { opacity: 1 }, + exit: { opacity: 0 }, }; export const Modal = ({ - isOpen = false, children, - onClose, - hotkeyScope = ModalHotkeyScope.Default, - onEnter, size = 'medium', padding = 'medium', className, + hotkeyScope = ModalHotkeyScope.Default, + onEnter, + isClosable = false, + onClose, + modalVariant = 'primary', }: ModalProps) => { + const isMobile = useIsMobile(); + const modalRef = useRef(null); + const { goBackToPreviousHotkeyScope, setHotkeyScopeAndMemorizePreviousScope, } = usePreviousHotkeyScope(); - useScopedHotkeys( - [Key.Escape], - () => { - onClose?.(); - }, + useEffect(() => { + setHotkeyScopeAndMemorizePreviousScope(hotkeyScope); + return () => { + goBackToPreviousHotkeyScope(); + }; + }, [ hotkeyScope, - [onClose], - ); + setHotkeyScopeAndMemorizePreviousScope, + goBackToPreviousHotkeyScope, + ]); useScopedHotkeys( [Key.Enter], @@ -50,41 +187,53 @@ export const Modal = ({ hotkeyScope, ); - useEffect(() => { - if (isOpen) { - setHotkeyScopeAndMemorizePreviousScope(hotkeyScope); - } else { - goBackToPreviousHotkeyScope(); - } - }, [ - goBackToPreviousHotkeyScope, + useScopedHotkeys( + [Key.Escape], + () => { + if (isClosable && onClose !== undefined) { + onClose(); + } + }, hotkeyScope, - isOpen, - setHotkeyScopeAndMemorizePreviousScope, - ]); - - const modalRef = useRef(null); + ); useListenClickOutsideV2({ refs: [modalRef], listenerId: 'MODAL_CLICK_OUTSIDE_LISTENER_ID', - callback: () => onClose?.(), + callback: () => { + if (isClosable && onClose !== undefined) { + onClose(); + } + }, }); - return isOpen ? ( - { + e.stopPropagation(); + }; + + return ( + - {children} - - ) : ( - <> + + {children} + + ); }; -Modal.Header = ModalLayout.Header; -Modal.Content = ModalLayout.Content; -Modal.Footer = ModalLayout.Footer; +Modal.Header = ModalHeader; +Modal.Content = ModalContent; +Modal.Footer = ModalFooter; diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/ModalLayout.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/ModalLayout.tsx deleted file mode 100644 index d11c6be921a..00000000000 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/ModalLayout.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import React from 'react'; -import styled from '@emotion/styled'; -import { motion } from 'framer-motion'; - -const StyledModalDiv = styled(motion.div)<{ - size?: ModalSize; - padding?: ModalPadding; -}>` - display: flex; - flex-direction: column; - background: ${({ theme }) => theme.background.primary}; - color: ${({ theme }) => theme.font.color.primary}; - border-radius: ${({ theme }) => theme.border.radius.md}; - overflow: hidden; - max-height: 90vh; - z-index: 10000; // should be higher than Backdrop's z-index - - width: ${({ size, theme }) => { - switch (size) { - case 'small': - return theme.modal.size.sm; - case 'medium': - return theme.modal.size.md; - case 'large': - return theme.modal.size.lg; - default: - return 'auto'; - } - }}; - - padding: ${({ padding, theme }) => { - switch (padding) { - case 'none': - return theme.spacing(0); - case 'small': - return theme.spacing(2); - case 'medium': - return theme.spacing(4); - case 'large': - return theme.spacing(6); - default: - return 'auto'; - } - }}; -`; - -const StyledHeader = styled.div` - align-items: center; - display: flex; - flex-direction: row; - height: 60px; - overflow: hidden; - padding: ${({ theme }) => theme.spacing(5)}; -`; - -const StyledContent = styled.div` - display: flex; - flex: 1; - flex: 1 1 0%; - flex-direction: column; - overflow-y: auto; - padding: ${({ theme }) => theme.spacing(10)}; -`; - -const StyledFooter = styled.div` - align-items: center; - display: flex; - flex-direction: row; - height: 60px; - overflow: hidden; - padding: ${({ theme }) => theme.spacing(5)}; -`; - -const StyledBackDrop = styled(motion.div)` - align-items: center; - background: ${({ theme }) => theme.background.overlay}; - display: flex; - height: 100%; - justify-content: center; - left: 0; - position: fixed; - top: 0; - width: 100%; - z-index: 9999; - user-select: none; -`; - -/** - * Modal components - */ -type ModalLayoutHeaderProps = React.PropsWithChildren & { - className?: string; -}; - -const ModalLayoutHeader = ({ children, className }: ModalLayoutHeaderProps) => ( - {children} -); - -type ModalLayoutContentProps = React.PropsWithChildren & { - className?: string; -}; - -const ModalLayoutContent = ({ - children, - className, -}: ModalLayoutContentProps) => ( - {children} -); - -type ModalLayoutFooterProps = React.PropsWithChildren & { - className?: string; -}; - -const ModalLayoutFooter = ({ children, className }: ModalLayoutFooterProps) => ( - {children} -); - -/** - * Modal - */ -export type ModalSize = 'small' | 'medium' | 'large'; -export type ModalPadding = 'none' | 'small' | 'medium' | 'large'; - -export type ModalLayoutProps = React.PropsWithChildren & { - size?: ModalSize; - padding?: ModalPadding; - className?: string; - modalRef?: React.RefObject; -}; - -const modalVariants = { - hidden: { opacity: 0 }, - visible: { opacity: 1 }, - exit: { opacity: 0 }, -}; - -// This component should be used over Modal when seeking a modal feel without modal state (hotkeyScope etc) -export const ModalLayout = ({ - children, - size = 'medium', - padding = 'medium', - modalRef, - className, -}: ModalLayoutProps) => { - const stopEventPropagation = (e: React.MouseEvent) => { - e.stopPropagation(); - }; - - return ( - - - {children} - - - ); -}; - -ModalLayout.Header = ModalLayoutHeader; -ModalLayout.Content = ModalLayoutContent; -ModalLayout.Footer = ModalLayoutFooter; diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/Modal.stories.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/Modal.stories.tsx index d27d09f2b66..919bf33d47f 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/Modal.stories.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/Modal.stories.tsx @@ -2,7 +2,6 @@ import { Meta, StoryObj } from '@storybook/react'; import { ComponentDecorator } from 'twenty-ui'; import { Modal } from '../Modal'; -import { ModalHotkeyScope } from '../types/ModalHotkeyScope'; const meta: Meta = { title: 'UI/Layout/Modal/Modal', @@ -14,10 +13,8 @@ type Story = StoryObj; export const Default: Story = { args: { - isOpen: true, size: 'medium', padding: 'medium', - hotkeyScope: ModalHotkeyScope.Default, children: ( <> Stay in touch diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/ModalLayout.stories.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/ModalLayout.stories.tsx deleted file mode 100644 index 538c7b29923..00000000000 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/ModalLayout.stories.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Meta, StoryObj } from '@storybook/react'; -import { ComponentDecorator } from 'twenty-ui'; - -import { ModalLayout } from '@/ui/layout/modal/components/ModalLayout'; - -const meta: Meta = { - title: 'UI/Layout/Modal/ModalLayout', - component: ModalLayout, -}; - -export default meta; -type Story = StoryObj; - -export const Default: Story = { - args: { - size: 'medium', - padding: 'medium', - children: ( - <> - Stay in touch - - This is a dummy newletter form so don't bother trying to test it. Not - that I expect you to, anyways. :) - - - By using Twenty, you're opting for the finest CRM experience you'll - ever encounter. - - - ), - }, - decorators: [ComponentDecorator], - argTypes: { - children: { control: false }, - }, -}; diff --git a/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx b/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx index a41e7914249..4108f6a5cee 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx @@ -2,8 +2,6 @@ import { css, Global, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { AnimatePresence, LayoutGroup, motion } from 'framer-motion'; import { Outlet } from 'react-router-dom'; - -import { AuthModal } from '@/auth/components/Modal'; import { CommandMenu } from '@/command-menu/components/CommandMenu'; import { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary'; import { KeyboardShortcutMenu } from '@/keyboard-shortcut-menu/components/KeyboardShortcutMenu'; @@ -16,6 +14,7 @@ import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal'; import { DESKTOP_NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/DesktopNavDrawerWidths'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useScreenSize } from '@/ui/utilities/screen-size/hooks/useScreenSize'; +import { AuthModal } from '@/auth/components/AuthModal'; const StyledLayout = styled.div` background: ${({ theme }) => theme.background.noisy}; diff --git a/packages/twenty-ui/src/theme/constants/BackgroundDark.ts b/packages/twenty-ui/src/theme/constants/BackgroundDark.ts index df00ccf90b3..b594cb842bb 100644 --- a/packages/twenty-ui/src/theme/constants/BackgroundDark.ts +++ b/packages/twenty-ui/src/theme/constants/BackgroundDark.ts @@ -23,7 +23,8 @@ export const BACKGROUND_DARK = { lighter: RGBA(GRAY_SCALE.gray0, 0.03), danger: RGBA(COLOR.red, 0.08), }, - overlay: RGBA(GRAY_SCALE.gray80, 0.8), + overlayPrimary: RGBA(GRAY_SCALE.gray80, 0.8), + overlaySecondary: RGBA(GRAY_SCALE.gray80, 0.4), radialGradient: `radial-gradient(50% 62.62% at 50% 0%, #505050 0%, ${GRAY_SCALE.gray60} 100%)`, radialGradientHover: `radial-gradient(76.32% 95.59% at 50% 0%, #505050 0%, ${GRAY_SCALE.gray60} 100%)`, primaryInverted: GRAY_SCALE.gray20, diff --git a/packages/twenty-ui/src/theme/constants/BackgroundLight.ts b/packages/twenty-ui/src/theme/constants/BackgroundLight.ts index 82f1eccbf78..187ecf7de8a 100644 --- a/packages/twenty-ui/src/theme/constants/BackgroundLight.ts +++ b/packages/twenty-ui/src/theme/constants/BackgroundLight.ts @@ -23,7 +23,8 @@ export const BACKGROUND_LIGHT = { lighter: RGBA(GRAY_SCALE.gray100, 0.02), danger: RGBA(COLOR.red, 0.08), }, - overlay: RGBA(GRAY_SCALE.gray80, 0.8), + overlayPrimary: RGBA(GRAY_SCALE.gray80, 0.8), + overlaySecondary: RGBA(GRAY_SCALE.gray80, 0.4), radialGradient: `radial-gradient(50% 62.62% at 50% 0%, #505050 0%, ${GRAY_SCALE.gray60} 100%)`, radialGradientHover: `radial-gradient(76.32% 95.59% at 50% 0%, #505050 0%, ${GRAY_SCALE.gray60} 100%)`, primaryInverted: GRAY_SCALE.gray60, diff --git a/packages/twenty-ui/src/theme/constants/Modal.ts b/packages/twenty-ui/src/theme/constants/Modal.ts index 2a53265cc00..f72880127e9 100644 --- a/packages/twenty-ui/src/theme/constants/Modal.ts +++ b/packages/twenty-ui/src/theme/constants/Modal.ts @@ -3,5 +3,6 @@ export const MODAL = { sm: '300px', md: '400px', lg: '53%', + fullscreen: `100dvh`, }, };