mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-15 06:07:03 +00:00
Merge pull request #7956 from overleaf/ii-refactor-toolitp-usage
Tooltip usage refactoring GitOrigin-RevId: f4b2d4d57722172141a081dd60e4394ff7fff332
This commit is contained in:
parent
835a11df1e
commit
5731463d32
20 changed files with 253 additions and 276 deletions
|
@ -1,18 +1,15 @@
|
|||
import Icon from '../../../shared/components/icon'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
|
||||
function BackToProjectsButton() {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="right"
|
||||
overlay={
|
||||
<Tooltip id="back-to-projects-tooltip">
|
||||
{t('back_to_your_projects')}
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id="back-to-projects"
|
||||
description={t('back_to_your_projects')}
|
||||
overlayProps={{ placement: 'right' }}
|
||||
>
|
||||
<div className="toolbar-item">
|
||||
<a className="btn btn-full-height" href="/project">
|
||||
|
@ -23,7 +20,7 @@ function BackToProjectsButton() {
|
|||
/>
|
||||
</a>
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import { useCallback } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Dropdown, MenuItem, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import { Dropdown, MenuItem } from 'react-bootstrap'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import IconChecked from '../../../shared/components/icon-checked'
|
||||
import ControlledDropdown from '../../../shared/components/controlled-dropdown'
|
||||
|
@ -50,21 +51,19 @@ function PdfDetachMenuItem({ handleDetach, children }) {
|
|||
|
||||
if (!('BroadcastChannel' in window)) {
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="left"
|
||||
overlay={
|
||||
<Tooltip id="detach-disabled-tooltip">
|
||||
{t('your_browser_does_not_support_this_feature')}
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id="detach-disabled"
|
||||
description={t('your_browser_does_not_support_this_feature')}
|
||||
overlayProps={{ placement: 'left' }}
|
||||
>
|
||||
<MenuItem disabled>{children}</MenuItem>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
return <MenuItem onSelect={handleDetach}>{children}</MenuItem>
|
||||
}
|
||||
|
||||
PdfDetachMenuItem.propTypes = {
|
||||
handleDetach: PropTypes.func.isRequired,
|
||||
children: PropTypes.arrayOf(PropTypes.node).isRequired,
|
||||
|
@ -126,13 +125,13 @@ function LayoutDropdownButton() {
|
|||
<Dropdown.Toggle className="btn-full-height" bsStyle="link">
|
||||
{processing ? <IconRefresh /> : <IconLayout />}
|
||||
<span className="toolbar-label">{t('layout')}</span>
|
||||
<OverlayTrigger
|
||||
placement="bottom"
|
||||
overlay={<Tooltip id="pdf-detach-badge">Beta feature</Tooltip>}
|
||||
delayHide={100}
|
||||
<Tooltip
|
||||
id="pdf-detach-badge"
|
||||
description="Beta feature"
|
||||
overlayProps={{ placement: 'bottom', delayHide: 100 }}
|
||||
>
|
||||
<span className="beta-badge" />
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu id="layout-dropdown-list">
|
||||
<MenuItem onSelect={() => handleChangeLayout('sideBySide')}>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Dropdown, MenuItem, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import { Dropdown, MenuItem } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { getHueForUserId } from '../../../shared/utils/colors'
|
||||
import ControlledDropdown from '../../../shared/components/controlled-dropdown'
|
||||
|
@ -37,17 +38,17 @@ function OnlineUsersWidget({ onlineUsers, goToUser }) {
|
|||
return (
|
||||
<div className="online-users">
|
||||
{onlineUsers.map((user, index) => (
|
||||
<OverlayTrigger
|
||||
<Tooltip
|
||||
key={`${user.user_id}_${index}`}
|
||||
placement="bottom"
|
||||
trigger={['hover', 'focus']}
|
||||
overlay={<Tooltip id="tooltip-online-user">{user.name}</Tooltip>}
|
||||
id="online-user"
|
||||
description={user.name}
|
||||
overlayProps={{ placement: 'bottom', trigger: ['hover', 'focus'] }}
|
||||
>
|
||||
<span>
|
||||
{/* OverlayTrigger won't fire unless UserIcon is wrapped in a span */}
|
||||
<UserIcon user={user} onClick={goToUser} />
|
||||
</span>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
@ -94,11 +95,10 @@ UserIcon.propTypes = {
|
|||
const DropDownToggleButton = React.forwardRef((props, ref) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="left"
|
||||
overlay={
|
||||
<Tooltip id="tooltip-connected-users">{t('connected_users')}</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id="connected-users"
|
||||
description={t('connected_users')}
|
||||
overlayProps={{ placement: 'left' }}
|
||||
>
|
||||
<button
|
||||
className="btn online-user online-user-multi"
|
||||
|
@ -107,7 +107,7 @@ const DropDownToggleButton = React.forwardRef((props, ref) => {
|
|||
<strong>{props.onlineUserCount}</strong>
|
||||
<Icon type="users" fw />
|
||||
</button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import classNames from 'classnames'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
|
||||
function PdfToggleButton({ onClick, pdfViewIsOpen }) {
|
||||
type PdfToggleButtonProps = {
|
||||
onClick: () => void
|
||||
pdfViewIsOpen?: boolean
|
||||
}
|
||||
|
||||
function PdfToggleButton({ onClick, pdfViewIsOpen }: PdfToggleButtonProps) {
|
||||
const classes = classNames(
|
||||
'btn',
|
||||
'btn-full-height',
|
||||
|
@ -14,22 +18,17 @@ function PdfToggleButton({ onClick, pdfViewIsOpen }) {
|
|||
)
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="bottom"
|
||||
trigger={['hover', 'focus']}
|
||||
overlay={<Tooltip id="tooltip-online-user">PDF</Tooltip>}
|
||||
<Tooltip
|
||||
id="online-user"
|
||||
description="PDF"
|
||||
overlayProps={{ placement: 'bottom', trigger: ['hover', 'focus'] }}
|
||||
>
|
||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid,jsx-a11y/click-events-have-key-events,jsx-a11y/interactive-supports-focus */}
|
||||
<a role="button" className={classes} onClick={onClick}>
|
||||
<Icon type="file-pdf-o" fw accessibilityLabel="PDF" />
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
PdfToggleButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
pdfViewIsOpen: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default PdfToggleButton
|
|
@ -1,16 +1,22 @@
|
|||
import { useEffect, useState, useRef } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import classNames from 'classnames'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
|
||||
type ProjectNameEditableLabelProps = {
|
||||
projectName: string
|
||||
onChange: (value: string) => void
|
||||
hasRenamePermissions?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
function ProjectNameEditableLabel({
|
||||
projectName,
|
||||
hasRenamePermissions,
|
||||
onChange,
|
||||
className,
|
||||
}) {
|
||||
}: ProjectNameEditableLabelProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [isRenaming, setIsRenaming] = useState(false)
|
||||
|
@ -19,11 +25,11 @@ function ProjectNameEditableLabel({
|
|||
|
||||
const [inputContent, setInputContent] = useState(projectName)
|
||||
|
||||
const inputRef = useRef(null)
|
||||
const inputRef = useRef<HTMLInputElement | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (isRenaming) {
|
||||
inputRef.current.select()
|
||||
inputRef.current?.select()
|
||||
}
|
||||
}, [isRenaming])
|
||||
|
||||
|
@ -39,14 +45,14 @@ function ProjectNameEditableLabel({
|
|||
onChange(inputContent)
|
||||
}
|
||||
|
||||
function handleKeyDown(event) {
|
||||
function handleKeyDown(event: React.KeyboardEvent) {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault()
|
||||
finishRenaming()
|
||||
}
|
||||
}
|
||||
|
||||
function handleOnChange(event) {
|
||||
function handleOnChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
setInputContent(event.target.value)
|
||||
}
|
||||
|
||||
|
@ -75,26 +81,19 @@ function ProjectNameEditableLabel({
|
|||
/>
|
||||
)}
|
||||
{canRename && (
|
||||
<OverlayTrigger
|
||||
placement="bottom"
|
||||
trigger={['hover', 'focus']}
|
||||
overlay={<Tooltip id="tooltip-online-user">{t('rename')}</Tooltip>}
|
||||
<Tooltip
|
||||
id="online-user"
|
||||
description={t('rename')}
|
||||
overlayProps={{ placement: 'bottom', trigger: ['hover', 'focus'] }}
|
||||
>
|
||||
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid, jsx-a11y/click-events-have-key-events, jsx-a11y/interactive-supports-focus */}
|
||||
<a className="rename" role="button" onClick={startRenaming}>
|
||||
<Icon type="pencil" fw />
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ProjectNameEditableLabel.propTypes = {
|
||||
projectName: PropTypes.string.isRequired,
|
||||
hasRenamePermissions: PropTypes.bool,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
className: PropTypes.string,
|
||||
}
|
||||
|
||||
export default ProjectNameEditableLabel
|
|
@ -1,8 +1,9 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { Button } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import TooltipButton from '../../../shared/components/tooltip-button'
|
||||
|
||||
import { useEditorContext } from '../../../shared/context/editor-context'
|
||||
import { useFileTreeActionable } from '../contexts/file-tree-actionable'
|
||||
|
@ -37,27 +38,33 @@ function FileTreeToolbarLeft() {
|
|||
|
||||
return (
|
||||
<div className="toolbar-left">
|
||||
<TooltipButton
|
||||
id="new_file"
|
||||
<Tooltip
|
||||
id="new-file"
|
||||
description={t('new_file')}
|
||||
onClick={startCreatingDocOrFile}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<Icon type="file" fw accessibilityLabel={t('new_file')} />
|
||||
</TooltipButton>
|
||||
<TooltipButton
|
||||
id="new_folder"
|
||||
<Button onClick={startCreatingDocOrFile}>
|
||||
<Icon type="file" fw accessibilityLabel={t('new_file')} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
id="new-folder"
|
||||
description={t('new_folder')}
|
||||
onClick={startCreatingFolder}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<Icon type="folder" fw accessibilityLabel={t('new_folder')} />
|
||||
</TooltipButton>
|
||||
<TooltipButton
|
||||
<Button onClick={startCreatingFolder}>
|
||||
<Icon type="folder" fw accessibilityLabel={t('new_folder')} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
id="upload"
|
||||
description={t('upload')}
|
||||
onClick={startUploadingDocOrFile}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<Icon type="upload" fw accessibilityLabel={t('upload')} />
|
||||
</TooltipButton>
|
||||
<Button onClick={startUploadingDocOrFile}>
|
||||
<Icon type="upload" fw accessibilityLabel={t('upload')} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -74,22 +81,26 @@ function FileTreeToolbarRight() {
|
|||
return (
|
||||
<div className="toolbar-right">
|
||||
{canRename ? (
|
||||
<TooltipButton
|
||||
<Tooltip
|
||||
id="rename"
|
||||
description={t('rename')}
|
||||
onClick={startRenaming}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<Icon type="pencil" fw accessibilityLabel={t('rename')} />
|
||||
</TooltipButton>
|
||||
<Button onClick={startRenaming}>
|
||||
<Icon type="pencil" fw accessibilityLabel={t('rename')} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{canDelete ? (
|
||||
<TooltipButton
|
||||
<Tooltip
|
||||
id="delete"
|
||||
description={t('delete')}
|
||||
onClick={startDeleting}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<Icon type="trash-o" fw accessibilityLabel={t('delete')} />
|
||||
</TooltipButton>
|
||||
<Button onClick={startDeleting}>
|
||||
<Icon type="trash-o" fw accessibilityLabel={t('delete')} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -1,26 +1,35 @@
|
|||
import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { memo } from 'react'
|
||||
|
||||
const modifierKey = /Mac/i.test(navigator.platform) ? 'Cmd' : 'Ctrl'
|
||||
|
||||
function PdfCompileButtonInner({ startCompile, compiling }) {
|
||||
type PdfCompileButtonInnerProps = {
|
||||
startCompile: () => void
|
||||
compiling: boolean
|
||||
}
|
||||
|
||||
function PdfCompileButtonInner({
|
||||
startCompile,
|
||||
compiling,
|
||||
}: PdfCompileButtonInnerProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const compileButtonLabel = compiling ? t('compiling') + '…' : t('recompile')
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="bottom"
|
||||
delayShow={500}
|
||||
overlay={
|
||||
<Tooltip id="tooltip-logs-toggle" className="keyboard-tooltip">
|
||||
<Tooltip
|
||||
id="logs-toggle"
|
||||
description={
|
||||
<>
|
||||
{t('recompile_pdf')}{' '}
|
||||
<span className="keyboard-shortcut">({modifierKey} + Enter)</span>
|
||||
</Tooltip>
|
||||
</>
|
||||
}
|
||||
tooltipProps={{ className: 'keyboard-tooltip' }}
|
||||
overlayProps={{ delayShow: 500 }}
|
||||
>
|
||||
<Button
|
||||
className="btn-recompile"
|
||||
|
@ -34,13 +43,8 @@ function PdfCompileButtonInner({ startCompile, compiling }) {
|
|||
{compileButtonLabel}
|
||||
</span>
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
PdfCompileButtonInner.propTypes = {
|
||||
compiling: PropTypes.bool.isRequired,
|
||||
startCompile: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default memo(PdfCompileButtonInner)
|
|
@ -1,7 +1,8 @@
|
|||
import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { memo, useMemo } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import { useLayoutContext } from '../../../shared/context/layout-context'
|
||||
|
||||
function PdfExpandButton() {
|
||||
|
@ -14,9 +15,10 @@ function PdfExpandButton() {
|
|||
}, [pdfLayout, t])
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="left"
|
||||
overlay={<Tooltip id="expand-pdf-btn">{text}</Tooltip>}
|
||||
<Tooltip
|
||||
id="expand-pdf-btn"
|
||||
description="text"
|
||||
overlayProps={{ placement: 'left' }}
|
||||
>
|
||||
<Button
|
||||
onClick={switchLayout}
|
||||
|
@ -25,8 +27,8 @@ function PdfExpandButton() {
|
|||
>
|
||||
<Icon type={pdfLayout === 'sideBySide' ? 'expand' : 'compress'} />
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(PdfExpandButton)
|
||||
export default PdfExpandButton
|
|
@ -1,25 +1,19 @@
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { memo } from 'react'
|
||||
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
|
||||
|
||||
function PdfHybridDownloadButton() {
|
||||
const { pdfDownloadUrl } = useCompileContext()
|
||||
|
||||
const { t } = useTranslation()
|
||||
const description = pdfDownloadUrl
|
||||
? t('download_pdf')
|
||||
: t('please_compile_pdf_before_download')
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="bottom"
|
||||
overlay={
|
||||
<Tooltip id="tooltip-logs-toggle">
|
||||
{pdfDownloadUrl
|
||||
? t('download_pdf')
|
||||
: t('please_compile_pdf_before_download')}
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<Tooltip id="logs-toggle" description={description}>
|
||||
<Button
|
||||
bsStyle="link"
|
||||
disabled={!pdfDownloadUrl}
|
||||
|
@ -30,8 +24,8 @@ function PdfHybridDownloadButton() {
|
|||
>
|
||||
<Icon type="download" fw />
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(PdfHybridDownloadButton)
|
||||
export default PdfHybridDownloadButton
|
|
@ -1,6 +1,7 @@
|
|||
import { memo, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button, Label, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import { Button, Label } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
|
||||
|
||||
|
@ -18,11 +19,10 @@ function PdfHybridLogsButton() {
|
|||
const totalCount = errorCount + warningCount
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="bottom"
|
||||
overlay={
|
||||
<Tooltip id="tooltip-logs-toggle">{t('logs_and_output_files')}</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id="logs-toggle"
|
||||
description={t('logs_and_output_files')}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<Button
|
||||
bsStyle="link"
|
||||
|
@ -41,7 +41,7 @@ function PdfHybridLogsButton() {
|
|||
</Label>
|
||||
)}
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
|
@ -7,7 +7,8 @@ import { getJSON } from '../../../infrastructure/fetch-json'
|
|||
import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
|
||||
import { useLayoutContext } from '../../../shared/context/layout-context'
|
||||
import useScopeValue from '../../../shared/hooks/use-scope-value'
|
||||
import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useIsMounted from '../../../shared/hooks/use-is-mounted'
|
||||
|
@ -38,13 +39,10 @@ function GoToCodeButton({
|
|||
}
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement={tooltipPlacement}
|
||||
overlay={
|
||||
<Tooltip id="sync-to-code-tooltip">
|
||||
{t('go_to_pdf_location_in_code')}
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id="sync-to-code"
|
||||
description={t('go_to_pdf_location_in_code')}
|
||||
overlayProps={{ placement: tooltipPlacement }}
|
||||
>
|
||||
<Button
|
||||
bsStyle="default"
|
||||
|
@ -57,7 +55,7 @@ function GoToCodeButton({
|
|||
{buttonIcon}
|
||||
{isDetachLayout ? <span> {t('show_in_code')}</span> : ''}
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -82,13 +80,10 @@ function GoToPdfButton({
|
|||
}
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement={tooltipPlacement}
|
||||
overlay={
|
||||
<Tooltip id="sync-to-pdf-tooltip">
|
||||
{t('go_to_code_location_in_pdf')}
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id="sync-to-pdf"
|
||||
description={t('go_to_code_location_in_pdf')}
|
||||
overlayProps={{ placement: tooltipPlacement }}
|
||||
>
|
||||
<Button
|
||||
bsStyle="default"
|
||||
|
@ -101,7 +96,7 @@ function GoToPdfButton({
|
|||
{buttonIcon}
|
||||
{isDetachLayout ? <span> {t('show_in_pdf')}</span> : ''}
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ import PropTypes from 'prop-types'
|
|||
import classNames from 'classnames'
|
||||
import { useState, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import useResizeObserver from '../hooks/use-resize-observer'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
|
||||
function PreviewLogEntryHeader({
|
||||
|
@ -84,13 +84,6 @@ function PreviewLogEntryHeader({
|
|||
</button>
|
||||
) : null
|
||||
|
||||
const locationTooltip =
|
||||
locationSpanOverflown && locationLinkText ? (
|
||||
<Tooltip id={locationLinkText} className="log-location-tooltip">
|
||||
{locationLinkText}
|
||||
</Tooltip>
|
||||
) : null
|
||||
|
||||
const headerTitleText = logType ? `${logType} ${headerTitle}` : headerTitle
|
||||
|
||||
return (
|
||||
|
@ -99,10 +92,15 @@ function PreviewLogEntryHeader({
|
|||
<div className="log-entry-header-icon-container">{headerIcon}</div>
|
||||
) : null}
|
||||
<h3 className="log-entry-header-title">{headerTitleText}</h3>
|
||||
{locationTooltip ? (
|
||||
<OverlayTrigger placement="left" overlay={locationTooltip}>
|
||||
{locationSpanOverflown && locationLinkText ? (
|
||||
<Tooltip
|
||||
id={locationLinkText}
|
||||
description={locationLinkText}
|
||||
overlayProps={{ placement: 'left' }}
|
||||
tooltipProps={{ className: 'log-location-tooltip' }}
|
||||
>
|
||||
{locationLink}
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
) : (
|
||||
locationLink
|
||||
)}
|
||||
|
|
|
@ -2,18 +2,11 @@ import { useState, useEffect } from 'react'
|
|||
import PropTypes from 'prop-types'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useShareProjectContext } from './share-project-modal'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import TransferOwnershipModal from './transfer-ownership-modal'
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Form,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
OverlayTrigger,
|
||||
Tooltip,
|
||||
} from 'react-bootstrap'
|
||||
import { removeMemberFromProject, updateMember } from '../utils/api'
|
||||
import { Button, Col, Form, FormControl, FormGroup } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { useProjectContext } from '../../../shared/context/project-context'
|
||||
|
||||
export default function EditMember({ member }) {
|
||||
|
@ -110,6 +103,7 @@ function SelectPrivilege({ value, handleChange }) {
|
|||
</FormControl>
|
||||
)
|
||||
}
|
||||
|
||||
SelectPrivilege.propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
handleChange: PropTypes.func.isRequired,
|
||||
|
@ -134,13 +128,10 @@ function RemoveMemberAction({ member }) {
|
|||
|
||||
return (
|
||||
<FormControl.Static className="text-center">
|
||||
<OverlayTrigger
|
||||
placement="bottom"
|
||||
overlay={
|
||||
<Tooltip id="tooltip-remove-collaborator">
|
||||
<Trans i18nKey="remove_collaborator" />
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id="remove-collaborator"
|
||||
description={<Trans i18nKey="remove_collaborator" />}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<Button
|
||||
type="button"
|
||||
|
@ -151,10 +142,11 @@ function RemoveMemberAction({ member }) {
|
|||
>
|
||||
<Icon type="times" />
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
</FormControl.Static>
|
||||
)
|
||||
}
|
||||
|
||||
RemoveMemberAction.propTypes = {
|
||||
member: PropTypes.shape({
|
||||
_id: PropTypes.string.isRequired,
|
||||
|
@ -179,6 +171,7 @@ function ChangePrivilegesActions({ handleReset }) {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
ChangePrivilegesActions.propTypes = {
|
||||
handleReset: PropTypes.func.isRequired,
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ import { useCallback } from 'react'
|
|||
import PropTypes from 'prop-types'
|
||||
import { useShareProjectContext } from './share-project-modal'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { Button, Col, Row, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import { Button, Col, Row } from 'react-bootstrap'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import MemberPrivileges from './member-privileges'
|
||||
import { resendInvite, revokeInvite } from '../utils/api'
|
||||
|
@ -68,6 +69,7 @@ function ResendInvite({ invite }) {
|
|||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
ResendInvite.propTypes = {
|
||||
invite: PropTypes.object.isRequired,
|
||||
}
|
||||
|
@ -88,13 +90,10 @@ function RevokeInvite({ invite }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="bottom"
|
||||
overlay={
|
||||
<Tooltip id="tooltip-revoke-invite">
|
||||
<Trans i18nKey="revoke_invite" />
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id="revoke-invite"
|
||||
description={<Trans i18nKey="revoke_invite" />}
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
>
|
||||
<Button
|
||||
type="button"
|
||||
|
@ -105,9 +104,10 @@ function RevokeInvite({ invite }) {
|
|||
>
|
||||
<Icon type="times" />
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
RevokeInvite.propTypes = {
|
||||
invite: PropTypes.object.isRequired,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { useCallback, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Button, Col, OverlayTrigger, Row, Tooltip } from 'react-bootstrap'
|
||||
import { Button, Col, Row } from 'react-bootstrap'
|
||||
import { Trans } from 'react-i18next'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import { useShareProjectContext } from './share-project-modal'
|
||||
import { setProjectAccessLevel } from '../utils/api'
|
||||
|
@ -93,6 +94,7 @@ function PrivateSharing({ setAccessLevel, inflight }) {
|
|||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
PrivateSharing.propTypes = {
|
||||
setAccessLevel: PropTypes.func.isRequired,
|
||||
inflight: PropTypes.bool,
|
||||
|
@ -144,6 +146,7 @@ function TokenBasedSharing({ setAccessLevel, inflight }) {
|
|||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
TokenBasedSharing.propTypes = {
|
||||
setAccessLevel: PropTypes.func.isRequired,
|
||||
inflight: PropTypes.bool,
|
||||
|
@ -177,6 +180,7 @@ function LegacySharing({ accessLevel, setAccessLevel, inflight }) {
|
|||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
LegacySharing.propTypes = {
|
||||
accessLevel: PropTypes.string.isRequired,
|
||||
setAccessLevel: PropTypes.func.isRequired,
|
||||
|
@ -230,6 +234,7 @@ function AccessToken({ token, path, tooltipId }) {
|
|||
</pre>
|
||||
)
|
||||
}
|
||||
|
||||
AccessToken.propTypes = {
|
||||
token: PropTypes.string,
|
||||
tooltipId: PropTypes.string.isRequired,
|
||||
|
@ -238,13 +243,9 @@ AccessToken.propTypes = {
|
|||
|
||||
function LinkSharingInfo() {
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="top"
|
||||
overlay={
|
||||
<Tooltip id="tooltip-link-sharing-info">
|
||||
<Trans i18nKey="learn_more_about_link_sharing" />
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id="link-sharing-info"
|
||||
description={<Trans i18nKey="learn_more_about_link_sharing" />}
|
||||
>
|
||||
<a
|
||||
href="/learn/how-to/What_is_Link_Sharing%3F"
|
||||
|
@ -253,6 +254,6 @@ function LinkSharingInfo() {
|
|||
>
|
||||
<Icon type="question-circle" />
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
export default function BetaBadge({ tooltip, url = '/beta/participate' }) {
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement={tooltip.placement || 'bottom'}
|
||||
overlay={
|
||||
<Tooltip id={tooltip.id} className={tooltip.className}>
|
||||
{tooltip.text}
|
||||
</Tooltip>
|
||||
}
|
||||
delayHide={100}
|
||||
>
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="badge beta-badge"
|
||||
>
|
||||
<span className="sr-only">{tooltip.text}</span>
|
||||
</a>
|
||||
</OverlayTrigger>
|
||||
)
|
||||
}
|
||||
|
||||
BetaBadge.propTypes = {
|
||||
tooltip: PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
text: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
|
||||
placement: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
}),
|
||||
url: PropTypes.string,
|
||||
}
|
39
services/web/frontend/js/shared/components/beta-badge.tsx
Normal file
39
services/web/frontend/js/shared/components/beta-badge.tsx
Normal file
|
@ -0,0 +1,39 @@
|
|||
import Tooltip from './tooltip'
|
||||
import { OverlayTriggerProps } from 'react-bootstrap'
|
||||
|
||||
type TooltipProps = {
|
||||
id: string
|
||||
text: React.ReactNode
|
||||
placement?: OverlayTriggerProps['placement']
|
||||
className?: string
|
||||
}
|
||||
|
||||
type BetaBadgeProps = {
|
||||
tooltip: TooltipProps
|
||||
url?: string
|
||||
}
|
||||
|
||||
function BetaBadge({ tooltip, url = '/beta/participate' }: BetaBadgeProps) {
|
||||
return (
|
||||
<Tooltip
|
||||
id={tooltip.id}
|
||||
description={tooltip.text}
|
||||
tooltipProps={{ className: tooltip.className }}
|
||||
overlayProps={{
|
||||
placement: tooltip.placement || 'bottom',
|
||||
delayHide: 100,
|
||||
}}
|
||||
>
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="badge beta-badge"
|
||||
>
|
||||
<span className="sr-only">{tooltip.text}</span>
|
||||
</a>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export default BetaBadge
|
|
@ -1,10 +1,15 @@
|
|||
import { useCallback, useState } from 'react'
|
||||
import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import Tooltip from './tooltip'
|
||||
import Icon from './icon'
|
||||
|
||||
export default function CopyLink({ link, tooltipId }) {
|
||||
type CopyLinkProps = {
|
||||
link: string
|
||||
tooltipId: string
|
||||
}
|
||||
|
||||
function CopyLink({ link, tooltipId }: CopyLinkProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
@ -23,15 +28,13 @@ export default function CopyLink({ link, tooltipId }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
placement="top"
|
||||
delayHide={copied ? 1000 : 250}
|
||||
shouldUpdatePosition
|
||||
overlay={
|
||||
<Tooltip id={tooltipId}>
|
||||
{copied ? 'Copied!' : <Trans i18nKey="copy" />}
|
||||
</Tooltip>
|
||||
}
|
||||
<Tooltip
|
||||
id={tooltipId}
|
||||
description={copied ? 'Copied!' : <Trans i18nKey="copy" />}
|
||||
overlayProps={{
|
||||
delayHide: copied ? 1000 : 250,
|
||||
shouldUpdatePosition: true,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
|
@ -42,10 +45,8 @@ export default function CopyLink({ link, tooltipId }) {
|
|||
>
|
||||
{copied ? <Icon type="check" /> : <Icon type="clipboard" />}
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
CopyLink.propTypes = {
|
||||
link: PropTypes.string.isRequired,
|
||||
tooltipId: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
export default CopyLink
|
|
@ -1,24 +0,0 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import { Button, Tooltip, OverlayTrigger } from 'react-bootstrap'
|
||||
|
||||
function TooltipButton({ id, description, onClick, children }) {
|
||||
const tooltip = <Tooltip id={`${id}_tooltip`}>{description}</Tooltip>
|
||||
|
||||
return (
|
||||
<OverlayTrigger placement="bottom" overlay={tooltip}>
|
||||
<Button onClick={onClick}>{children}</Button>
|
||||
</OverlayTrigger>
|
||||
)
|
||||
}
|
||||
|
||||
TooltipButton.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
onClick: PropTypes.func,
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node,
|
||||
]),
|
||||
}
|
||||
|
||||
export default TooltipButton
|
|
@ -4,11 +4,15 @@ import {
|
|||
Tooltip as BSTooltip,
|
||||
} from 'react-bootstrap'
|
||||
|
||||
type OverlayTriggerCustomProps = {
|
||||
shouldUpdatePosition?: boolean // Not officially documented https://stackoverflow.com/a/43138470
|
||||
} & OverlayTriggerProps
|
||||
|
||||
type TooltipProps = {
|
||||
children: React.ReactNode
|
||||
description: string
|
||||
description: React.ReactNode
|
||||
id: string
|
||||
overlayProps?: Omit<OverlayTriggerProps, 'overlay'>
|
||||
overlayProps?: Omit<OverlayTriggerCustomProps, 'overlay'>
|
||||
tooltipProps?: BSTooltip.TooltipProps
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue