mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #21240 from overleaf/ii-bs5-review-panel-old
[web] BS5 review panel old GitOrigin-RevId: da018b8f2946afb21ab63da0003453e20781f04c
This commit is contained in:
parent
92a23b7e9d
commit
5c3d9117c5
25 changed files with 1594 additions and 430 deletions
|
@ -16,6 +16,8 @@ import useScopeEventListener from '@/shared/hooks/use-scope-event-listener'
|
||||||
import { memo, useCallback } from 'react'
|
import { memo, useCallback } from 'react'
|
||||||
import { useLayoutContext } from '@/shared/context/layout-context'
|
import { useLayoutContext } from '@/shared/context/layout-context'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
|
||||||
function EditorWidgets() {
|
function EditorWidgets() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -71,10 +73,20 @@ function EditorWidgets() {
|
||||||
{nChanges > 1 && permissions.write && (
|
{nChanges > 1 && permissions.write && (
|
||||||
<>
|
<>
|
||||||
<BulkActions.Button onClick={handleShowBulkAcceptDialog}>
|
<BulkActions.Button onClick={handleShowBulkAcceptDialog}>
|
||||||
<Icon type="check" /> {t('accept_all')} ({nChanges})
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="check" />}
|
||||||
|
bs5={<MaterialIcon type="check" />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{t('accept_all')} ({nChanges})
|
||||||
</BulkActions.Button>
|
</BulkActions.Button>
|
||||||
<BulkActions.Button onClick={handleShowBulkRejectDialog}>
|
<BulkActions.Button onClick={handleShowBulkRejectDialog}>
|
||||||
<Icon type="times" /> {t('reject_all')} ({nChanges})
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="times" />}
|
||||||
|
bs5={<MaterialIcon type="close" />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{t('reject_all')} ({nChanges})
|
||||||
</BulkActions.Button>
|
</BulkActions.Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -83,7 +95,12 @@ function EditorWidgets() {
|
||||||
!isRestrictedTokenMember &&
|
!isRestrictedTokenMember &&
|
||||||
currentDocEntries?.['add-comment'] && (
|
currentDocEntries?.['add-comment'] && (
|
||||||
<AddCommentButton onClick={handleAddNewCommentClick}>
|
<AddCommentButton onClick={handleAddNewCommentClick}>
|
||||||
<Icon type="comment" /> {t('add_comment')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="comment" />}
|
||||||
|
bs5={<MaterialIcon type="mode_comment" />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{t('add_comment')}
|
||||||
</AddCommentButton>
|
</AddCommentButton>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,6 +11,9 @@ import {
|
||||||
useReviewPanelValueContext,
|
useReviewPanelValueContext,
|
||||||
} from '../../../context/review-panel/review-panel-context'
|
} from '../../../context/review-panel/review-panel-context'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import LoadingSpinner from '@/shared/components/loading-spinner'
|
||||||
|
|
||||||
function AddCommentEntry() {
|
function AddCommentEntry() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -116,9 +119,7 @@ function AddCommentEntry() {
|
||||||
<>
|
<>
|
||||||
<div className="rp-new-comment">
|
<div className="rp-new-comment">
|
||||||
{isSubmitting ? (
|
{isSubmitting ? (
|
||||||
<div className="rp-loading">
|
<LoadingSpinner className="d-flex justify-content-center" />
|
||||||
<Icon type="spinner" spin />
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<AutoExpandingTextArea
|
<AutoExpandingTextArea
|
||||||
className="rp-comment-input"
|
className="rp-comment-input"
|
||||||
|
@ -137,19 +138,34 @@ function AddCommentEntry() {
|
||||||
className="rp-entry-button-cancel"
|
className="rp-entry-button-cancel"
|
||||||
onClick={handleCancelNewComment}
|
onClick={handleCancelNewComment}
|
||||||
>
|
>
|
||||||
<Icon type="times" /> {t('cancel')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="times" />}
|
||||||
|
bs5={<MaterialIcon type="close" />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{t('cancel')}
|
||||||
</EntryActions.Button>
|
</EntryActions.Button>
|
||||||
<EntryActions.Button
|
<EntryActions.Button
|
||||||
onClick={handleSubmitNewComment}
|
onClick={handleSubmitNewComment}
|
||||||
disabled={isSubmitting || !content.length}
|
disabled={isSubmitting || !content.length}
|
||||||
>
|
>
|
||||||
<Icon type="comment" /> {t('comment')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="comment" />}
|
||||||
|
bs5={<MaterialIcon type="mode_comment" />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{t('comment')}
|
||||||
</EntryActions.Button>
|
</EntryActions.Button>
|
||||||
</EntryActions>
|
</EntryActions>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<AddCommentButton onClick={handleStartNewComment}>
|
<AddCommentButton onClick={handleStartNewComment}>
|
||||||
<Icon type="comment" /> {t('add_comment')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="comment" />}
|
||||||
|
bs5={<MaterialIcon type="mode_comment" />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{t('add_comment')}
|
||||||
</AddCommentButton>
|
</AddCommentButton>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,6 +12,8 @@ import { BaseChangeEntryProps } from '../types/base-change-entry-props'
|
||||||
import useIndicatorHover from '../hooks/use-indicator-hover'
|
import useIndicatorHover from '../hooks/use-indicator-hover'
|
||||||
import EntryIndicator from './entry-indicator'
|
import EntryIndicator from './entry-indicator'
|
||||||
import { useEntryClick } from '@/features/source-editor/components/review-panel/hooks/use-entry-click'
|
import { useEntryClick } from '@/features/source-editor/components/review-panel/hooks/use-entry-click'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
|
||||||
interface AggregateChangeEntryProps extends BaseChangeEntryProps {
|
interface AggregateChangeEntryProps extends BaseChangeEntryProps {
|
||||||
replacedContent: string
|
replacedContent: string
|
||||||
|
@ -80,7 +82,10 @@ function AggregateChangeEntry({
|
||||||
onMouseEnter={handleIndicatorMouseEnter}
|
onMouseEnter={handleIndicatorMouseEnter}
|
||||||
onClick={handleIndicatorClick}
|
onClick={handleIndicatorClick}
|
||||||
>
|
>
|
||||||
<Icon type="pencil" />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="pencil" />}
|
||||||
|
bs5={<MaterialIcon type="edit" />}
|
||||||
|
/>
|
||||||
</EntryIndicator>
|
</EntryIndicator>
|
||||||
<div
|
<div
|
||||||
className={classnames('rp-entry', 'rp-entry-aggregate', {
|
className={classnames('rp-entry', 'rp-entry-aggregate', {
|
||||||
|
@ -89,7 +94,10 @@ function AggregateChangeEntry({
|
||||||
>
|
>
|
||||||
<div className="rp-entry-body">
|
<div className="rp-entry-body">
|
||||||
<div className="rp-entry-action-icon">
|
<div className="rp-entry-action-icon">
|
||||||
<Icon type="pencil" />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="pencil" />}
|
||||||
|
bs5={<MaterialIcon type="edit" />}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="rp-entry-details">
|
<div className="rp-entry-details">
|
||||||
<div className="rp-entry-description">
|
<div className="rp-entry-description">
|
||||||
|
@ -97,7 +105,7 @@ function AggregateChangeEntry({
|
||||||
<del className="rp-content-highlight">{deletionContent}</del>
|
<del className="rp-content-highlight">{deletionContent}</del>
|
||||||
{deletionNeedsCollapsing && (
|
{deletionNeedsCollapsing && (
|
||||||
<button
|
<button
|
||||||
className="rp-collapse-toggle btn-inline-link"
|
className="rp-collapse-toggle"
|
||||||
onClick={handleDeletionToggleCollapse}
|
onClick={handleDeletionToggleCollapse}
|
||||||
>
|
>
|
||||||
{isDeletionCollapsed
|
{isDeletionCollapsed
|
||||||
|
@ -109,7 +117,7 @@ function AggregateChangeEntry({
|
||||||
<ins className="rp-content-highlight">{insertionContent}</ins>
|
<ins className="rp-content-highlight">{insertionContent}</ins>
|
||||||
{insertionNeedsCollapsing && (
|
{insertionNeedsCollapsing && (
|
||||||
<button
|
<button
|
||||||
className="rp-collapse-toggle btn-inline-link"
|
className="rp-collapse-toggle"
|
||||||
onClick={handleInsertionToggleCollapse}
|
onClick={handleInsertionToggleCollapse}
|
||||||
>
|
>
|
||||||
{isInsertionCollapsed
|
{isInsertionCollapsed
|
||||||
|
@ -139,10 +147,18 @@ function AggregateChangeEntry({
|
||||||
{permissions.write && (
|
{permissions.write && (
|
||||||
<EntryActions>
|
<EntryActions>
|
||||||
<EntryActions.Button onClick={() => rejectChanges(entryIds)}>
|
<EntryActions.Button onClick={() => rejectChanges(entryIds)}>
|
||||||
<Icon type="times" /> {t('reject')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="times" />}
|
||||||
|
bs5={<MaterialIcon type="close" />}
|
||||||
|
/>
|
||||||
|
{t('reject')}
|
||||||
</EntryActions.Button>
|
</EntryActions.Button>
|
||||||
<EntryActions.Button onClick={() => acceptChanges(entryIds)}>
|
<EntryActions.Button onClick={() => acceptChanges(entryIds)}>
|
||||||
<Icon type="check" /> {t('accept')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="check" />}
|
||||||
|
bs5={<MaterialIcon type="check" />}
|
||||||
|
/>
|
||||||
|
{t('accept')}
|
||||||
</EntryActions.Button>
|
</EntryActions.Button>
|
||||||
</EntryActions>
|
</EntryActions>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import Icon from '../../../../../../shared/components/icon'
|
||||||
import BulkActions from './bulk-actions'
|
import BulkActions from './bulk-actions'
|
||||||
import Modal, { useBulkActionsModal } from './modal'
|
import Modal, { useBulkActionsModal } from './modal'
|
||||||
import { ReviewPanelBulkActionsEntry } from '../../../../../../../../types/review-panel/entry'
|
import { ReviewPanelBulkActionsEntry } from '../../../../../../../../types/review-panel/entry'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
|
||||||
type BulkActionsEntryProps = {
|
type BulkActionsEntryProps = {
|
||||||
entryId: ReviewPanelBulkActionsEntry['type']
|
entryId: ReviewPanelBulkActionsEntry['type']
|
||||||
|
@ -30,10 +32,18 @@ function BulkActionsEntry({ entryId, nChanges }: BulkActionsEntryProps) {
|
||||||
<EntryCallout className="rp-entry-callout-bulk-actions" />
|
<EntryCallout className="rp-entry-callout-bulk-actions" />
|
||||||
<BulkActions className="rp-entry">
|
<BulkActions className="rp-entry">
|
||||||
<BulkActions.Button onClick={handleShowBulkRejectDialog}>
|
<BulkActions.Button onClick={handleShowBulkRejectDialog}>
|
||||||
<Icon type="times" /> {t('reject_all')} ({nChanges})
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="times" />}
|
||||||
|
bs5={<MaterialIcon type="close" />}
|
||||||
|
/>
|
||||||
|
{t('reject_all')} ({nChanges})
|
||||||
</BulkActions.Button>
|
</BulkActions.Button>
|
||||||
<BulkActions.Button onClick={handleShowBulkAcceptDialog}>
|
<BulkActions.Button onClick={handleShowBulkAcceptDialog}>
|
||||||
<Icon type="check" /> {t('accept_all')} ({nChanges})
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="check" />}
|
||||||
|
bs5={<MaterialIcon type="check" />}
|
||||||
|
/>
|
||||||
|
{t('accept_all')} ({nChanges})
|
||||||
</BulkActions.Button>
|
</BulkActions.Button>
|
||||||
</BulkActions>
|
</BulkActions>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import { useState, useCallback } from 'react'
|
import { useState, useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Button, Modal as BootstrapModal } from 'react-bootstrap'
|
|
||||||
import AccessibleModal from '../../../../../../shared/components/accessible-modal'
|
|
||||||
import { useReviewPanelUpdaterFnsContext } from '../../../../context/review-panel/review-panel-context'
|
import { useReviewPanelUpdaterFnsContext } from '../../../../context/review-panel/review-panel-context'
|
||||||
|
import OLModal, {
|
||||||
|
OLModalBody,
|
||||||
|
OLModalFooter,
|
||||||
|
OLModalHeader,
|
||||||
|
OLModalTitle,
|
||||||
|
} from '@/features/ui/components/ol/ol-modal'
|
||||||
|
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||||
|
|
||||||
type BulkActionsModalProps = {
|
type BulkActionsModalProps = {
|
||||||
show: boolean
|
show: boolean
|
||||||
|
@ -22,30 +27,28 @@ function Modal({
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AccessibleModal show={show} onHide={() => setShow(false)}>
|
<OLModal show={show} onHide={() => setShow(false)}>
|
||||||
<BootstrapModal.Header closeButton>
|
<OLModalHeader closeButton>
|
||||||
<h3>{isAccept ? t('accept_all') : t('reject_all')}</h3>
|
<OLModalTitle>
|
||||||
</BootstrapModal.Header>
|
{isAccept ? t('accept_all') : t('reject_all')}
|
||||||
<BootstrapModal.Body>
|
</OLModalTitle>
|
||||||
|
</OLModalHeader>
|
||||||
|
<OLModalBody>
|
||||||
<p>
|
<p>
|
||||||
{isAccept
|
{isAccept
|
||||||
? t('bulk_accept_confirm', { nChanges })
|
? t('bulk_accept_confirm', { nChanges })
|
||||||
: t('bulk_reject_confirm', { nChanges })}
|
: t('bulk_reject_confirm', { nChanges })}
|
||||||
</p>
|
</p>
|
||||||
</BootstrapModal.Body>
|
</OLModalBody>
|
||||||
<BootstrapModal.Footer>
|
<OLModalFooter>
|
||||||
<Button
|
<OLButton variant="secondary" onClick={() => setShow(false)}>
|
||||||
bsStyle={null}
|
|
||||||
className="btn-secondary"
|
|
||||||
onClick={() => setShow(false)}
|
|
||||||
>
|
|
||||||
{t('cancel')}
|
{t('cancel')}
|
||||||
</Button>
|
</OLButton>
|
||||||
<Button bsStyle={null} className="btn-primary" onClick={onConfirm}>
|
<OLButton variant="primary" onClick={onConfirm}>
|
||||||
{t('ok')}
|
{t('ok')}
|
||||||
</Button>
|
</OLButton>
|
||||||
</BootstrapModal.Footer>
|
</OLModalFooter>
|
||||||
</AccessibleModal>
|
</OLModal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ import comparePropsWithShallowArrayCompare from '../utils/compare-props-with-sha
|
||||||
import useIndicatorHover from '../hooks/use-indicator-hover'
|
import useIndicatorHover from '../hooks/use-indicator-hover'
|
||||||
import EntryIndicator from './entry-indicator'
|
import EntryIndicator from './entry-indicator'
|
||||||
import { useEntryClick } from '@/features/source-editor/components/review-panel/hooks/use-entry-click'
|
import { useEntryClick } from '@/features/source-editor/components/review-panel/hooks/use-entry-click'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
|
||||||
interface ChangeEntryProps extends BaseChangeEntryProps {
|
interface ChangeEntryProps extends BaseChangeEntryProps {
|
||||||
type: ReviewPanelChangeEntry['type']
|
type: ReviewPanelChangeEntry['type']
|
||||||
|
@ -71,7 +73,14 @@ function ChangeEntry({
|
||||||
onMouseEnter={handleIndicatorMouseEnter}
|
onMouseEnter={handleIndicatorMouseEnter}
|
||||||
onClick={handleIndicatorClick}
|
onClick={handleIndicatorClick}
|
||||||
>
|
>
|
||||||
{isInsert ? <Icon type="pencil" /> : <i className="rp-icon-delete" />}
|
{isInsert ? (
|
||||||
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="pencil" />}
|
||||||
|
bs5={<MaterialIcon type="edit" />}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<i className="rp-icon-delete" />
|
||||||
|
)}
|
||||||
</EntryIndicator>
|
</EntryIndicator>
|
||||||
<div
|
<div
|
||||||
className={classnames('rp-entry', `rp-entry-${type}`, {
|
className={classnames('rp-entry', `rp-entry-${type}`, {
|
||||||
|
@ -81,7 +90,10 @@ function ChangeEntry({
|
||||||
<div className="rp-entry-body">
|
<div className="rp-entry-body">
|
||||||
<div className="rp-entry-action-icon">
|
<div className="rp-entry-action-icon">
|
||||||
{isInsert ? (
|
{isInsert ? (
|
||||||
<Icon type="pencil" />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="pencil" />}
|
||||||
|
bs5={<MaterialIcon type="edit" />}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<i className="rp-icon-delete" />
|
<i className="rp-icon-delete" />
|
||||||
)}
|
)}
|
||||||
|
@ -106,7 +118,7 @@ function ChangeEntry({
|
||||||
)}
|
)}
|
||||||
{needsCollapsing && (
|
{needsCollapsing && (
|
||||||
<button
|
<button
|
||||||
className="rp-collapse-toggle btn-inline-link"
|
className="rp-collapse-toggle"
|
||||||
onClick={handleToggleCollapse}
|
onClick={handleToggleCollapse}
|
||||||
>
|
>
|
||||||
{isCollapsed
|
{isCollapsed
|
||||||
|
@ -137,10 +149,18 @@ function ChangeEntry({
|
||||||
{permissions.write && (
|
{permissions.write && (
|
||||||
<EntryActions>
|
<EntryActions>
|
||||||
<EntryActions.Button onClick={() => rejectChanges(entryIds)}>
|
<EntryActions.Button onClick={() => rejectChanges(entryIds)}>
|
||||||
<Icon type="times" /> {t('reject')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="times" />}
|
||||||
|
bs5={<MaterialIcon type="close" />}
|
||||||
|
/>
|
||||||
|
{t('reject')}
|
||||||
</EntryActions.Button>
|
</EntryActions.Button>
|
||||||
<EntryActions.Button onClick={() => acceptChanges(entryIds)}>
|
<EntryActions.Button onClick={() => acceptChanges(entryIds)}>
|
||||||
<Icon type="check" /> {t('accept')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="check" />}
|
||||||
|
bs5={<MaterialIcon type="check" />}
|
||||||
|
/>
|
||||||
|
{t('accept')}
|
||||||
</EntryActions.Button>
|
</EntryActions.Button>
|
||||||
</EntryActions>
|
</EntryActions>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -16,6 +16,9 @@ import { ReviewPanelCommentEntry } from '../../../../../../../types/review-panel
|
||||||
import useIndicatorHover from '../hooks/use-indicator-hover'
|
import useIndicatorHover from '../hooks/use-indicator-hover'
|
||||||
import EntryIndicator from './entry-indicator'
|
import EntryIndicator from './entry-indicator'
|
||||||
import { useEntryClick } from '@/features/source-editor/components/review-panel/hooks/use-entry-click'
|
import { useEntryClick } from '@/features/source-editor/components/review-panel/hooks/use-entry-click'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import LoadingSpinner from '@/shared/components/loading-spinner'
|
||||||
|
|
||||||
type CommentEntryProps = {
|
type CommentEntryProps = {
|
||||||
docId: DocId
|
docId: DocId
|
||||||
|
@ -120,7 +123,10 @@ function CommentEntry({
|
||||||
onMouseEnter={handleIndicatorMouseEnter}
|
onMouseEnter={handleIndicatorMouseEnter}
|
||||||
onClick={handleIndicatorClick}
|
onClick={handleIndicatorClick}
|
||||||
>
|
>
|
||||||
<Icon type="comment" />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="comment" />}
|
||||||
|
bs5={<MaterialIcon type="mode_comment" />}
|
||||||
|
/>
|
||||||
</EntryIndicator>
|
</EntryIndicator>
|
||||||
<div
|
<div
|
||||||
className={classnames('rp-entry', 'rp-entry-comment', {
|
className={classnames('rp-entry', 'rp-entry-comment', {
|
||||||
|
@ -130,7 +136,7 @@ function CommentEntry({
|
||||||
ref={entryDivRef}
|
ref={entryDivRef}
|
||||||
>
|
>
|
||||||
{!submitting && (!thread || thread.messages.length === 0) && (
|
{!submitting && (!thread || thread.messages.length === 0) && (
|
||||||
<div className="rp-loading">{t('no_comments')}</div>
|
<div className="text-center p-1">{t('no_comments')}</div>
|
||||||
)}
|
)}
|
||||||
<div className="rp-comment-loaded">
|
<div className="rp-comment-loaded">
|
||||||
{thread.messages.map(comment => (
|
{thread.messages.map(comment => (
|
||||||
|
@ -143,9 +149,7 @@ function CommentEntry({
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{submitting && (
|
{submitting && (
|
||||||
<div className="rp-loading">
|
<LoadingSpinner className="d-flex justify-content-center" />
|
||||||
<Icon type="spinner" spin />
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
{permissions.comment && (
|
{permissions.comment && (
|
||||||
<div className="rp-comment-reply">
|
<div className="rp-comment-reply">
|
||||||
|
@ -163,7 +167,11 @@ function CommentEntry({
|
||||||
<EntryActions>
|
<EntryActions>
|
||||||
{permissions.comment && permissions.write && (
|
{permissions.comment && permissions.write && (
|
||||||
<EntryActions.Button onClick={handleAnimateAndCallOnResolve}>
|
<EntryActions.Button onClick={handleAnimateAndCallOnResolve}>
|
||||||
<Icon type="inbox" /> {t('resolve')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="inbox" />}
|
||||||
|
bs5={<MaterialIcon type="inbox" />}
|
||||||
|
/>
|
||||||
|
{t('resolve')}
|
||||||
</EntryActions.Button>
|
</EntryActions.Button>
|
||||||
)}
|
)}
|
||||||
{permissions.comment && (
|
{permissions.comment && (
|
||||||
|
@ -171,7 +179,11 @@ function CommentEntry({
|
||||||
onClick={handleOnReply}
|
onClick={handleOnReply}
|
||||||
disabled={!replyContent.length}
|
disabled={!replyContent.length}
|
||||||
>
|
>
|
||||||
<Icon type="reply" /> {t('reply')}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="reply" />}
|
||||||
|
bs5={<MaterialIcon type="reply" />}
|
||||||
|
/>
|
||||||
|
{t('reply')}
|
||||||
</EntryActions.Button>
|
</EntryActions.Button>
|
||||||
)}
|
)}
|
||||||
</EntryActions>
|
</EntryActions>
|
||||||
|
|
|
@ -61,7 +61,7 @@ function ResolvedCommentEntry({
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
className="rp-collapse-toggle btn-inline-link"
|
className="rp-collapse-toggle"
|
||||||
onClick={() => setIsCollapsed(value => !value)}
|
onClick={() => setIsCollapsed(value => !value)}
|
||||||
>
|
>
|
||||||
{isCollapsed ? `… (${t('show_all')})` : ` (${t('show_less')})`}
|
{isCollapsed ? `… (${t('show_all')})` : ` (${t('show_less')})`}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import {
|
||||||
import { isCurrentFileView, isOverviewView } from '../../utils/sub-view'
|
import { isCurrentFileView, isOverviewView } from '../../utils/sub-view'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useResizeObserver } from '../../../../shared/hooks/use-resize-observer'
|
import { useResizeObserver } from '../../../../shared/hooks/use-resize-observer'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
|
||||||
function Nav() {
|
function Nav() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -40,7 +42,10 @@ function Nav() {
|
||||||
})}
|
})}
|
||||||
onClick={() => handleSetSubview('cur_file')}
|
onClick={() => handleSetSubview('cur_file')}
|
||||||
>
|
>
|
||||||
<Icon type="file-text-o" />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="file-text-o" />}
|
||||||
|
bs5={<MaterialIcon type="description" className="align-middle" />}
|
||||||
|
/>
|
||||||
<span className="rp-nav-label">{t('current_file')}</span>
|
<span className="rp-nav-label">{t('current_file')}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
@ -55,7 +60,10 @@ function Nav() {
|
||||||
})}
|
})}
|
||||||
onClick={() => handleSetSubview('overview')}
|
onClick={() => handleSetSubview('overview')}
|
||||||
>
|
>
|
||||||
<Icon type="list" />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="list" />}
|
||||||
|
bs5={<MaterialIcon type="list" className="align-middle" />}
|
||||||
|
/>
|
||||||
<span className="rp-nav-label">{t('overview')}</span>
|
<span className="rp-nav-label">{t('overview')}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,11 +2,11 @@ import Container from './container'
|
||||||
import Toggler from './toggler'
|
import Toggler from './toggler'
|
||||||
import Toolbar from './toolbar/toolbar'
|
import Toolbar from './toolbar/toolbar'
|
||||||
import Nav from './nav'
|
import Nav from './nav'
|
||||||
import Icon from '../../../../shared/components/icon'
|
|
||||||
import OverviewFile from './overview-file'
|
import OverviewFile from './overview-file'
|
||||||
import { useReviewPanelValueContext } from '../../context/review-panel/review-panel-context'
|
import { useReviewPanelValueContext } from '../../context/review-panel/review-panel-context'
|
||||||
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
|
import LoadingSpinner from '@/shared/components/loading-spinner'
|
||||||
|
|
||||||
function OverviewContainer() {
|
function OverviewContainer() {
|
||||||
const { isOverviewLoading } = useReviewPanelValueContext()
|
const { isOverviewLoading } = useReviewPanelValueContext()
|
||||||
|
@ -24,9 +24,7 @@ function OverviewContainer() {
|
||||||
aria-labelledby="review-panel-tab-overview"
|
aria-labelledby="review-panel-tab-overview"
|
||||||
>
|
>
|
||||||
{isOverviewLoading ? (
|
{isOverviewLoading ? (
|
||||||
<div className="rp-loading">
|
<LoadingSpinner className="d-flex justify-content-center my-2" />
|
||||||
<Icon type="spinner" spin />
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
docs?.map(doc => (
|
docs?.map(doc => (
|
||||||
<OverviewFile
|
<OverviewFile
|
||||||
|
|
|
@ -8,6 +8,8 @@ import classnames from 'classnames'
|
||||||
import { ReviewPanelDocEntries } from '../../../../../../types/review-panel/review-panel'
|
import { ReviewPanelDocEntries } from '../../../../../../types/review-panel/review-panel'
|
||||||
import { MainDocument } from '../../../../../../types/project-settings'
|
import { MainDocument } from '../../../../../../types/project-settings'
|
||||||
import OverviewFileEntries from '@/features/source-editor/components/review-panel/entries/overview-file-entries'
|
import OverviewFileEntries from '@/features/source-editor/components/review-panel/entries/overview-file-entries'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
|
||||||
type OverviewFileProps = {
|
type OverviewFileProps = {
|
||||||
docId: MainDocument['doc']['id']
|
docId: MainDocument['doc']['id']
|
||||||
|
@ -45,7 +47,10 @@ function OverviewFile({ docId, docPath }: OverviewFileProps) {
|
||||||
'rp-overview-file-header-collapse-on': docCollapsed,
|
'rp-overview-file-header-collapse-on': docCollapsed,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Icon type="angle-down" />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="angle-down" />}
|
||||||
|
bs5={<MaterialIcon type="expand_more" />}
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
{docPath}
|
{docPath}
|
||||||
{docCollapsed && (
|
{docCollapsed && (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useLayoutEffect, useRef, useCallback } from 'react'
|
||||||
import { useLayoutContext } from '../../../../shared/context/layout-context'
|
import { useLayoutContext } from '../../../../shared/context/layout-context'
|
||||||
import {
|
import {
|
||||||
ReviewPanelEntry,
|
ReviewPanelEntry,
|
||||||
|
@ -6,7 +6,6 @@ import {
|
||||||
} from '../../../../../../types/review-panel/entry'
|
} from '../../../../../../types/review-panel/entry'
|
||||||
import { debugConsole } from '../../../../utils/debugging'
|
import { debugConsole } from '../../../../utils/debugging'
|
||||||
import { useReviewPanelValueContext } from '../../context/review-panel/review-panel-context'
|
import { useReviewPanelValueContext } from '../../context/review-panel/review-panel-context'
|
||||||
import useEventListener from '../../../../shared/hooks/use-event-listener'
|
|
||||||
import { ReviewPanelDocEntries } from '../../../../../../types/review-panel/review-panel'
|
import { ReviewPanelDocEntries } from '../../../../../../types/review-panel/review-panel'
|
||||||
import { dispatchReviewPanelLayout } from '../../extensions/changes/change-manager'
|
import { dispatchReviewPanelLayout } from '../../extensions/changes/change-manager'
|
||||||
import { isEqual } from 'lodash'
|
import { isEqual } from 'lodash'
|
||||||
|
@ -214,7 +213,8 @@ function PositionedEntries({
|
||||||
previousLayoutInfoRef.current = initialLayoutInfo
|
previousLayoutInfoRef.current = initialLayoutInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
const layout = (animate = true) => {
|
const layout = useCallback(
|
||||||
|
(animate = true) => {
|
||||||
const container = containerRef.current
|
const container = containerRef.current
|
||||||
if (!container) {
|
if (!container) {
|
||||||
return
|
return
|
||||||
|
@ -252,7 +252,8 @@ function PositionedEntries({
|
||||||
const layoutElement = reviewPanelOpen ? box : indicator
|
const layoutElement = reviewPanelOpen ? box : indicator
|
||||||
|
|
||||||
if (box && callout && layoutElement) {
|
if (box && callout && layoutElement) {
|
||||||
const previousPositions = previousLayoutInfoRef.current?.positions.find(
|
const previousPositions =
|
||||||
|
previousLayoutInfoRef.current?.positions.find(
|
||||||
pos => pos.entryId === entryId
|
pos => pos.entryId === entryId
|
||||||
)?.positions
|
)?.positions
|
||||||
const hasScreenPos = Boolean(entry.screenPos)
|
const hasScreenPos = Boolean(entry.screenPos)
|
||||||
|
@ -452,17 +453,29 @@ function PositionedEntries({
|
||||||
height,
|
height,
|
||||||
overflowTop,
|
overflowTop,
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
[entries, lineHeight, navHeight, reviewPanelOpen, toolbarHeight]
|
||||||
|
)
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const callback = (event: Event) => {
|
||||||
|
const e = event as CustomEvent
|
||||||
|
|
||||||
useEventListener('review-panel:layout', (event: CustomEvent) => {
|
|
||||||
if (!layoutSuspended) {
|
if (!layoutSuspended) {
|
||||||
// Clear previous positions if forcing a layout
|
// Clear previous positions if forcing a layout
|
||||||
if (event.detail.force) {
|
if (e.detail.force) {
|
||||||
previousLayoutInfoRef.current = initialLayoutInfo
|
previousLayoutInfoRef.current = initialLayoutInfo
|
||||||
}
|
}
|
||||||
layout(event.detail.animate)
|
layout(e.detail.animate)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
window.addEventListener('review-panel:layout', callback)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('review-panel:layout', callback)
|
||||||
|
}
|
||||||
|
}, [layoutSuspended, layout])
|
||||||
|
|
||||||
// Layout on first render. This is necessary to ensure layout happens when
|
// Layout on first render. This is necessary to ensure layout happens when
|
||||||
// switching from overview to current file view
|
// switching from overview to current file view
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useReviewPanelUpdaterFnsContext } from '../../context/review-panel/review-panel-context'
|
import { useReviewPanelUpdaterFnsContext } from '../../context/review-panel/review-panel-context'
|
||||||
|
import Icon from '@/shared/components/icon'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
|
||||||
function Toggler() {
|
function Toggler() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -18,6 +21,12 @@ function Toggler() {
|
||||||
onClick={handleTogglerClick}
|
onClick={handleTogglerClick}
|
||||||
>
|
>
|
||||||
<span className="sr-only">{t('hotkey_toggle_review_panel')}</span>
|
<span className="sr-only">{t('hotkey_toggle_review_panel')}</span>
|
||||||
|
<span className="review-panel-toggler-icon">
|
||||||
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="chevron-left" />}
|
||||||
|
bs5={<MaterialIcon type="chevron_left" />}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useState, useMemo, useCallback } from 'react'
|
import { useState, useMemo, useCallback } from 'react'
|
||||||
import Icon from '../../../../../shared/components/icon'
|
import Icon from '../../../../../shared/components/icon'
|
||||||
import Tooltip from '../../../../../shared/components/tooltip'
|
|
||||||
import ResolvedCommentsScroller from './resolved-comments-scroller'
|
import ResolvedCommentsScroller from './resolved-comments-scroller'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import {
|
import {
|
||||||
|
@ -16,6 +15,10 @@ import { ReviewPanelResolvedCommentThread } from '../../../../../../../types/rev
|
||||||
import { DocId } from '../../../../../../../types/project-settings'
|
import { DocId } from '../../../../../../../types/project-settings'
|
||||||
import { ReviewPanelEntry } from '../../../../../../../types/review-panel/entry'
|
import { ReviewPanelEntry } from '../../../../../../../types/review-panel/entry'
|
||||||
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
||||||
|
import LoadingSpinner from '@/shared/components/loading-spinner'
|
||||||
|
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
|
||||||
export interface FilteredResolvedComments
|
export interface FilteredResolvedComments
|
||||||
extends ReviewPanelResolvedCommentThread {
|
extends ReviewPanelResolvedCommentThread {
|
||||||
|
@ -97,7 +100,7 @@ function ResolvedCommentsDropdown() {
|
||||||
onClick={() => setIsOpen(false)}
|
onClick={() => setIsOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Tooltip
|
<OLTooltip
|
||||||
id="resolved-comments-toggle"
|
id="resolved-comments-toggle"
|
||||||
description={t('resolved_comments')}
|
description={t('resolved_comments')}
|
||||||
overlayProps={{ container: document.body, placement: 'bottom' }}
|
overlayProps={{ container: document.body, placement: 'bottom' }}
|
||||||
|
@ -107,9 +110,12 @@ function ResolvedCommentsDropdown() {
|
||||||
onClick={handleResolvedCommentsClick}
|
onClick={handleResolvedCommentsClick}
|
||||||
aria-label={t('resolved_comments')}
|
aria-label={t('resolved_comments')}
|
||||||
>
|
>
|
||||||
<Icon type="inbox" />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="inbox" />}
|
||||||
|
bs5={<MaterialIcon type="inbox" />}
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</OLTooltip>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={classnames('resolved-comments-dropdown', {
|
className={classnames('resolved-comments-dropdown', {
|
||||||
|
@ -117,9 +123,7 @@ function ResolvedCommentsDropdown() {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="rp-loading">
|
<LoadingSpinner className="d-flex justify-content-center my-2" />
|
||||||
<Icon type="spinner" spin />
|
|
||||||
</div>
|
|
||||||
) : isOpen ? (
|
) : isOpen ? (
|
||||||
<ResolvedCommentsScroller
|
<ResolvedCommentsScroller
|
||||||
resolvedComments={filteredResolvedComments}
|
resolvedComments={filteredResolvedComments}
|
||||||
|
|
|
@ -31,7 +31,7 @@ function ResolvedCommentsScroller({
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{!resolvedComments.length && (
|
{!resolvedComments.length && (
|
||||||
<div className="rp-loading">{t('no_resolved_threads')}</div>
|
<div className="text-center p-1">{t('no_resolved_threads')}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,6 +10,8 @@ import {
|
||||||
} from '../../../context/review-panel/review-panel-context'
|
} from '../../../context/review-panel/review-panel-context'
|
||||||
import { send, sendMB } from '../../../../../infrastructure/event-tracking'
|
import { send, sendMB } from '../../../../../infrastructure/event-tracking'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
|
||||||
const sendAnalytics = () => {
|
const sendAnalytics = () => {
|
||||||
send('subscription-funnel', 'editor-click-feature', 'real-time-track-changes')
|
send('subscription-funnel', 'editor-click-feature', 'real-time-track-changes')
|
||||||
|
@ -39,7 +41,7 @@ function ToggleMenu() {
|
||||||
<span className="review-panel-toolbar-label">
|
<span className="review-panel-toolbar-label">
|
||||||
{wantTrackChanges && (
|
{wantTrackChanges && (
|
||||||
<span className="review-panel-toolbar-icon-on">
|
<span className="review-panel-toolbar-icon-on">
|
||||||
<Icon type="circle" />
|
<span className="track-changes-indicator-circle" />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -47,13 +49,18 @@ function ToggleMenu() {
|
||||||
className="review-panel-toolbar-collapse-button"
|
className="review-panel-toolbar-collapse-button"
|
||||||
onClick={handleToggleFullTCStateCollapse}
|
onClick={handleToggleFullTCStateCollapse}
|
||||||
>
|
>
|
||||||
|
<span>
|
||||||
{wantTrackChanges ? <TrackChangesOn /> : <TrackChangesOff />}
|
{wantTrackChanges ? <TrackChangesOn /> : <TrackChangesOff />}
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
className={classnames('rp-tc-state-collapse', {
|
className={classnames('rp-tc-state-collapse', {
|
||||||
'rp-tc-state-collapse-on': shouldCollapse,
|
'rp-tc-state-collapse-on': shouldCollapse,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Icon type="angle-down" />
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="angle-down" />}
|
||||||
|
bs5={<MaterialIcon type="expand_more" />}
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Tooltip from '@/shared/components/tooltip'
|
|
||||||
import TrackChangesToggle from '@/features/source-editor/components/review-panel/toolbar/track-changes-toggle'
|
import TrackChangesToggle from '@/features/source-editor/components/review-panel/toolbar/track-changes-toggle'
|
||||||
import {
|
import {
|
||||||
useReviewPanelUpdaterFnsContext,
|
useReviewPanelUpdaterFnsContext,
|
||||||
|
@ -7,6 +6,7 @@ import {
|
||||||
} from '@/features/source-editor/context/review-panel/review-panel-context'
|
} from '@/features/source-editor/context/review-panel/review-panel-context'
|
||||||
import { useProjectContext } from '@/shared/context/project-context'
|
import { useProjectContext } from '@/shared/context/project-context'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||||
|
|
||||||
function TrackChangesMenu() {
|
function TrackChangesMenu() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -28,7 +28,7 @@ function TrackChangesMenu() {
|
||||||
return (
|
return (
|
||||||
<ul className="rp-tc-state" data-testid="review-panel-track-changes-menu">
|
<ul className="rp-tc-state" data-testid="review-panel-track-changes-menu">
|
||||||
<li className="rp-tc-state-item rp-tc-state-item-everyone">
|
<li className="rp-tc-state-item rp-tc-state-item-everyone">
|
||||||
<Tooltip
|
<OLTooltip
|
||||||
description={t('tc_switch_everyone_tip')}
|
description={t('tc_switch_everyone_tip')}
|
||||||
id="track-changes-switch-everyone"
|
id="track-changes-switch-everyone"
|
||||||
overlayProps={{
|
overlayProps={{
|
||||||
|
@ -38,7 +38,7 @@ function TrackChangesMenu() {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="rp-tc-state-item-name">{t('tc_everyone')}</span>
|
<span className="rp-tc-state-item-name">{t('tc_everyone')}</span>
|
||||||
</Tooltip>
|
</OLTooltip>
|
||||||
|
|
||||||
<TrackChangesToggle
|
<TrackChangesToggle
|
||||||
id="track-changes-everyone"
|
id="track-changes-everyone"
|
||||||
|
@ -52,7 +52,7 @@ function TrackChangesMenu() {
|
||||||
</li>
|
</li>
|
||||||
{Object.values(formattedProjectMembers).map(member => (
|
{Object.values(formattedProjectMembers).map(member => (
|
||||||
<li className="rp-tc-state-item" key={member.id}>
|
<li className="rp-tc-state-item" key={member.id}>
|
||||||
<Tooltip
|
<OLTooltip
|
||||||
description={t('tc_switch_user_tip')}
|
description={t('tc_switch_user_tip')}
|
||||||
id="track-changes-switch-user"
|
id="track-changes-switch-user"
|
||||||
overlayProps={{
|
overlayProps={{
|
||||||
|
@ -68,7 +68,7 @@ function TrackChangesMenu() {
|
||||||
>
|
>
|
||||||
{member.name}
|
{member.name}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</OLTooltip>
|
||||||
|
|
||||||
<TrackChangesToggle
|
<TrackChangesToggle
|
||||||
id={`track-changes-user-toggle-${member.id}`}
|
id={`track-changes-user-toggle-${member.id}`}
|
||||||
|
@ -90,7 +90,7 @@ function TrackChangesMenu() {
|
||||||
))}
|
))}
|
||||||
<li className="rp-tc-state-separator" />
|
<li className="rp-tc-state-separator" />
|
||||||
<li className="rp-tc-state-item">
|
<li className="rp-tc-state-item">
|
||||||
<Tooltip
|
<OLTooltip
|
||||||
description={t('tc_switch_guests_tip')}
|
description={t('tc_switch_guests_tip')}
|
||||||
id="track-changes-switch-guests"
|
id="track-changes-switch-guests"
|
||||||
overlayProps={{
|
overlayProps={{
|
||||||
|
@ -106,7 +106,7 @@ function TrackChangesMenu() {
|
||||||
>
|
>
|
||||||
{t('tc_guests')}
|
{t('tc_guests')}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</OLTooltip>
|
||||||
|
|
||||||
<TrackChangesToggle
|
<TrackChangesToggle
|
||||||
id="track-changes-guests-toggle"
|
id="track-changes-guests-toggle"
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Row, Col, Button, Modal } from 'react-bootstrap'
|
|
||||||
import AccessibleModal from '../../../../shared/components/accessible-modal'
|
|
||||||
import Icon from '../../../../shared/components/icon'
|
import Icon from '../../../../shared/components/icon'
|
||||||
import { useProjectContext } from '../../../../shared/context/project-context'
|
import { useProjectContext } from '../../../../shared/context/project-context'
|
||||||
import { useUserContext } from '../../../../shared/context/user-context'
|
import { useUserContext } from '../../../../shared/context/user-context'
|
||||||
import { startFreeTrial, upgradePlan } from '../../../../main/account-upgrade'
|
import { startFreeTrial, upgradePlan } from '../../../../main/account-upgrade'
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||||
|
import OLModal, {
|
||||||
|
OLModalBody,
|
||||||
|
OLModalFooter,
|
||||||
|
OLModalHeader,
|
||||||
|
OLModalTitle,
|
||||||
|
} from '@/features/ui/components/ol/ol-modal'
|
||||||
|
import OLButton from '@/features/ui/components/ol/ol-button'
|
||||||
|
import OLRow from '@/features/ui/components/ol/ol-row'
|
||||||
|
import OLCol from '@/features/ui/components/ol/ol-col'
|
||||||
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
|
import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
|
||||||
type UpgradeTrackChangesModalProps = {
|
type UpgradeTrackChangesModalProps = {
|
||||||
show: boolean
|
show: boolean
|
||||||
|
@ -24,11 +33,11 @@ function UpgradeTrackChangesModal({
|
||||||
const hasNewPaywallCta = useFeatureFlag('paywall-cta')
|
const hasNewPaywallCta = useFeatureFlag('paywall-cta')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AccessibleModal show={show} onHide={() => setShow(false)}>
|
<OLModal show={show} onHide={() => setShow(false)}>
|
||||||
<Modal.Header closeButton>
|
<OLModalHeader closeButton>
|
||||||
<h3>{t('upgrade_to_track_changes')}</h3>
|
<OLModalTitle>{t('upgrade_to_track_changes')}</OLModalTitle>
|
||||||
</Modal.Header>
|
</OLModalHeader>
|
||||||
<Modal.Body>
|
<OLModalBody>
|
||||||
<div className="teaser-video-container">
|
<div className="teaser-video-container">
|
||||||
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
|
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
|
||||||
<video className="teaser-video" autoPlay loop>
|
<video className="teaser-video" autoPlay loop>
|
||||||
|
@ -45,8 +54,8 @@ function UpgradeTrackChangesModal({
|
||||||
<h4 className="teaser-title">
|
<h4 className="teaser-title">
|
||||||
{t('see_changes_in_your_documents_live')}
|
{t('see_changes_in_your_documents_live')}
|
||||||
</h4>
|
</h4>
|
||||||
<Row>
|
<OLRow>
|
||||||
<Col md={10} mdOffset={1}>
|
<OLCol lg={{ span: 10, offset: 1 }}>
|
||||||
<ul className="list-unstyled">
|
<ul className="list-unstyled">
|
||||||
{[
|
{[
|
||||||
t('track_any_change_in_real_time'),
|
t('track_any_change_in_real_time'),
|
||||||
|
@ -54,36 +63,43 @@ function UpgradeTrackChangesModal({
|
||||||
t('accept_or_reject_each_changes_individually'),
|
t('accept_or_reject_each_changes_individually'),
|
||||||
].map(translation => (
|
].map(translation => (
|
||||||
<li key={translation}>
|
<li key={translation}>
|
||||||
<Icon type="check" /> {translation}
|
<BootstrapVersionSwitcher
|
||||||
|
bs3={<Icon type="check" />}
|
||||||
|
bs5={
|
||||||
|
<MaterialIcon
|
||||||
|
type="check"
|
||||||
|
className="align-text-bottom"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{translation}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</Col>
|
</OLCol>
|
||||||
</Row>
|
</OLRow>
|
||||||
<p className="small">
|
<p className="small">
|
||||||
{t('already_subscribed_try_refreshing_the_page')}
|
{t('already_subscribed_try_refreshing_the_page')}
|
||||||
</p>
|
</p>
|
||||||
{project.owner && (
|
{project.owner && (
|
||||||
<Row className="text-center">
|
<div className="text-center">
|
||||||
{project.owner._id === user.id ? (
|
{project.owner._id === user.id ? (
|
||||||
user.allowedFreeTrial ? (
|
user.allowedFreeTrial ? (
|
||||||
<Button
|
<OLButton
|
||||||
bsStyle={null}
|
variant="primary"
|
||||||
className="btn-primary"
|
|
||||||
onClick={() => startFreeTrial('track-changes')}
|
onClick={() => startFreeTrial('track-changes')}
|
||||||
>
|
>
|
||||||
{hasNewPaywallCta
|
{hasNewPaywallCta
|
||||||
? t('get_track_changes')
|
? t('get_track_changes')
|
||||||
: t('try_it_for_free')}
|
: t('try_it_for_free')}
|
||||||
</Button>
|
</OLButton>
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<OLButton
|
||||||
bsStyle={null}
|
variant="primary"
|
||||||
className="btn-primary"
|
|
||||||
onClick={() => upgradePlan('project-sharing')}
|
onClick={() => upgradePlan('project-sharing')}
|
||||||
>
|
>
|
||||||
{t('upgrade')}
|
{t('upgrade')}
|
||||||
</Button>
|
</OLButton>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<p>
|
<p>
|
||||||
|
@ -94,19 +110,15 @@ function UpgradeTrackChangesModal({
|
||||||
</strong>
|
</strong>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</Row>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Modal.Body>
|
</OLModalBody>
|
||||||
<Modal.Footer>
|
<OLModalFooter>
|
||||||
<Button
|
<OLButton variant="secondary" onClick={() => setShow(false)}>
|
||||||
bsStyle={null}
|
|
||||||
className="btn-secondary"
|
|
||||||
onClick={() => setShow(false)}
|
|
||||||
>
|
|
||||||
{t('close')}
|
{t('close')}
|
||||||
</Button>
|
</OLButton>
|
||||||
</Modal.Footer>
|
</OLModalFooter>
|
||||||
</AccessibleModal>
|
</OLModal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,10 +39,7 @@ function LoadingSpinner({
|
||||||
}
|
}
|
||||||
|
|
||||||
const extraClasses = isBootstrap5()
|
const extraClasses = isBootstrap5()
|
||||||
? [
|
? [align === 'left' ? 'align-items-start' : 'align-items-center']
|
||||||
'd-inline-flex',
|
|
||||||
align === 'left' ? 'align-items-start' : 'align-items-center',
|
|
||||||
]
|
|
||||||
: null
|
: null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -9,10 +9,8 @@
|
||||||
@rp-border-grey: #d9d9d9;
|
@rp-border-grey: #d9d9d9;
|
||||||
|
|
||||||
@rp-green: #2c8e30;
|
@rp-green: #2c8e30;
|
||||||
@rp-green-on-dark: rgba(37, 107, 41, 0.5);
|
|
||||||
@rp-red: #c5060b;
|
@rp-red: #c5060b;
|
||||||
@rp-yellow: #f3b111;
|
@rp-yellow: #f3b111;
|
||||||
@rp-yellow-on-dark: rgba(194, 93, 11, 0.5);
|
|
||||||
@rp-grey: #aaaaaa;
|
@rp-grey: #aaaaaa;
|
||||||
|
|
||||||
@rp-type-blue: #6b7797;
|
@rp-type-blue: #6b7797;
|
||||||
|
@ -24,8 +22,6 @@
|
||||||
@review-panel-width: 230px;
|
@review-panel-width: 230px;
|
||||||
@review-off-width: 22px;
|
@review-off-width: 22px;
|
||||||
|
|
||||||
@rp-toolbar-height: 32px;
|
|
||||||
|
|
||||||
@rp-entry-animation-speed: 0.3s;
|
@rp-entry-animation-speed: 0.3s;
|
||||||
|
|
||||||
.rp-button() {
|
.rp-button() {
|
||||||
|
@ -64,12 +60,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-panel {
|
|
||||||
.rp-size-expanded & {
|
|
||||||
right: @review-panel-width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.review-panel-toolbar {
|
.review-panel-toolbar {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
|
@ -105,10 +95,6 @@
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.review-panel-toolbar-spinner {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rp-tc-state {
|
.rp-tc-state {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
|
@ -173,10 +159,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.rp-entry-list-inner {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rp-entry-indicator {
|
.rp-entry-indicator {
|
||||||
display: none;
|
display: none;
|
||||||
z-index: 2; // above .review-panel-toggler
|
z-index: 2; // above .review-panel-toggler
|
||||||
|
@ -752,11 +734,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.rp-loading {
|
|
||||||
text-align: center;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rp-nav {
|
.rp-nav {
|
||||||
display: none;
|
display: none;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
@ -806,18 +783,6 @@
|
||||||
font-size: @rp-base-font-size;
|
font-size: @rp-base-font-size;
|
||||||
}
|
}
|
||||||
|
|
||||||
#editor {
|
|
||||||
.rp-size-mini & {
|
|
||||||
right: @review-off-width;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rp-size-expanded & {
|
|
||||||
right: @review-panel-width;
|
|
||||||
left: 0px;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.review-icon {
|
.review-icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: url('../../../../public/img/ol-icons/review-icon-dark-theme.svg')
|
background: url('../../../../public/img/ol-icons/review-icon-dark-theme.svg')
|
||||||
|
@ -919,6 +884,7 @@ button when (@is-overleaf-light = true) {
|
||||||
}
|
}
|
||||||
|
|
||||||
.rp-collapse-toggle {
|
.rp-collapse-toggle {
|
||||||
|
.btn-inline-link;
|
||||||
color: @rp-type-blue;
|
color: @rp-type-blue;
|
||||||
font-weight: @rp-semibold-weight;
|
font-weight: @rp-semibold-weight;
|
||||||
|
|
||||||
|
@ -979,8 +945,8 @@ button when (@is-overleaf-light = true) {
|
||||||
}
|
}
|
||||||
|
|
||||||
.rp-size-expanded & {
|
.rp-size-expanded & {
|
||||||
&::after {
|
.review-panel-toggler-icon .fa {
|
||||||
content: '\f105';
|
transform: scale(0.7) rotate(180deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,20 +956,16 @@ button when (@is-overleaf-light = true) {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
.review-panel-toggler-icon {
|
||||||
content: '\f104';
|
|
||||||
font-family: FontAwesome;
|
|
||||||
line-height: 1;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
font-size: 16px;
|
|
||||||
display: block;
|
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
bottom: 50%;
|
bottom: 50%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
|
||||||
margin-top: -0.5em;
|
.fa {
|
||||||
|
font-size: 14px;
|
||||||
|
transform: scale(0.7);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1134,40 +1096,10 @@ button when (@is-overleaf-light = true) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.review-panel-indicator {
|
.track-changes-indicator-circle {
|
||||||
display: none;
|
display: inline-block;
|
||||||
}
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
.review-panel-mini {
|
border-radius: 100%;
|
||||||
width: 22px !important;
|
background-color: @ol-green;
|
||||||
overflow: visible !important;
|
|
||||||
|
|
||||||
.rp-entry {
|
|
||||||
height: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rp-entry-indicator {
|
|
||||||
position: absolute;
|
|
||||||
left: -6px;
|
|
||||||
right: 0;
|
|
||||||
display: flex;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rp-entry-content {
|
|
||||||
display: none;
|
|
||||||
background: white;
|
|
||||||
border: 1px solid @rp-border-grey;
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rp-entry:hover {
|
|
||||||
.rp-entry-content {
|
|
||||||
display: initial;
|
|
||||||
position: absolute;
|
|
||||||
left: -206px;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,3 +143,33 @@
|
||||||
--link-hover-color: var(--link-hover-color-dark);
|
--link-hover-color: var(--link-hover-color-dark);
|
||||||
--link-visited-color: var(--link-visited-color-dark);
|
--link-visited-color: var(--link-visited-color-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin triangle($direction, $width, $height, $color) {
|
||||||
|
position: absolute;
|
||||||
|
border-color: transparent;
|
||||||
|
border-style: solid;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
|
||||||
|
@if $direction == top {
|
||||||
|
border-width: 0 calc(#{$width} / 2) #{$height} calc(#{$width} / 2);
|
||||||
|
border-bottom-color: $color;
|
||||||
|
border-left-color: transparent;
|
||||||
|
border-right-color: transparent;
|
||||||
|
} @else if $direction == bottom {
|
||||||
|
border-width: #{$height} calc(#{$width} / 2) 0 calc(#{$width} / 2);
|
||||||
|
border-top-color: $color;
|
||||||
|
border-left-color: transparent;
|
||||||
|
border-right-color: transparent;
|
||||||
|
} @else if $direction == right {
|
||||||
|
border-width: calc(#{$height} / 2) 0 calc(#{$height} / 2) #{$width};
|
||||||
|
border-left-color: $color;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
} @else if $direction == left {
|
||||||
|
border-width: calc(#{$height} / 2) #{$width} calc(#{$height} / 2) 0;
|
||||||
|
border-right-color: $color;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
.loading {
|
.loading {
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
.spinner-border-sm,
|
.spinner-border-sm,
|
||||||
.spinner-border {
|
.spinner-border {
|
||||||
// Ensure the thickness of the spinner is independent of the font size of its container
|
// Ensure the thickness of the spinner is independent of the font size of its container
|
||||||
|
|
|
@ -294,8 +294,8 @@ $editor-toggler-bg-dark-color: color.adjust(
|
||||||
}
|
}
|
||||||
|
|
||||||
.teaser-video-container {
|
.teaser-video-container {
|
||||||
margin: calc(var(--spacing-07) * -1) calc(var(--spacing-07) * -1)
|
margin: calc(var(--bs-modal-padding) * -1) calc(var(--bs-modal-padding) * -1)
|
||||||
var(--spacing-02) calc(var(--spacing-07) * -1);
|
var(--spacing-02) calc(var(--bs-modal-padding) * -1);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -84,3 +84,11 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.d-flex {
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-content-center {
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue