Deduplicate CommonModal Props (#1649)

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2021-11-26 21:51:12 +01:00 committed by GitHub
parent 1e27263abb
commit e0a0c86846
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 91 additions and 105 deletions

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React from 'react'
import React, { useMemo } from 'react'
import { Modal } from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
import { ForkAwesomeIcon } from '../fork-awesome/fork-awesome-icon'
@ -13,31 +13,40 @@ import { ShowIf } from '../show-if/show-if'
import type { PropsWithDataCypressId } from '../../../utils/cypress-attribute'
import { cypressId } from '../../../utils/cypress-attribute'
export interface CommonModalProps extends PropsWithDataCypressId {
export interface ModalVisibilityProps {
show: boolean
onHide?: () => void
titleI18nKey?: string
}
export interface ModalContentProps {
title?: string
closeButton?: boolean
icon?: IconName
size?: 'lg' | 'sm' | 'xl'
titleIsI18nKey?: boolean
showCloseButton?: boolean
titleIcon?: IconName
modalSize?: 'lg' | 'sm' | 'xl'
additionalClasses?: string
}
export type CommonModalProps = PropsWithDataCypressId & ModalVisibilityProps & ModalContentProps
export const CommonModal: React.FC<CommonModalProps> = ({
show,
onHide,
titleI18nKey,
title,
closeButton,
icon,
showCloseButton,
titleIcon,
additionalClasses,
size,
modalSize,
children,
titleIsI18nKey = true,
...props
}) => {
useTranslation()
const titleElement = useMemo(() => {
return titleIsI18nKey ? <Trans i18nKey={title} /> : <span>{title}</span>
}, [title, titleIsI18nKey])
return (
<Modal
{...cypressId(props)}
@ -45,14 +54,14 @@ export const CommonModal: React.FC<CommonModalProps> = ({
onHide={onHide}
animation={true}
dialogClassName={`text-dark ${additionalClasses ?? ''}`}
size={size}>
<Modal.Header closeButton={!!closeButton}>
size={modalSize}>
<Modal.Header closeButton={!!showCloseButton}>
<Modal.Title>
<ShowIf condition={!!icon}>
<ForkAwesomeIcon icon={icon as IconName} />
<ShowIf condition={!!titleIcon}>
<ForkAwesomeIcon icon={titleIcon as IconName} />
&nbsp;
</ShowIf>
{titleI18nKey ? <Trans i18nKey={titleI18nKey} /> : <span>{title}</span>}
{titleElement}
</Modal.Title>
</Modal.Header>
{children}

View file

@ -18,17 +18,17 @@ export interface DeletionModalProps extends CommonModalProps {
export const DeletionModal: React.FC<DeletionModalProps> = ({
show,
onHide,
titleI18nKey,
title,
onConfirm,
deletionButtonI18nKey,
icon,
titleIcon,
children,
...props
}) => {
useTranslation()
return (
<CommonModal show={show} onHide={onHide} titleI18nKey={titleI18nKey} icon={icon} closeButton={true} {...props}>
<CommonModal show={show} onHide={onHide} title={title} titleIcon={titleIcon} showCloseButton={true} {...props}>
<Modal.Body className='text-dark'>{children}</Modal.Body>
<Modal.Footer>
<Button variant='danger' onClick={onConfirm}>

View file

@ -48,7 +48,7 @@ export const MotdModal: React.FC = () => {
return null
} else {
return (
<CommonModal {...cypressId('motd')} show={!!motdState} titleI18nKey={'motd.title'}>
<CommonModal {...cypressId('motd')} show={!!motdState} title={'motd.title'}>
<Modal.Body>{domContent}</Modal.Body>
<Modal.Footer>
<Button variant={'success'} onClick={dismiss} {...cypressId('motd-dismiss')}>

View file

@ -10,7 +10,7 @@ import { Trans, useTranslation } from 'react-i18next'
import './cheatsheet.scss'
import { CheatsheetLine } from './cheatsheet-line'
export const Cheatsheet: React.FC = () => {
export const CheatsheetTabContent: React.FC = () => {
const { t } = useTranslation()
const [checked, setChecked] = useState<boolean>(false)
const codes = useMemo(
@ -58,4 +58,4 @@ export const Cheatsheet: React.FC = () => {
)
}
export default Cheatsheet
export default CheatsheetTabContent

View file

@ -7,10 +7,11 @@
import { Button, Modal } from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
import React, { useMemo, useState } from 'react'
import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
import { CommonModal } from '../../../common/modals/common-modal'
import { Shortcut } from './shortcuts'
import { Links } from './links'
import { Cheatsheet } from './cheatsheet'
import { ShortcutTabContent } from './shortcuts-tab-content'
import { LinksTabContent } from './links-tab-content'
import { CheatsheetTabContent } from './cheatsheet-tab-content'
export enum HelpTabStatus {
Cheatsheet = 'cheatsheet.title',
@ -18,30 +19,31 @@ export enum HelpTabStatus {
Links = 'links.title'
}
export interface HelpModalProps {
show: boolean
onHide: () => void
}
export const HelpModal: React.FC<HelpModalProps> = ({ show, onHide }) => {
export const HelpModal: React.FC<ModalVisibilityProps> = ({ show, onHide }) => {
const [tab, setTab] = useState<HelpTabStatus>(HelpTabStatus.Cheatsheet)
const { t } = useTranslation()
const tabContent = useMemo(() => {
switch (tab) {
case HelpTabStatus.Cheatsheet:
return <Cheatsheet />
return <CheatsheetTabContent />
case HelpTabStatus.Shortcuts:
return <Shortcut />
return <ShortcutTabContent />
case HelpTabStatus.Links:
return <Links />
return <LinksTabContent />
}
}, [tab])
const tabTitle = useMemo(() => t('editor.documentBar.help') + ' - ' + t(`editor.help.${tab}`), [t, tab])
const modalTitle = useMemo(() => t('editor.documentBar.help') + ' - ' + t(`editor.help.${tab}`), [t, tab])
return (
<CommonModal size={'lg'} icon={'question-circle'} show={show} onHide={onHide} title={tabTitle}>
<CommonModal
modalSize={'lg'}
titleIcon={'question-circle'}
show={show}
onHide={onHide}
title={modalTitle}
titleIsI18nKey={false}>
<Modal.Body>
<nav className='nav nav-tabs'>
<Button

View file

@ -11,7 +11,7 @@ import links from '../../../../links.json'
import { TranslatedExternalLink } from '../../../common/links/translated-external-link'
import { TranslatedInternalLink } from '../../../common/links/translated-internal-link'
export const Links: React.FC = () => {
export const LinksTabContent: React.FC = () => {
useTranslation()
return (

View file

@ -9,7 +9,7 @@ import { Card, ListGroup, Row } from 'react-bootstrap'
import { Trans } from 'react-i18next'
import { isMac } from '../../utils'
export const Shortcut: React.FC = () => {
export const ShortcutTabContent: React.FC = () => {
const modifierKey = isMac ? <kbd></kbd> : <kbd>Ctrl</kbd>
const altKey = isMac ? <kbd></kbd> : <kbd>Alt</kbd>

View file

@ -8,6 +8,7 @@ import { DateTime } from 'luxon'
import React from 'react'
import { ListGroup, Modal } from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
import { CommonModal } from '../../../common/modals/common-modal'
import { DocumentInfoLine } from './document-info-line'
import { DocumentInfoLineWithTimeMode, DocumentInfoTimeLine } from './document-info-time-line'
@ -16,12 +17,7 @@ import { useCustomizeAssetsUrl } from '../../../../hooks/common/use-customize-as
import { DocumentInfoLineWordCount } from './document-info-line-word-count'
import { cypressId } from '../../../../utils/cypress-attribute'
export interface DocumentInfoModalProps {
show: boolean
onHide: () => void
}
export const DocumentInfoModal: React.FC<DocumentInfoModalProps> = ({ show, onHide }) => {
export const DocumentInfoModal: React.FC<ModalVisibilityProps> = ({ show, onHide }) => {
const assetsBaseUrl = useCustomizeAssetsUrl()
useTranslation()
@ -30,8 +26,8 @@ export const DocumentInfoModal: React.FC<DocumentInfoModalProps> = ({ show, onHi
<CommonModal
show={show}
onHide={onHide}
closeButton={true}
titleI18nKey={'editor.modal.documentInfo.title'}
showCloseButton={true}
title={'editor.modal.documentInfo.title'}
{...cypressId('document-info-modal')}>
<Modal.Body>
<ListGroup>

View file

@ -8,6 +8,7 @@ import React, { useEffect, useState } from 'react'
import { Alert, Modal } from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
import { getUserById } from '../../../../api/users'
import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
import { CommonModal } from '../../../common/modals/common-modal'
import { ShowIf } from '../../../common/show-if/show-if'
import type { UserAvatarProps } from '../../../common/user-avatar/user-avatar'
@ -15,11 +16,6 @@ import { UserAvatar } from '../../../common/user-avatar/user-avatar'
import { GroupMode, PermissionGroupEntry } from './permission-group-entry'
import { PermissionList } from './permission-list'
export interface PermissionsModalProps {
show: boolean
onHide: () => void
}
export interface Principal {
id: string
name: string
@ -66,7 +62,7 @@ const permissionsApiResponse: NotePermissions = {
]
}
export const PermissionModal: React.FC<PermissionsModalProps> = ({ show, onHide }) => {
export const PermissionModal: React.FC<ModalVisibilityProps> = ({ show, onHide }) => {
useTranslation()
const [error, setError] = useState(false)
const [userList, setUserList] = useState<Principal[]>([])
@ -138,7 +134,7 @@ export const PermissionModal: React.FC<PermissionsModalProps> = ({ show, onHide
}
return (
<CommonModal show={show} onHide={onHide} closeButton={true} titleI18nKey={'editor.modal.permissions.title'}>
<CommonModal show={show} onHide={onHide} showCloseButton={true} title={'editor.modal.permissions.title'}>
<Modal.Body>
<h5 className={'mb-3'}>
<Trans i18nKey={'editor.modal.permissions.owner'} />

View file

@ -14,18 +14,14 @@ import type { Revision, RevisionListEntry } from '../../../../api/revisions/type
import type { UserResponse } from '../../../../api/users/types'
import { useIsDarkModeActivated } from '../../../../hooks/common/use-is-dark-mode-activated'
import { useNoteMarkdownContent } from '../../../../hooks/common/use-note-markdown-content'
import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
import { CommonModal } from '../../../common/modals/common-modal'
import { ShowIf } from '../../../common/show-if/show-if'
import { RevisionModalListEntry } from './revision-modal-list-entry'
import './revision-modal.scss'
import { downloadRevision, getUserDataForRevision } from './utils'
export interface PermissionsModalProps {
show: boolean
onHide: () => void
}
export const RevisionModal: React.FC<PermissionsModalProps> = ({ show, onHide }) => {
export const RevisionModal: React.FC<ModalVisibilityProps> = ({ show, onHide }) => {
useTranslation()
const [revisions, setRevisions] = useState<RevisionListEntry[]>([])
const [selectedRevisionTimestamp, setSelectedRevisionTimestamp] = useState<number | null>(null)
@ -67,10 +63,10 @@ export const RevisionModal: React.FC<PermissionsModalProps> = ({ show, onHide })
<CommonModal
show={show}
onHide={onHide}
titleI18nKey={'editor.modal.revision.title'}
icon={'history'}
closeButton={true}
size={'xl'}
title={'editor.modal.revision.title'}
titleIcon={'history'}
showCloseButton={true}
modalSize={'xl'}
additionalClasses='revision-modal'>
<Modal.Body>
<Row>

View file

@ -10,18 +10,14 @@ import { Trans, useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'
import { useFrontendBaseUrl } from '../../../../hooks/common/use-frontend-base-url'
import { CopyableField } from '../../../common/copyable/copyable-field/copyable-field'
import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
import { CommonModal } from '../../../common/modals/common-modal'
import { ShowIf } from '../../../common/show-if/show-if'
import type { EditorPagePathParams } from '../../editor-page'
import { NoteType } from '../../../common/note-frontmatter/types'
import { useApplicationState } from '../../../../hooks/common/use-application-state'
export interface ShareModalProps {
show: boolean
onHide: () => void
}
export const ShareModal: React.FC<ShareModalProps> = ({ show, onHide }) => {
export const ShareModal: React.FC<ModalVisibilityProps> = ({ show, onHide }) => {
useTranslation()
const noteFrontmatter = useApplicationState((state) => state.noteDetails.frontmatter)
const editorMode = useApplicationState((state) => state.editorConfig.editorMode)
@ -29,7 +25,7 @@ export const ShareModal: React.FC<ShareModalProps> = ({ show, onHide }) => {
const { id } = useParams<EditorPagePathParams>()
return (
<CommonModal show={show} onHide={onHide} closeButton={true} titleI18nKey={'editor.modal.shareLink.title'}>
<CommonModal show={show} onHide={onHide} showCloseButton={true} title={'editor.modal.shareLink.title'}>
<Modal.Body>
<Trans i18nKey={'editor.modal.shareLink.editorDescription'} />
<CopyableField

View file

@ -7,12 +7,11 @@
import React from 'react'
import { Button, Modal } from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
import type { ModalVisibilityProps } from '../../common/modals/common-modal'
import { CommonModal } from '../../common/modals/common-modal'
import { cypressId } from '../../../utils/cypress-attribute'
export interface MaxLengthWarningModalProps {
show: boolean
onHide: () => void
export interface MaxLengthWarningModalProps extends ModalVisibilityProps {
maxLength: number
}
@ -24,8 +23,8 @@ export const MaxLengthWarningModal: React.FC<MaxLengthWarningModalProps> = ({ sh
{...cypressId('limitReachedModal')}
show={show}
onHide={onHide}
titleI18nKey={'editor.error.limitReached.title'}
closeButton={true}>
title={'editor.error.limitReached.title'}
showCloseButton={true}>
<Modal.Body>
<Trans i18nKey={'editor.error.limitReached.description'} values={{ maxLength }} />
<strong className='mt-2 d-block'>

View file

@ -32,9 +32,9 @@ export const EditorPreferences: React.FC = () => {
<CommonModal
show={showModal}
onHide={() => setShowModal(false)}
titleI18nKey={'editor.modal.preferences.title'}
closeButton={true}
icon={'wrench'}>
title={'editor.modal.preferences.title'}
showCloseButton={true}
titleIcon={'wrench'}>
<Form>
<ListGroup>
<ListGroup.Item>

View file

@ -40,9 +40,9 @@ export const CustomTableSizeModal: React.FC<CustomTableSizeModalProps> = ({ show
<CommonModal
show={showModal}
onHide={() => onDismiss()}
titleI18nKey={'editor.editorToolbar.table.customSize'}
closeButton={true}
icon={'table'}>
title={'editor.editorToolbar.table.customSize'}
showCloseButton={true}
titleIcon={'table'}>
<div className={'col-lg-10 d-flex flex-row p-3 align-items-center'}>
<Form.Control
type={'number'}

View file

@ -24,7 +24,7 @@ export const DeleteNoteSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({ hi
deletionButtonI18nKey={'editor.modal.deleteNote.button'}
show={showDialog}
onHide={() => setShowDialog(false)}
titleI18nKey={'editor.modal.deleteNote.title'}>
title={'editor.modal.deleteNote.title'}>
<h5>
<Trans i18nKey={'editor.modal.deleteNote.question'} />
</h5>

View file

@ -51,7 +51,7 @@ export const DropdownItemWithDeletionModal: React.FC<DropdownItemWithDeletionMod
deletionButtonI18nKey={modalButtonI18nKey}
show={showDialog}
onHide={() => setShowDialog(false)}
titleI18nKey={modalTitleI18nKey}>
title={modalTitleI18nKey}>
<h5>
<Trans i18nKey={modalQuestionI18nKey} />
</h5>

View file

@ -42,7 +42,7 @@ export const ClearHistoryButton: React.FC = () => {
deletionButtonI18nKey={'landing.history.toolbar.clear'}
show={show}
onHide={handleClose}
titleI18nKey={'landing.history.modal.clearHistory.title'}>
title={'landing.history.modal.clearHistory.title'}>
<h5>
<Trans i18nKey={'landing.history.modal.clearHistory.question'} />
</h5>

View file

@ -35,8 +35,8 @@ export const VersionInfoModal: React.FC<CommonModalProps> = ({ onHide, show }) =
{...cypressId('version-modal')}
show={show}
onHide={onHide}
closeButton={true}
titleI18nKey={'landing.versionInfo.title'}>
showCloseButton={true}
title={'landing.versionInfo.title'}>
<Modal.Body>
<Row>
<VersionInfoModalColumn

View file

@ -5,14 +5,12 @@
*/
import React from 'react'
import { Modal } from 'react-bootstrap'
import { ForkAwesomeIcon } from '../../../common/fork-awesome/fork-awesome-icon'
import './lightbox.scss'
import { ProxyImageFrame } from './proxy-image-frame'
import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
import { CommonModal } from '../../../common/modals/common-modal'
export interface ImageLightboxModalProps {
show: boolean
onHide: () => void
export interface ImageLightboxModalProps extends ModalVisibilityProps {
alt?: string
src?: string
title?: string
@ -20,21 +18,15 @@ export interface ImageLightboxModalProps {
export const ImageLightboxModal: React.FC<ImageLightboxModalProps> = ({ show, onHide, src, alt, title }) => {
return (
<Modal
animation={true}
centered={true}
dialogClassName={'text-dark lightbox'}
<CommonModal
modalSize={'xl'}
show={show && !!src}
onHide={onHide}
size={'xl'}>
<Modal.Header closeButton={true}>
<Modal.Title className={'h6'}>
<ForkAwesomeIcon icon={'picture-o'} />
&nbsp;
<span>{alt ?? title ?? ''}</span>
</Modal.Title>
</Modal.Header>
showCloseButton={true}
additionalClasses={'lightbox'}
title={alt ?? title ?? ''}
titleIsI18nKey={false}>
<ProxyImageFrame alt={alt} src={src} title={title} className={'w-100 cursor-zoom-out'} onClick={onHide} />
</Modal>
</CommonModal>
)
}

View file

@ -168,7 +168,7 @@ export const ProfileAccessTokens: React.FC = () => {
<CommonModal
show={showAddedModal}
onHide={() => setShowAddedModal(false)}
titleI18nKey='profile.modal.addedAccessToken.title'
title='profile.modal.addedAccessToken.title'
{...cypressId('access-token-modal-add')}>
<Modal.Body>
<Trans i18nKey='profile.modal.addedAccessToken.message' />
@ -185,7 +185,7 @@ export const ProfileAccessTokens: React.FC = () => {
<CommonModal
show={showDeleteModal}
onHide={() => setShowDeleteModal(false)}
titleI18nKey={'profile.modal.deleteAccessToken.title'}
title={'profile.modal.deleteAccessToken.title'}
{...cypressId('access-token-modal-delete')}>
<Modal.Body>
<Trans i18nKey='profile.modal.deleteAccessToken.message' />