diff --git a/services/web/frontend/js/features/settings/components/emails/actions/make-primary/confirmation-modal.tsx b/services/web/frontend/js/features/settings/components/emails/actions/make-primary/confirmation-modal.tsx index 75ea0e5163..b1d7482bde 100644 --- a/services/web/frontend/js/features/settings/components/emails/actions/make-primary/confirmation-modal.tsx +++ b/services/web/frontend/js/features/settings/components/emails/actions/make-primary/confirmation-modal.tsx @@ -1,8 +1,13 @@ import { useTranslation, Trans } from 'react-i18next' -import { Modal } from 'react-bootstrap' import AccessibleModal from '../../../../../../shared/components/accessible-modal' import { MergeAndOverride } from '../../../../../../../../types/utils' import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper' +import OLModal, { + OLModalBody, + OLModalFooter, + OLModalHeader, + OLModalTitle, +} from '@/features/ui/components/bootstrap-5/wrappers/ol-modal' type ConfirmationModalProps = MergeAndOverride< React.ComponentProps, @@ -24,11 +29,11 @@ function ConfirmationModal({ const { t } = useTranslation() return ( - - - {t('confirm_primary_email_change')} - - + + + {t('confirm_primary_email_change')} + +

{t('log_in_with_primary_email_address')}

-
- + + {t('confirm')} - -
+ + ) } diff --git a/services/web/frontend/js/features/settings/components/leave/modal-content.tsx b/services/web/frontend/js/features/settings/components/leave/modal-content.tsx index b1edcf995d..40f317e61a 100644 --- a/services/web/frontend/js/features/settings/components/leave/modal-content.tsx +++ b/services/web/frontend/js/features/settings/components/leave/modal-content.tsx @@ -1,10 +1,15 @@ import { useState, Dispatch, SetStateAction } from 'react' -import { Modal } from 'react-bootstrap' import { useTranslation, Trans } from 'react-i18next' import getMeta from '../../../../utils/meta' import LeaveModalForm, { LeaveModalFormProps } from './modal-form' import { ExposedSettings } from '../../../../../../types/exposed-settings' import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper' +import { + OLModalBody, + OLModalFooter, + OLModalHeader, + OLModalTitle, +} from '@/features/ui/components/bootstrap-5/wrappers/ol-modal' type LeaveModalContentProps = { handleHide: () => void @@ -50,11 +55,11 @@ function LeaveModalContent({ return ( <> - - {t('delete_account')} - + + {t('delete_account')} + - +

- + - + {inFlight ? <>{t('deleting')}… : t('delete')} - + ) } diff --git a/services/web/frontend/js/features/settings/components/leave/modal.tsx b/services/web/frontend/js/features/settings/components/leave/modal.tsx index 82b9a5cad1..de22bc495d 100644 --- a/services/web/frontend/js/features/settings/components/leave/modal.tsx +++ b/services/web/frontend/js/features/settings/components/leave/modal.tsx @@ -1,6 +1,6 @@ import { useState, useCallback } from 'react' -import AccessibleModal from '../../../../shared/components/accessible-modal' import LeaveModalContent from './modal-content' +import OLModal from '@/features/ui/components/bootstrap-5/wrappers/ol-modal' type LeaveModalProps = { isOpen: boolean @@ -17,19 +17,19 @@ function LeaveModal({ isOpen, handleClose }: LeaveModalProps) { }, [handleClose, inFlight]) return ( - - + ) } diff --git a/services/web/frontend/js/features/settings/components/linking/integration-widget.tsx b/services/web/frontend/js/features/settings/components/linking/integration-widget.tsx index 6ff979a417..d57c0f7ab5 100644 --- a/services/web/frontend/js/features/settings/components/linking/integration-widget.tsx +++ b/services/web/frontend/js/features/settings/components/linking/integration-widget.tsx @@ -1,12 +1,16 @@ import { useCallback, useState, ReactNode } from 'react' import { useTranslation } from 'react-i18next' -import AccessibleModal from '../../../../shared/components/accessible-modal' -import { Modal } from 'react-bootstrap' import BadgeWrapper from '@/features/ui/components/bootstrap-5/wrappers/badge-wrapper' import getMeta from '../../../../utils/meta' import { sendMB } from '../../../../infrastructure/event-tracking' import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper' import { bsVersion } from '@/features/utils/bootstrap-5' +import OLModal, { + OLModalBody, + OLModalFooter, + OLModalHeader, + OLModalTitle, +} from '@/features/ui/components/bootstrap-5/wrappers/ol-modal' function trackUpgradeClick(integration: string) { sendMB('settings-upgrade-click', { integration }) @@ -201,16 +205,16 @@ function UnlinkConfirmationModal({ } return ( - - - {title} - + + + {title} + - +

