From 8e10ac9ab50a1e2a0f40ba1ad07907a8017a02df Mon Sep 17 00:00:00 2001 From: David Cho-Lerat Date: Fri, 12 May 2023 16:25:44 +0200 Subject: [PATCH] SONAR-19170 Create new Modal component in design-system/ --- server/sonar-web/design-system/package.json | 1 + .../design-system/src/components/index.ts | 1 + .../src/components/modal/Modal.tsx | 158 ++++++++++++++++++ .../src/components/modal/ModalBody.tsx | 47 ++++++ .../src/components/modal/ModalFooter.tsx | 43 +++++ .../src/components/modal/ModalHeader.tsx | 51 ++++++ .../components/modal/__tests__/Modal-test.tsx | 90 ++++++++++ .../modal/__tests__/ModalBody-test.tsx | 33 ++++ .../modal/__tests__/ModalFooter-test.tsx | 56 +++++++ .../modal/__tests__/ModalHeader-test.tsx | 45 +++++ .../__snapshots__/ModalBody-test.tsx.snap | 29 ++++ .../__snapshots__/ModalFooter-test.tsx.snap | 66 ++++++++ .../__snapshots__/ModalHeader-test.tsx.snap | 75 +++++++++ .../design-system/src/helpers/constants.ts | 4 +- .../design-system/src/theme/light.ts | 6 +- server/sonar-web/tailwind.base.config.js | 2 + server/sonar-web/yarn.lock | 1 + 17 files changed, 706 insertions(+), 2 deletions(-) create mode 100644 server/sonar-web/design-system/src/components/modal/Modal.tsx create mode 100644 server/sonar-web/design-system/src/components/modal/ModalBody.tsx create mode 100644 server/sonar-web/design-system/src/components/modal/ModalFooter.tsx create mode 100644 server/sonar-web/design-system/src/components/modal/ModalHeader.tsx create mode 100644 server/sonar-web/design-system/src/components/modal/__tests__/Modal-test.tsx create mode 100644 server/sonar-web/design-system/src/components/modal/__tests__/ModalBody-test.tsx create mode 100644 server/sonar-web/design-system/src/components/modal/__tests__/ModalFooter-test.tsx create mode 100644 server/sonar-web/design-system/src/components/modal/__tests__/ModalHeader-test.tsx create mode 100644 server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap create mode 100644 server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap create mode 100644 server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap diff --git a/server/sonar-web/design-system/package.json b/server/sonar-web/design-system/package.json index bedf128e5e1..45633e20409 100644 --- a/server/sonar-web/design-system/package.json +++ b/server/sonar-web/design-system/package.json @@ -62,6 +62,7 @@ "react-helmet-async": "1.3.0", "react-highlight-words": "0.20.0", "react-intl": "6.2.5", + "react-modal": "3.16.1", "react-router-dom": "6.10.0", "react-select": "5.7.2", "tailwindcss": "3.3.1" diff --git a/server/sonar-web/design-system/src/components/index.ts b/server/sonar-web/design-system/src/components/index.ts index 74092bf20ac..7fefefbfc7f 100644 --- a/server/sonar-web/design-system/src/components/index.ts +++ b/server/sonar-web/design-system/src/components/index.ts @@ -71,5 +71,6 @@ export * from './buttons'; export { ClipboardIconButton } from './clipboard'; export * from './icons'; export * from './layouts'; +export * from './modal/Modal'; export * from './popups'; export * from './subnavigation'; diff --git a/server/sonar-web/design-system/src/components/modal/Modal.tsx b/server/sonar-web/design-system/src/components/modal/Modal.tsx new file mode 100644 index 00000000000..95d6213cbb8 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/Modal.tsx @@ -0,0 +1,158 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { Global, css, useTheme } from '@emotion/react'; +import classNames from 'classnames'; +import { ReactNode } from 'react'; +import ReactModal from 'react-modal'; +import tw from 'twin.macro'; +import { themeColor } from '../../helpers'; +import { REACT_DOM_CONTAINER } from '../../helpers/constants'; +import { translate } from '../../helpers/l10n'; +import { Theme } from '../../types/theme'; +import { ButtonSecondary } from '../buttons'; +import { ModalBody } from './ModalBody'; +import { ModalFooter } from './ModalFooter'; +import { ModalHeader } from './ModalHeader'; + +ReactModal.setAppElement(REACT_DOM_CONTAINER); + +interface CommonProps { + closeOnOverlayClick?: boolean; + isLarge?: boolean; + isOpen?: boolean; + isScrollable?: boolean; + onClose: VoidFunction; +} + +interface ChildrenProp { + children: React.ReactNode; +} + +interface NotChildrenProp { + children?: never; +} + +interface SectionsProps { + body: React.ReactNode; + headerDescription?: string | ReactNode; + headerTitle: string | ReactNode; + loading?: boolean; + primaryButton?: ReactNode; + secondaryButtonLabel: ReactNode; +} + +type NotSectionsProps = { + [prop in keyof SectionsProps]?: never; +}; + +export type PropsWithChildren = CommonProps & ChildrenProp & NotSectionsProps; + +export type PropsWithSections = CommonProps & SectionsProps & NotChildrenProp; + +type Props = PropsWithChildren | PropsWithSections; + +function hasNoChildren(props: Partial): props is PropsWithSections { + return (props as PropsWithChildren).children === undefined; +} + +export function Modal({ + closeOnOverlayClick = true, + isLarge, + isOpen = true, + isScrollable = true, + onClose, + ...props +}: Props) { + const theme = useTheme(); + + return ( + <> + + + + {hasNoChildren(props) ? ( + <> + + + {props.body} + + + {props.secondaryButtonLabel ?? translate('close')} + + } + /> + + ) : ( + (props as PropsWithChildren).children + )} + + + ); +} + +const globalStyles = ({ theme }: { theme: Theme }) => css` + .design-system-modal-contents { + ${tw`sw-container sw-flex sw-flex-col`} + ${tw`sw-p-9`} + ${tw`sw-rounded-2`} + ${tw`sw-z-modal`} + + background-color: ${themeColor('modalContents')({ theme })}; + max-height: calc(100vh - 30px); + min-height: 160px; + width: 544px; + + &.large { + max-width: 1280px; + min-width: 1040px; + } + } + + .design-system-modal-overlay { + ${tw`sw-fixed sw-inset-0`} + ${tw`sw-flex sw-items-center sw-justify-center`} + ${tw`sw-z-modal-overlay`} + + background-color: ${themeColor('modalOverlay')({ theme })}; + } +`; + +Modal.Body = ModalBody; +Modal.Footer = ModalFooter; +Modal.Header = ModalHeader; diff --git a/server/sonar-web/design-system/src/components/modal/ModalBody.tsx b/server/sonar-web/design-system/src/components/modal/ModalBody.tsx new file mode 100644 index 00000000000..5a3b1f19832 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/ModalBody.tsx @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import styled from '@emotion/styled'; +import classNames from 'classnames'; +import { ReactNode } from 'react'; +import tw from 'twin.macro'; +import { themeColor } from '../../helpers/theme'; + +interface Props { + children: ReactNode; + isScrollable?: boolean; +} + +export function ModalBody({ children, isScrollable = true }: Props) { + return {children}; +} + +const StyledMain = styled.main` + ${tw`sw-body-sm`} + ${tw`sw-pr-3`} // to accomodate a possible scrollbar + ${tw`sw-my-12`} + ${tw`sw-overflow-x-hidden`} + + color: ${themeColor('pageContent')}; + + &.scrollable { + overflow-y: auto; + } +`; diff --git a/server/sonar-web/design-system/src/components/modal/ModalFooter.tsx b/server/sonar-web/design-system/src/components/modal/ModalFooter.tsx new file mode 100644 index 00000000000..72d75b6cce5 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/ModalFooter.tsx @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import styled from '@emotion/styled'; +import tw from 'twin.macro'; +import { DeferredSpinner } from '../DeferredSpinner'; + +interface Props { + loading?: boolean; + primaryButton?: React.ReactNode; + secondaryButton: React.ReactNode; +} + +export function ModalFooter({ loading = false, primaryButton, secondaryButton }: Props) { + return ( + + + {primaryButton} + {secondaryButton} + + ); +} + +const StyledFooter = styled.footer` + ${tw`sw-flex sw-gap-3 sw-items-center sw-justify-end`} +`; diff --git a/server/sonar-web/design-system/src/components/modal/ModalHeader.tsx b/server/sonar-web/design-system/src/components/modal/ModalHeader.tsx new file mode 100644 index 00000000000..eaa02e175cb --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/ModalHeader.tsx @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import styled from '@emotion/styled'; +import { ReactNode } from 'react'; +import tw from 'twin.macro'; +import { themeColor } from '../../helpers/theme'; + +interface Props { + description?: string | ReactNode; + title: string | ReactNode; +} + +export function ModalHeader({ description, title }: Props) { + return ( +
+ {title} + {description && {description}} +
+ ); +} + +const Description = styled.p` + ${tw`sw-body-sm`} + ${tw`sw-mt-2`} + + color: ${themeColor('pageContent')}; +`; + +const Title = styled.p` + ${tw`sw-heading-lg`} + + color: ${themeColor('pageTitle')}; +`; diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/Modal-test.tsx b/server/sonar-web/design-system/src/components/modal/__tests__/Modal-test.tsx new file mode 100644 index 00000000000..86085f547dd --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/Modal-test.tsx @@ -0,0 +1,90 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { screen } from '@testing-library/react'; +import { render } from '../../../helpers/testUtils'; +import { Modal, PropsWithChildren, PropsWithSections } from '../Modal'; + +it('should render default modal with predefined content', async () => { + setupPredefinedContent({ + body: 'Modal body', + headerTitle: 'Hello', + headerDescription: 'Does this look OK?', + secondaryButtonLabel: undefined, // should use the default of 'Close' + }); + + expect(await screen.findByText('Modal body')).toBeVisible(); + expect(await screen.findByText('Hello')).toBeVisible(); + expect(await screen.findByText('Does this look OK?')).toBeVisible(); + expect(await screen.findByRole('button', { name: 'close' })).toBeVisible(); +}); + +it('should request close when pressing esc', async () => { + const onClose = jest.fn(); + const { user } = setupPredefinedContent({ onClose }); + + await user.keyboard('{Escape}'); + + expect(onClose).toHaveBeenCalled(); +}); + +it('should render modal with loose content', async () => { + setupLooseContent(undefined,
Hello
); + + expect(await screen.findByText('Hello')).toBeVisible(); +}); + +it('should request close when pressing esc on loose content', async () => { + const onClose = jest.fn(); + const { user } = setupLooseContentWithMultipleChildren({ onClose }); + + await user.keyboard('{Escape}'); + + expect(onClose).toHaveBeenCalled(); +}); + +function setupPredefinedContent(props: Partial = {}) { + return render( + + ); +} + +function setupLooseContent(props: Partial = {}, children =
) { + return render( + + {children} + + ); +} + +function setupLooseContentWithMultipleChildren(props: Partial = {}) { + return render( + +
Hello there!
+
How are you?
+
+ ); +} diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/ModalBody-test.tsx b/server/sonar-web/design-system/src/components/modal/__tests__/ModalBody-test.tsx new file mode 100644 index 00000000000..690cd99d821 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/ModalBody-test.tsx @@ -0,0 +1,33 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { render } from '../../../helpers/testUtils'; +import { ModalBody } from '../ModalBody'; + +it('renders with children', () => { + const children =
Hello!
; + const { container } = setup(children); + + expect(container).toMatchSnapshot(); +}); + +function setup(children =
) { + return render({children}); +} diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/ModalFooter-test.tsx b/server/sonar-web/design-system/src/components/modal/__tests__/ModalFooter-test.tsx new file mode 100644 index 00000000000..ab2c19c133d --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/ModalFooter-test.tsx @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; +import { ModalFooter } from '../ModalFooter'; + +it('should render with secondary button', () => { + const { container } = setupWithProps({ + secondaryButton: ( + + ), + }); + + expect(container).toMatchSnapshot(); +}); + +it('should render with primary and secondary buttons', () => { + const { container } = setupWithProps({ + primaryButton: ( + + ), + secondaryButton: ( + + ), + }); + + expect(container).toMatchSnapshot(); +}); + +function setupWithProps(props: Partial> = {}) { + return render(} {...props} />); +} diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/ModalHeader-test.tsx b/server/sonar-web/design-system/src/components/modal/__tests__/ModalHeader-test.tsx new file mode 100644 index 00000000000..a3a163a66d1 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/ModalHeader-test.tsx @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { render } from '../../../helpers/testUtils'; +import { FCProps } from '../../../types/misc'; +import { ModalHeader } from '../ModalHeader'; + +it('should use the default title if not provided', () => { + const { container } = setupWithProps(); + + expect(container).toMatchSnapshot(); +}); + +it('should render with title', () => { + const { container } = setupWithProps({ title: 'Foo' }); + + expect(container).toMatchSnapshot(); +}); + +it('should render with title and description', () => { + const { container } = setupWithProps({ title: 'Foo', description: 'Bar' }); + + expect(container).toMatchSnapshot(); +}); + +function setupWithProps(props: Partial> = {}) { + return render(); +} diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap new file mode 100644 index 00000000000..8f64b28df6b --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalBody-test.tsx.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders with children 1`] = ` +.emotion-0 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 400; + padding-right: 0.75rem; + margin-top: 3rem; + margin-bottom: 3rem; + overflow-x: hidden; + color: rgb(62,67,87); +} + +.emotion-0.scrollable { + overflow-y: auto; +} + +
+
+
+ Hello! +
+
+
+`; diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap new file mode 100644 index 00000000000..250bd886c0e --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalFooter-test.tsx.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render with primary and secondary buttons 1`] = ` +.emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: end; + -ms-flex-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + gap: 0.75rem; +} + +
+
+ + +
+
+`; + +exports[`should render with secondary button 1`] = ` +.emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: end; + -ms-flex-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + gap: 0.75rem; +} + +
+
+ +
+
+`; diff --git a/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap new file mode 100644 index 00000000000..10d1204b2e5 --- /dev/null +++ b/server/sonar-web/design-system/src/components/modal/__tests__/__snapshots__/ModalHeader-test.tsx.snap @@ -0,0 +1,75 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render with title 1`] = ` +.emotion-0 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 1.5rem; + line-height: 1.75rem; + font-weight: 600; + color: rgb(29,33,47); +} + +
+
+

