mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-24 01:29:35 +02:00
Merge pull request #18127 from overleaf/rd-bs-modal
[web] - Migrate the Modal to Bootstrap 5 on the Account Settings page GitOrigin-RevId: 90799125f837742b4887eab762ca9ff84a67e70b
This commit is contained in:
@@ -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<typeof AccessibleModal>,
|
||||
@@ -24,11 +29,11 @@ function ConfirmationModal({
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<AccessibleModal show={show} onHide={onHide}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>{t('confirm_primary_email_change')}</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body className="modal-body-share">
|
||||
<OLModal show={show} onHide={onHide}>
|
||||
<OLModalHeader closeButton>
|
||||
<OLModalTitle>{t('confirm_primary_email_change')}</OLModalTitle>
|
||||
</OLModalHeader>
|
||||
<OLModalBody>
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey="do_you_want_to_change_your_primary_email_address_to"
|
||||
@@ -39,8 +44,8 @@ function ConfirmationModal({
|
||||
/>
|
||||
</p>
|
||||
<p className="mb-0">{t('log_in_with_primary_email_address')}</p>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
</OLModalBody>
|
||||
<OLModalFooter>
|
||||
<ButtonWrapper
|
||||
variant="secondary"
|
||||
onClick={onHide}
|
||||
@@ -59,8 +64,8 @@ function ConfirmationModal({
|
||||
>
|
||||
{t('confirm')}
|
||||
</ButtonWrapper>
|
||||
</Modal.Footer>
|
||||
</AccessibleModal>
|
||||
</OLModalFooter>
|
||||
</OLModal>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>{t('delete_account')}</Modal.Title>
|
||||
</Modal.Header>
|
||||
<OLModalHeader closeButton>
|
||||
<OLModalTitle>{t('delete_account')}</OLModalTitle>
|
||||
</OLModalHeader>
|
||||
|
||||
<Modal.Body>
|
||||
<OLModalBody>
|
||||
<p>
|
||||
<Trans
|
||||
i18nKey="delete_account_warning_message_3"
|
||||
@@ -66,9 +71,9 @@ function LeaveModalContent({
|
||||
isFormValid={isFormValid}
|
||||
setIsFormValid={setIsFormValid}
|
||||
/>
|
||||
</Modal.Body>
|
||||
</OLModalBody>
|
||||
|
||||
<Modal.Footer>
|
||||
<OLModalFooter>
|
||||
<ButtonWrapper
|
||||
disabled={inFlight}
|
||||
onClick={handleHide}
|
||||
@@ -86,7 +91,7 @@ function LeaveModalContent({
|
||||
>
|
||||
{inFlight ? <>{t('deleting')}…</> : t('delete')}
|
||||
</ButtonWrapper>
|
||||
</Modal.Footer>
|
||||
</OLModalFooter>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<AccessibleModal
|
||||
<OLModal
|
||||
animation
|
||||
show={isOpen}
|
||||
onHide={handleHide}
|
||||
id="leave-modal"
|
||||
backdrop="static"
|
||||
bs3Props={{ backdrop: 'static' }}
|
||||
>
|
||||
<LeaveModalContent
|
||||
handleHide={handleHide}
|
||||
inFlight={inFlight}
|
||||
setInFlight={setInFlight}
|
||||
/>
|
||||
</AccessibleModal>
|
||||
</OLModal>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<AccessibleModal show={show} onHide={handleHide}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>{title}</Modal.Title>
|
||||
</Modal.Header>
|
||||
<OLModal show={show} onHide={handleHide}>
|
||||
<OLModalHeader closeButton>
|
||||
<OLModalTitle>{title}</OLModalTitle>
|
||||
</OLModalHeader>
|
||||
|
||||
<Modal.Body className="modal-body-share">
|
||||
<OLModalBody>
|
||||
<p>{content}</p>
|
||||
</Modal.Body>
|
||||
</OLModalBody>
|
||||
|
||||
<Modal.Footer>
|
||||
<OLModalFooter>
|
||||
<form action={unlinkPath} method="POST" className="form-inline">
|
||||
<input type="hidden" name="_csrf" value={getMeta('ol-csrfToken')} />
|
||||
<ButtonWrapper
|
||||
@@ -232,7 +236,7 @@ function UnlinkConfirmationModal({
|
||||
{t('unlink')}
|
||||
</ButtonWrapper>
|
||||
</form>
|
||||
</Modal.Footer>
|
||||
</AccessibleModal>
|
||||
</OLModalFooter>
|
||||
</OLModal>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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: <IEEELogo />,
|
||||
@@ -165,18 +169,18 @@ function UnlinkConfirmModal({
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<AccessibleModal show={show} onHide={handleHide}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>
|
||||
<OLModal show={show} onHide={handleHide}>
|
||||
<OLModalHeader closeButton>
|
||||
<OLModalTitle>
|
||||
{t('unlink_provider_account_title', { provider: title })}
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
</OLModalTitle>
|
||||
</OLModalHeader>
|
||||
|
||||
<Modal.Body className="modal-body-share">
|
||||
<OLModalBody>
|
||||
<p>{t('unlink_provider_account_warning', { provider: title })}</p>
|
||||
</Modal.Body>
|
||||
</OLModalBody>
|
||||
|
||||
<Modal.Footer>
|
||||
<OLModalFooter>
|
||||
<ButtonWrapper
|
||||
variant="secondary"
|
||||
onClick={handleHide}
|
||||
@@ -194,7 +198,7 @@ function UnlinkConfirmModal({
|
||||
>
|
||||
{t('unlink')}
|
||||
</ButtonWrapper>
|
||||
</Modal.Footer>
|
||||
</AccessibleModal>
|
||||
</OLModalFooter>
|
||||
</OLModal>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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<typeof BS5Modal> & {
|
||||
bs3Props?: Record<string, unknown>
|
||||
size?: 'sm' | 'lg'
|
||||
onHide: () => void
|
||||
}
|
||||
|
||||
type OLModalHeaderProps = React.ComponentProps<typeof BS5Modal> & {
|
||||
bs3Props?: Record<string, unknown>
|
||||
}
|
||||
|
||||
type OLModalTitleProps = React.ComponentProps<typeof BS5Modal> & {
|
||||
bs3Props?: Record<string, unknown>
|
||||
}
|
||||
|
||||
type OLModalBodyProps = React.ComponentProps<typeof BS5Modal> & {
|
||||
bs3Props?: Record<string, unknown>
|
||||
}
|
||||
|
||||
type OLModalFooterProps = React.ComponentProps<typeof BS5Modal> & {
|
||||
bs3Props?: Record<string, unknown>
|
||||
}
|
||||
|
||||
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 (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={<AccessibleModal {...bs3ModalProps}>{children}</AccessibleModal>}
|
||||
bs5={<BS5Modal {...bs5Props}>{children}</BS5Modal>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
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 (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={
|
||||
<BS3Modal.Header {...bs3ModalProps} closeButton={closeButton}>
|
||||
{children}
|
||||
</BS3Modal.Header>
|
||||
}
|
||||
bs5={
|
||||
<BS5Modal.Header {...bs5Props} closeButton={closeButton}>
|
||||
{children}
|
||||
</BS5Modal.Header>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function OLModalTitle({ children, ...props }: OLModalTitleProps) {
|
||||
const { bs3Props, ...bs5Props } = props
|
||||
|
||||
const bs3ModalProps: BS3ModalTitleProps = {
|
||||
componentClass: bs5Props.as,
|
||||
}
|
||||
return (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={<BS3Modal.Title {...bs3ModalProps}>{children}</BS3Modal.Title>}
|
||||
bs5={<BS5Modal.Title {...bs5Props}>{children}</BS5Modal.Title>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function OLModalBody({ children, ...props }: OLModalBodyProps) {
|
||||
const { bs3Props, ...bs5Props } = props
|
||||
|
||||
const bs3ModalProps: BS3ModalBodyProps = {
|
||||
componentClass: bs5Props.as,
|
||||
bsClass: bs5Props.className,
|
||||
}
|
||||
|
||||
return (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={<BS3Modal.Body {...bs3ModalProps}>{children}</BS3Modal.Body>}
|
||||
bs5={<BS5Modal.Body {...bs5Props}>{children}</BS5Modal.Body>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function OLModalFooter({ children, ...props }: OLModalFooterProps) {
|
||||
const { bs3Props, ...bs5Props } = props
|
||||
|
||||
const bs3ModalProps: BS3ModalFooterProps = {
|
||||
componentClass: bs5Props.as,
|
||||
bsClass: bs5Props.className,
|
||||
}
|
||||
|
||||
return (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={<BS3Modal.Footer {...bs3ModalProps}>{children}</BS3Modal.Footer>}
|
||||
bs5={<BS5Modal.Footer {...bs5Props}>{children}</BS5Modal.Footer>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
@import 'badge';
|
||||
@import 'form';
|
||||
@import 'input-suggestions';
|
||||
@import 'modal';
|
||||
@import 'footer';
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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%);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user