mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 06:33:55 +01:00
Merge pull request #34311 from overleaf/mj-review-panel-with-tabs
[web] Move review panel header into tabs row when open GitOrigin-RevId: e4594040f7a8ca67778fdd3e31cab909b3120adb
This commit is contained in:
committed by
Copybot
parent
aed97f025c
commit
1a7b5e66f5
@@ -58,6 +58,8 @@ const TabsContext = React.createContext<
|
||||
setContextMenuTarget: React.Dispatch<
|
||||
React.SetStateAction<TabsContextMenuTarget | null>
|
||||
>
|
||||
headerSlot: HTMLElement | null
|
||||
setHeaderSlot: React.Dispatch<React.SetStateAction<HTMLElement | null>>
|
||||
}
|
||||
| undefined
|
||||
>(undefined)
|
||||
@@ -80,6 +82,8 @@ export const TabsProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const [contextMenuTarget, setContextMenuTarget] =
|
||||
useState<TabsContextMenuTarget | null>(null)
|
||||
|
||||
const [headerSlot, setHeaderSlot] = useState<HTMLElement | null>(null)
|
||||
|
||||
const tabs = useMemo(() => {
|
||||
if (!tabsEnabled) {
|
||||
return []
|
||||
@@ -297,6 +301,8 @@ export const TabsProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
contextMenuTarget,
|
||||
setContextMenuTarget,
|
||||
closeToRight,
|
||||
headerSlot,
|
||||
setHeaderSlot,
|
||||
}),
|
||||
[
|
||||
tabs,
|
||||
@@ -308,6 +314,8 @@ export const TabsProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
contextMenuTarget,
|
||||
setContextMenuTarget,
|
||||
closeToRight,
|
||||
headerSlot,
|
||||
setHeaderSlot,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import { FC, memo } from 'react'
|
||||
|
||||
const ReviewPanelHeaderBuffer: FC = () => {
|
||||
return <div className="review-panel-header" aria-hidden />
|
||||
}
|
||||
|
||||
export default memo(ReviewPanelHeaderBuffer)
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import { FC } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import ReviewPanelHeader from './review-panel-header'
|
||||
import { useTabsContext } from '@/features/ide-react/context/tabs-context'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import useReviewPanelLayout from '../hooks/use-review-panel-layout'
|
||||
|
||||
const ReviewPanelTabsHeaderPortal: FC = () => {
|
||||
const editorTabsEnabled = useFeatureFlag('editor-tabs')
|
||||
const { headerSlot } = useTabsContext()
|
||||
const { showHeader } = useReviewPanelLayout()
|
||||
|
||||
if (!editorTabsEnabled || !headerSlot || !showHeader) {
|
||||
return null
|
||||
}
|
||||
|
||||
return createPortal(<ReviewPanelHeader />, headerSlot)
|
||||
}
|
||||
|
||||
export default ReviewPanelTabsHeaderPortal
|
||||
@@ -11,6 +11,7 @@ import importOverleafModules from '../../../../macros/import-overleaf-module.mac
|
||||
import { FigureModal } from './figure-modal/figure-modal'
|
||||
import { ReviewPanelProviders } from '@/features/review-panel/context/review-panel-providers'
|
||||
import { ReviewPanelRoot } from '@/features/review-panel/components/review-panel-root'
|
||||
import ReviewPanelTabsHeaderPortal from '@/features/review-panel/components/review-panel-tabs-header-portal'
|
||||
import ReviewTooltipMenu from '@/features/review-panel/components/review-tooltip-menu'
|
||||
import {
|
||||
CodeMirrorStateContext,
|
||||
@@ -104,6 +105,7 @@ function CodeMirrorEditorComponents({
|
||||
<MathPreviewTooltip />
|
||||
<EditorContextMenu />
|
||||
{features.trackChangesVisible && <ReviewTooltipMenu />}
|
||||
{features.trackChangesVisible && <ReviewPanelTabsHeaderPortal />}
|
||||
{features.trackChangesVisible && <ReviewPanelRoot />}
|
||||
{features.trackChangesVisible && <UpgradeTrackChangesModal />}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import { useUserSettingsContext } from '@/shared/context/user-settings-context'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
||||
import { useLayoutContext } from '@/shared/context/layout-context'
|
||||
import ReviewPanelHeaderBuffer from '@/features/review-panel/components/review-panel-header-buffer'
|
||||
|
||||
const sourceEditorToolbarComponents = importOverleafModules(
|
||||
'sourceEditorToolbarComponents'
|
||||
@@ -159,6 +160,7 @@ const Toolbar = memo(function Toolbar() {
|
||||
}, [buildOverflow, insideTable, resizeRef])
|
||||
|
||||
const showActions = !state.readOnly && !insideTable
|
||||
const tabsVisible = useFeatureFlag('editor-tabs')
|
||||
|
||||
if (focusMode) {
|
||||
return null
|
||||
@@ -166,7 +168,8 @@ const Toolbar = memo(function Toolbar() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{showReviewPanelHeader && <ReviewPanelHeader />}
|
||||
{showReviewPanelHeader &&
|
||||
(tabsVisible ? <ReviewPanelHeaderBuffer /> : <ReviewPanelHeader />)}
|
||||
<div
|
||||
id="ol-cm-toolbar-wrapper"
|
||||
className={classNames('ol-cm-toolbar-wrapper', {
|
||||
|
||||
@@ -19,6 +19,7 @@ export const TabsContainer = () => {
|
||||
moveTab,
|
||||
makeTabPermanent,
|
||||
setContextMenuTarget,
|
||||
setHeaderSlot,
|
||||
} = useTabsContext()
|
||||
const { openEntity } = useFileTreeOpenContext()
|
||||
const [hovered, setHovered] = useState<boolean>(false)
|
||||
@@ -87,6 +88,7 @@ export const TabsContainer = () => {
|
||||
|
||||
return (
|
||||
<div className="editor-tabs-container">
|
||||
<div className="review-panel-header-slot" ref={setHeaderSlot} />
|
||||
<div
|
||||
className={classNames('editor-tabs-row', {
|
||||
'editor-tabs-row-hovered': hovered,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
:root {
|
||||
--editor-tab-max-path-length: 250px;
|
||||
--editor-tab-divider-color: var(--neutral-70);
|
||||
--editor-tab-row-height: var(--review-panel-header-height, 36px);
|
||||
}
|
||||
|
||||
@include theme('light') {
|
||||
@@ -11,11 +12,15 @@
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--spacing-02);
|
||||
flex: 0 0 auto;
|
||||
min-height: var(--editor-tab-row-height);
|
||||
background: var(--bg-secondary-themed);
|
||||
justify-content: space-between;
|
||||
|
||||
.review-panel-header-slot {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.editor-tabs-labs-icon {
|
||||
flex: 0 0 auto;
|
||||
padding: 0 var(--spacing-02);
|
||||
@@ -29,6 +34,7 @@
|
||||
.editor-tabs-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: var(--editor-tab-row-height);
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
@@ -47,6 +53,7 @@
|
||||
--tab-bg-color: var(--bg-secondary-themed);
|
||||
--tab-text-color: var(--content-secondary-themed);
|
||||
|
||||
display: flex;
|
||||
border-right: 1px solid var(--editor-tab-divider-color);
|
||||
border-left: 1px solid transparent;
|
||||
padding: var(--spacing-01) var(--spacing-02) 0 var(--spacing-02);
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
import { EditorView } from '@codemirror/view'
|
||||
import { EditorState, Transaction } from '@codemirror/state'
|
||||
import { tabsListener } from '@/features/source-editor/extensions/tabs-listener'
|
||||
import ReviewPanelTabsHeaderPortal from '@/features/review-panel/components/review-panel-tabs-header-portal'
|
||||
|
||||
const DOC_IDS = {
|
||||
main: 'doc-main-id',
|
||||
@@ -247,6 +248,7 @@ describe('File Tabs', function () {
|
||||
>
|
||||
<FileSelectionDriver />
|
||||
<TabsContainer />
|
||||
<ReviewPanelTabsHeaderPortal />
|
||||
<RemoteChangeButton />
|
||||
</EditorProviders>
|
||||
)
|
||||
@@ -1158,6 +1160,41 @@ describe('File Tabs', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('Review panel header', function () {
|
||||
function toggleReviewPanel() {
|
||||
cy.window().then(win => {
|
||||
win.dispatchEvent(new win.CustomEvent('ui.toggle-review-panel'))
|
||||
})
|
||||
}
|
||||
|
||||
it('does not render the review panel header when the review panel is closed', function () {
|
||||
cy.then(() => selectDoc(DOC_IDS.main))
|
||||
|
||||
cy.findByRole('heading', { name: 'Review' }).should('not.exist')
|
||||
})
|
||||
|
||||
it('renders the review panel header inside the tabs container when the review panel is open', function () {
|
||||
cy.then(() => selectDoc(DOC_IDS.main))
|
||||
|
||||
toggleReviewPanel()
|
||||
|
||||
cy.get('.editor-tabs-container').within(() => {
|
||||
cy.findByRole('heading', { name: 'Review' }).should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
it('removes the review panel header when the review panel is closed again', function () {
|
||||
cy.then(() => selectDoc(DOC_IDS.main))
|
||||
|
||||
toggleReviewPanel()
|
||||
cy.findByRole('heading', { name: 'Review' }).should('exist')
|
||||
|
||||
toggleReviewPanel()
|
||||
|
||||
cy.findByRole('heading', { name: 'Review' }).should('not.exist')
|
||||
})
|
||||
})
|
||||
|
||||
describe('SplitTestBadge', function () {
|
||||
it('renders the labs badge icon in the tabs container', function () {
|
||||
cy.window().then(win => {
|
||||
|
||||
Reference in New Issue
Block a user