{content}

-
+ - +
-
- + + ) } diff --git a/services/web/frontend/js/features/settings/components/linking/sso-widget.tsx b/services/web/frontend/js/features/settings/components/linking/sso-widget.tsx index b5bd379a7f..c27383e542 100644 --- a/services/web/frontend/js/features/settings/components/linking/sso-widget.tsx +++ b/services/web/frontend/js/features/settings/components/linking/sso-widget.tsx @@ -1,14 +1,18 @@ import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' -import { Modal } from 'react-bootstrap' import { FetchError } from '../../../../infrastructure/fetch-json' -import AccessibleModal from '../../../../shared/components/accessible-modal' import IEEELogo from '../../../../shared/svgs/ieee-logo' import GoogleLogo from '../../../../shared/svgs/google-logo' import OrcidLogo from '../../../../shared/svgs/orcid-logo' import LinkingStatus from './status' import ButtonWrapper from '@/features/ui/components/bootstrap-5/wrappers/button-wrapper' import { bsVersion } from '@/features/utils/bootstrap-5' +import OLModal, { + OLModalBody, + OLModalFooter, + OLModalHeader, + OLModalTitle, +} from '@/features/ui/components/bootstrap-5/wrappers/ol-modal' const providerLogos: { readonly [p: string]: JSX.Element } = { collabratec: , @@ -165,18 +169,18 @@ function UnlinkConfirmModal({ const { t } = useTranslation() return ( - - - + + + {t('unlink_provider_account_title', { provider: title })} - - + + - +

{t('unlink_provider_account_warning', { provider: title })}