+ Foo +

+
+
+`; + +exports[`should render with title and description 1`] = ` +.emotion-0 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 1.5rem; + line-height: 1.75rem; + font-weight: 600; + color: rgb(29,33,47); +} + +.emotion-2 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 400; + margin-top: 0.5rem; + color: rgb(62,67,87); +} + +
+
+

+ Foo +

+

+ Bar +

+
+
+`; + +exports[`should use the default title if not provided 1`] = ` +.emotion-0 { + font-family: Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + font-size: 1.5rem; + line-height: 1.75rem; + font-weight: 600; + color: rgb(29,33,47); +} + +
+
+

+ Modal title +

+
+
+`; diff --git a/server/sonar-web/design-system/src/helpers/constants.ts b/server/sonar-web/design-system/src/helpers/constants.ts index 9d87c9245ee..e7f44f2f2aa 100644 --- a/server/sonar-web/design-system/src/helpers/constants.ts +++ b/server/sonar-web/design-system/src/helpers/constants.ts @@ -22,7 +22,7 @@ import { theme } from 'twin.macro'; export const DEFAULT_LOCALE = 'en'; export const IS_SSR = typeof window === 'undefined'; -export const REACT_DOM_CONTAINER = '#___gatsby'; +export const REACT_DOM_CONTAINER = '#content'; export const RULE_STATUSES = ['READY', 'BETA', 'DEPRECATED']; @@ -72,3 +72,5 @@ export const CORE_CONCEPTS_WIDTH = 350; export const DARK_THEME_ID = 'dark-theme'; export const OPACITY_20_PERCENT = 0.2; + +export const OPACITY_75_PERCENT = 0.75; diff --git a/server/sonar-web/design-system/src/theme/light.ts b/server/sonar-web/design-system/src/theme/light.ts index cbcebc1e185..7a3756efbde 100644 --- a/server/sonar-web/design-system/src/theme/light.ts +++ b/server/sonar-web/design-system/src/theme/light.ts @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { OPACITY_20_PERCENT } from '../helpers/constants'; +import { OPACITY_20_PERCENT, OPACITY_75_PERCENT } from '../helpers/constants'; import COLORS from './colors'; const primary = { @@ -92,6 +92,10 @@ export const lightTheme = { popup: COLORS.white, popupBorder: secondary.default, + // modal + modalContents: COLORS.white, + modalOverlay: [...COLORS.blueGrey[900], OPACITY_75_PERCENT], + // dropdown menu dropdownMenu: COLORS.white, dropdownMenuHover: secondary.light, diff --git a/server/sonar-web/tailwind.base.config.js b/server/sonar-web/tailwind.base.config.js index 3971e725b8b..af6c8b43a7f 100644 --- a/server/sonar-web/tailwind.base.config.js +++ b/server/sonar-web/tailwind.base.config.js @@ -110,6 +110,8 @@ module.exports = { 'global-popup': '5000', 'dropdown-menu': '7500', tooltip: '8000', + 'modal-overlay': 8500, + modal: '9000', }, extend: { width: { diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock index 96fdeac3e61..1847ec4d86a 100644 --- a/server/sonar-web/yarn.lock +++ b/server/sonar-web/yarn.lock @@ -6173,6 +6173,7 @@ __metadata: react-helmet-async: 1.3.0 react-highlight-words: 0.20.0 react-intl: 6.2.5 + react-modal: 3.16.1 react-router-dom: 6.10.0 react-select: 5.7.2 tailwindcss: 3.3.1 -- 2.39.5