-
+ - + {t('unlink')} - -
+ + ) } diff --git a/services/web/frontend/js/features/ui/components/bootstrap-5/wrappers/ol-modal.tsx b/services/web/frontend/js/features/ui/components/bootstrap-5/wrappers/ol-modal.tsx new file mode 100644 index 0000000000..991209cfea --- /dev/null +++ b/services/web/frontend/js/features/ui/components/bootstrap-5/wrappers/ol-modal.tsx @@ -0,0 +1,130 @@ +import { Modal as BS5Modal } from 'react-bootstrap-5' +import { + Modal as BS3Modal, + ModalProps as BS3ModalProps, + ModalHeaderProps as BS3ModalHeaderProps, + ModalTitleProps as BS3ModalTitleProps, + ModalBodyProps as BS3ModalBodyProps, + ModalFooterProps as BS3ModalFooterProps, +} from 'react-bootstrap' +import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' +import AccessibleModal from '@/shared/components/accessible-modal' + +type OLModalProps = React.ComponentProps & { + bs3Props?: Record + size?: 'sm' | 'lg' + onHide: () => void +} + +type OLModalHeaderProps = React.ComponentProps & { + bs3Props?: Record +} + +type OLModalTitleProps = React.ComponentProps & { + bs3Props?: Record +} + +type OLModalBodyProps = React.ComponentProps & { + bs3Props?: Record +} + +type OLModalFooterProps = React.ComponentProps & { + bs3Props?: Record +} + +export default function OLModal({ children, ...props }: OLModalProps) { + const { bs3Props, ...bs5Props } = props + + const bs3ModalProps: BS3ModalProps = { + bsClass: bs5Props.bsPrefix, + bsSize: bs5Props.size, + show: bs5Props.show, + onHide: bs5Props.onHide, + backdrop: bs5Props.backdrop, + animation: bs5Props.animation, + dialogComponent: bs5Props.dialogAs, + ...bs3Props, + } + + return ( + {children}} + bs5={{children}} + /> + ) +} + +export function OLModalHeader({ + children, + closeButton, + ...props +}: OLModalHeaderProps) { + const { bs3Props, ...bs5Props } = props + + const bs3ModalProps: BS3ModalHeaderProps = { + bsClass: bs5Props.bsPrefix, + onHide: bs5Props.onHide, + closeButton: bs5Props.closeButton, + closeLabel: bs5Props.closeLabel, + } + return ( + + {children} + + } + bs5={ + + {children} + + } + /> + ) +} + +export function OLModalTitle({ children, ...props }: OLModalTitleProps) { + const { bs3Props, ...bs5Props } = props + + const bs3ModalProps: BS3ModalTitleProps = { + componentClass: bs5Props.as, + } + return ( + {children}} + bs5={{children}} + /> + ) +} + +export function OLModalBody({ children, ...props }: OLModalBodyProps) { + const { bs3Props, ...bs5Props } = props + + const bs3ModalProps: BS3ModalBodyProps = { + componentClass: bs5Props.as, + bsClass: bs5Props.className, + } + + return ( + {children}} + bs5={{children}} + /> + ) +} + +export function OLModalFooter({ children, ...props }: OLModalFooterProps) { + const { bs3Props, ...bs5Props } = props + + const bs3ModalProps: BS3ModalFooterProps = { + componentClass: bs5Props.as, + bsClass: bs5Props.className, + } + + return ( + {children}} + bs5={{children}} + /> + ) +} diff --git a/services/web/frontend/stylesheets/bootstrap-5/abstracts/mixins.scss b/services/web/frontend/stylesheets/bootstrap-5/abstracts/mixins.scss index e05df3844c..c581822cac 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/abstracts/mixins.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/abstracts/mixins.scss @@ -52,3 +52,13 @@ border: 0; appearance: none; } + +@mixin modal-lg { + max-width: 960px; +} +@mixin modal-md { + max-width: 640px; +} +@mixin modal-sm { + max-width: 480px; +} diff --git a/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss b/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss index 8d99c0a2e9..2654fac64a 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/abstracts/variable-overrides.scss @@ -129,6 +129,11 @@ $form-validation-states: ( 'border-color': var(--#{$prefix}form-invalid-border-color), ), ); +// Close buttons +// Close button +$btn-close-color: $content-primary; +$btn-close-opacity: 1; +$btn-close-width: 10px; // Colors $primary: $bg-accent-01; @@ -166,3 +171,15 @@ $headings-margin-bottom: $spacing-05; // Horizontal rules $hr-margin-y: $spacing-08; $hr-border-color: $border-divider; + +// Modals +$modal-content-color: $content-secondary; +$modal-content-border-color: $border-divider; +$modal-backdrop-bg: $bg-dark-primary; +$modal-backdrop-opacity: 0.72; +$box-shadow: shadow-lg(); +$box-shadow-sm: shadow-lg(); +$box-shadow-lg: shadow-lg(); +$modal-header-padding: $spacing-05 $spacing-06; +$modal-header-padding-x: $spacing-08; +$modal-header-padding-y: $spacing-08; diff --git a/services/web/frontend/stylesheets/bootstrap-5/base/bootstrap.scss b/services/web/frontend/stylesheets/bootstrap-5/base/bootstrap.scss index c48ed5e4d5..dd6379ca14 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/base/bootstrap.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/base/bootstrap.scss @@ -34,6 +34,7 @@ @import 'bootstrap-5/scss/tooltip'; @import 'bootstrap-5/scss/spinners'; @import 'bootstrap-5/scss/card'; +@import 'bootstrap-5/scss/close'; // Helpers @import 'bootstrap-5/scss/helpers'; diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/all.scss b/services/web/frontend/stylesheets/bootstrap-5/components/all.scss index 24c499e401..5040eb55d7 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/components/all.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/components/all.scss @@ -7,4 +7,5 @@ @import 'badge'; @import 'form'; @import 'input-suggestions'; +@import 'modal'; @import 'footer'; diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/modal.scss b/services/web/frontend/stylesheets/bootstrap-5/components/modal.scss new file mode 100644 index 0000000000..42dbad8836 --- /dev/null +++ b/services/web/frontend/stylesheets/bootstrap-5/components/modal.scss @@ -0,0 +1,35 @@ +:root { + --bs-heading-color: var(--content-primary); +} + +@include media-breakpoint-up(sm) { + .modal-dialog { + @include modal-md(); + } + + .modal-sm { + @include modal-sm(); + } +} + +@include media-breakpoint-up(md) { + .modal-md { + @include modal-md(); + } +} + +@include media-breakpoint-up(lg) { + .modal-lg { + @include modal-lg(); + } +} + +.modal-content { + @include shadow-lg(); +} + +.modal-header { + .btn-close { + margin: var(--spacing-00); + } +} diff --git a/services/web/frontend/stylesheets/bootstrap-5/foundations/elevation.scss b/services/web/frontend/stylesheets/bootstrap-5/foundations/elevation.scss index 710865ca9c..78cec48f0f 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/foundations/elevation.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/foundations/elevation.scss @@ -13,6 +13,6 @@ // Modals, drawers @mixin shadow-lg { box-shadow: - 0 8px 24px rgb(30 37 48 / 16%), - 0 4px 8px rgb(30 37 48 / 16%); + 0px 8px 16px 0px rgb(30 37 48 / 12%), + 0px 4px 6px 0px rgb(30 37 48 / 12%); }