mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 21:23:45 +01:00
Merge pull request #34681 from overleaf/mfb-34187-move-editor-switch-to-right-hand
Introduce shared ToolbarLayout component and move editor switch to right in bibtex visual toolbar GitOrigin-RevId: 5f61bf8144dc68dfb4adce8a03d43c2dd0de3369
This commit is contained in:
committed by
Copybot
parent
f30c23cacc
commit
b93d180ee9
@@ -76,12 +76,10 @@ function CodeMirrorEditor() {
|
||||
return (
|
||||
<CodeMirrorStateContext.Provider value={state}>
|
||||
<CodeMirrorViewContext.Provider value={viewRef.current}>
|
||||
<CodeMirrorEditorComponents hidden={VisualEditor != null} />
|
||||
{VisualEditor && (
|
||||
<Suspense fallback={null}>
|
||||
<VisualEditor />
|
||||
</Suspense>
|
||||
)}
|
||||
<CodeMirrorEditorComponents
|
||||
hidden={VisualEditor != null}
|
||||
VisualEditor={VisualEditor}
|
||||
/>
|
||||
</CodeMirrorViewContext.Provider>
|
||||
</CodeMirrorStateContext.Provider>
|
||||
)
|
||||
@@ -89,10 +87,12 @@ function CodeMirrorEditor() {
|
||||
|
||||
type CodeMirrorEditorComponentsProps = {
|
||||
hidden: boolean
|
||||
VisualEditor: ElementType | null
|
||||
}
|
||||
|
||||
function CodeMirrorEditorComponents({
|
||||
hidden = false,
|
||||
VisualEditor,
|
||||
}: CodeMirrorEditorComponentsProps) {
|
||||
useToolbarMenuBarEditorCommands()
|
||||
const { features } = useProjectContext()
|
||||
@@ -132,6 +132,11 @@ function CodeMirrorEditorComponents({
|
||||
<Component key={path} />
|
||||
)
|
||||
)}
|
||||
{VisualEditor && (
|
||||
<Suspense fallback={null}>
|
||||
<VisualEditor />
|
||||
</Suspense>
|
||||
)}
|
||||
</ReviewPanelProviders>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -17,9 +17,6 @@ import { ToolbarOverflow } from './toolbar/overflow'
|
||||
import useDropdown from '../../../shared/hooks/use-dropdown'
|
||||
import { getPanel } from '@codemirror/view'
|
||||
import { createToolbarPanel } from '../extensions/toolbar/toolbar-panel'
|
||||
import EditorSwitch from './editor-switch'
|
||||
import ReviewModeSwitcher from '@/features/review-panel/components/review-mode-switcher'
|
||||
import SwitchToPDFButton from './switch-to-pdf-button'
|
||||
import { DetacherSynctexControl } from '../../pdf-preview/components/detach-synctex-control'
|
||||
import DetachCompileButtonWrapper from '../../pdf-preview/components/detach-compile-button-wrapper'
|
||||
import { isVisual } from '../extensions/visual/visual'
|
||||
@@ -27,31 +24,21 @@ import { language } from '@codemirror/language'
|
||||
import { minimumListDepthForSelection } from '../utils/tree-operations/ancestors'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ToggleSearchButton } from '@/features/source-editor/components/toolbar/toggle-search-button'
|
||||
import ReviewPanelHeader from '@/features/review-panel/components/review-panel-header'
|
||||
import useReviewPanelLayout from '@/features/review-panel/hooks/use-review-panel-layout'
|
||||
import Breadcrumbs from '@/features/source-editor/extensions/breadcrumbs'
|
||||
import classNames from 'classnames'
|
||||
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import { useProjectContext } from '@/shared/context/project-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'
|
||||
import { useAreTabsEnabled } from '@/features/ide-react/hooks/use-are-tabs-enabled'
|
||||
|
||||
const sourceEditorToolbarStartButtons = importOverleafModules(
|
||||
'sourceEditorToolbarStartButtons'
|
||||
) as { import: { default: ElementType }; path: string }[]
|
||||
import { ToolbarLayout } from './toolbar/toolbar-layout'
|
||||
|
||||
const sourceEditorToolbarComponents = importOverleafModules(
|
||||
'sourceEditorToolbarComponents'
|
||||
) as { import: { default: ElementType }; path: string }[]
|
||||
|
||||
const sourceEditorToolbarEndButtons = importOverleafModules(
|
||||
'sourceEditorToolbarEndButtons'
|
||||
) as { import: { default: ElementType }; path: string }[]
|
||||
|
||||
export const CodeMirrorToolbar = () => {
|
||||
const view = useCodeMirrorViewContext()
|
||||
const panel = getPanel(view, createToolbarPanel)
|
||||
@@ -70,9 +57,6 @@ const Toolbar = memo(function Toolbar() {
|
||||
const {
|
||||
userSettings: { breadcrumbs },
|
||||
} = useUserSettingsContext()
|
||||
const visualPreviewEnabled = useFeatureFlag('visual-preview')
|
||||
const isToolbarMigration = useFeatureFlag('writefull-toolbar-migration')
|
||||
const { features } = useProjectContext()
|
||||
const { focusMode } = useLayoutContext()
|
||||
|
||||
const [overflowed, setOverflowed] = useState(false)
|
||||
@@ -202,21 +186,19 @@ const Toolbar = memo(function Toolbar() {
|
||||
className="ol-cm-toolbar toolbar-editor"
|
||||
ref={handleToolbar}
|
||||
>
|
||||
{showActions &&
|
||||
sourceEditorToolbarStartButtons.map(
|
||||
({ import: { default: Component }, path }) => (
|
||||
<Component key={path} />
|
||||
)
|
||||
<ToolbarLayout.Left
|
||||
canEdit={!state.readOnly}
|
||||
showActions={showActions}
|
||||
>
|
||||
{showActions && (
|
||||
<ToolbarItems
|
||||
state={state}
|
||||
languageName={languageName}
|
||||
visual={visual}
|
||||
listDepth={listDepth}
|
||||
/>
|
||||
)}
|
||||
{showActions && (
|
||||
<ToolbarItems
|
||||
state={state}
|
||||
languageName={languageName}
|
||||
visual={visual}
|
||||
listDepth={listDepth}
|
||||
/>
|
||||
)}
|
||||
|
||||
</ToolbarLayout.Left>
|
||||
<div className="ol-cm-toolbar-button-group ol-cm-toolbar-stretch">
|
||||
{showActions && (
|
||||
<ToolbarOverflow
|
||||
@@ -235,26 +217,10 @@ const Toolbar = memo(function Toolbar() {
|
||||
</ToolbarOverflow>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="ol-cm-toolbar-button-group ol-cm-toolbar-end">
|
||||
{!visualPreviewEnabled && <EditorSwitch />}
|
||||
{/* trackChangesVisible controls provider/UI availability; trackChanges
|
||||
(checked inside the switcher) controls the actual feature entitlement.
|
||||
Users with trackChangesVisible:true but trackChanges:false see the
|
||||
switcher and get an upgrade modal when clicking "Reviewing". */}
|
||||
{isToolbarMigration && features.trackChangesVisible && (
|
||||
<ReviewModeSwitcher />
|
||||
)}
|
||||
{sourceEditorToolbarEndButtons.map(
|
||||
({ import: { default: Component }, path }) => (
|
||||
<Component key={path} />
|
||||
)
|
||||
)}
|
||||
<ToggleSearchButton state={state} />
|
||||
<SwitchToPDFButton />
|
||||
<ToolbarLayout.Right canSearchInFile={true}>
|
||||
<DetacherSynctexControl />
|
||||
<DetachCompileButtonWrapper />
|
||||
</div>
|
||||
</ToolbarLayout.Right>
|
||||
</div>
|
||||
{sourceEditorToolbarComponents.map(
|
||||
({ import: { default: Component }, path }) => (
|
||||
|
||||
@@ -2,7 +2,6 @@ import { ComponentType, FC, memo } from 'react'
|
||||
import { EditorState } from '@codemirror/state'
|
||||
import { useEditorContext } from '../../../../shared/context/editor-context'
|
||||
import { ToolbarButton } from './toolbar-button'
|
||||
import { redo, undo } from '@codemirror/commands'
|
||||
import * as commands from '../../extensions/toolbar/commands'
|
||||
import { SectionHeadingDropdown } from './section-heading-dropdown'
|
||||
import getMeta from '../../../../utils/meta'
|
||||
@@ -57,27 +56,6 @@ export const ToolbarItems: FC<{
|
||||
|
||||
return (
|
||||
<>
|
||||
{showGroup('group-history') && (
|
||||
<div
|
||||
className="ol-cm-toolbar-button-group"
|
||||
aria-label={t('toolbar_undo_redo_actions')}
|
||||
>
|
||||
<ToolbarButton
|
||||
id="toolbar-undo"
|
||||
label={t('toolbar_undo')}
|
||||
command={undo}
|
||||
icon="undo"
|
||||
shortcut={isMac ? '⌘Z' : 'Ctrl+Z'}
|
||||
/>
|
||||
<ToolbarButton
|
||||
id="toolbar-redo"
|
||||
label={t('toolbar_redo')}
|
||||
command={redo}
|
||||
icon="redo"
|
||||
shortcut={isMac ? '⇧⌘Z' : 'Ctrl+Y'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{sourceEditorToolbarButtonGroups.map(
|
||||
({ import: { default: Component, overflowGroupId }, path }) =>
|
||||
showGroup(overflowGroupId) && <Component key={path} />
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
import { ReactNode, ElementType } from 'react'
|
||||
import '../../../../../stylesheets/components/editor-toolbar.scss'
|
||||
import { ToolbarButton } from './toolbar-button'
|
||||
import { undo, redo } from '@codemirror/commands'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { isMac } from '@/shared/utils/os'
|
||||
import { useCodeMirrorStateContext } from '@/features/source-editor/components/codemirror-context'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
import EditorSwitch from '@/features/source-editor/components/editor-switch'
|
||||
import ReviewModeSwitcher from '@/features/review-panel/components/review-mode-switcher'
|
||||
import { ToggleSearchButton } from './toggle-search-button'
|
||||
import SwitchToPDFButton from '../switch-to-pdf-button'
|
||||
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
type ToolbarLayoutProps = {
|
||||
children: ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
type ToolbarLayoutLeftProps = {
|
||||
children?: ReactNode
|
||||
canEdit?: boolean
|
||||
showActions?: boolean
|
||||
}
|
||||
|
||||
type ToolbarLayoutRightProps = {
|
||||
canSearchInFile?: boolean
|
||||
canUseWritefull?: boolean
|
||||
children?: ReactNode
|
||||
}
|
||||
|
||||
const sourceEditorToolbarEndButtons = importOverleafModules(
|
||||
'sourceEditorToolbarEndButtons'
|
||||
) as { import: { default: ElementType }; path: string }[]
|
||||
|
||||
const sourceEditorToolbarStartButtons = importOverleafModules(
|
||||
'sourceEditorToolbarStartButtons'
|
||||
) as { import: { default: ElementType }; path: string }[]
|
||||
|
||||
function Left({ children, canEdit, showActions }: ToolbarLayoutLeftProps) {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className="ol-toolbar-layout-left">
|
||||
{showActions &&
|
||||
sourceEditorToolbarStartButtons.map(
|
||||
({ import: { default: Component }, path }) => <Component key={path} />
|
||||
)}
|
||||
{canEdit && (
|
||||
<div
|
||||
className="ol-editor-toolbar-button-group"
|
||||
aria-label={t('toolbar_undo_redo_actions')}
|
||||
>
|
||||
<ToolbarButton
|
||||
id="toolbar-undo"
|
||||
label={t('toolbar_undo')}
|
||||
command={undo}
|
||||
icon="undo"
|
||||
shortcut={isMac ? '⌘Z' : 'Ctrl+Z'}
|
||||
/>
|
||||
<ToolbarButton
|
||||
id="toolbar-redo"
|
||||
label={t('toolbar_redo')}
|
||||
command={redo}
|
||||
icon="redo"
|
||||
shortcut={isMac ? '⇧⌘Z' : 'Ctrl+Y'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Right({
|
||||
canSearchInFile,
|
||||
canUseWritefull = true,
|
||||
children,
|
||||
}: ToolbarLayoutRightProps) {
|
||||
const state = useCodeMirrorStateContext()
|
||||
const visualPreviewEnabled = useFeatureFlag('visual-preview')
|
||||
const isToolbarMigration = useFeatureFlag('writefull-toolbar-migration')
|
||||
const { features } = useProjectContext()
|
||||
return (
|
||||
<div className="ol-toolbar-layout-right">
|
||||
{!visualPreviewEnabled && <EditorSwitch />}
|
||||
{/* trackChangesVisible controls provider/UI availability; trackChanges
|
||||
(checked inside the switcher) controls the actual feature entitlement.
|
||||
Users with trackChangesVisible:true but trackChanges:false see the
|
||||
switcher and get an upgrade modal when clicking "Reviewing". */}
|
||||
{isToolbarMigration &&
|
||||
canUseWritefull !== false &&
|
||||
features.trackChangesVisible && <ReviewModeSwitcher />}
|
||||
{!isToolbarMigration && (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
visibility: canUseWritefull ? 'visible' : 'hidden',
|
||||
}}
|
||||
>
|
||||
{sourceEditorToolbarEndButtons.map(
|
||||
({ import: { default: Component }, path }) => (
|
||||
<Component key={path} />
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
visibility: canSearchInFile ? 'visible' : 'hidden',
|
||||
}}
|
||||
>
|
||||
<ToggleSearchButton state={state} />
|
||||
</div>
|
||||
<SwitchToPDFButton />
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
type ToolbarLayoutCompoundComponent = ((
|
||||
props: ToolbarLayoutProps
|
||||
) => JSX.Element) & {
|
||||
Left: typeof Left
|
||||
Right: typeof Right
|
||||
}
|
||||
|
||||
export const ToolbarLayout = (({ children, className }: ToolbarLayoutProps) => (
|
||||
<div className={className}>{children}</div>
|
||||
)) as ToolbarLayoutCompoundComponent
|
||||
|
||||
ToolbarLayout.Left = Left
|
||||
ToolbarLayout.Right = Right
|
||||
@@ -0,0 +1,78 @@
|
||||
.ol-editor-toolbar-button-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
padding: 0 4px;
|
||||
margin: 4px 0;
|
||||
line-height: 1;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-left: 1px solid rgb(125 125 125 / 30%);
|
||||
}
|
||||
|
||||
.ol-cm-toolbar-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
margin: 0 1px;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: var(--border-radius-base);
|
||||
line-height: 1;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
overflow: hidden;
|
||||
color: inherit;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active,
|
||||
&.active {
|
||||
background-color: rgb(125 125 125 / 10%);
|
||||
color: inherit;
|
||||
box-shadow: none;
|
||||
|
||||
&[aria-disabled='true'] {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
&.active,
|
||||
&:active {
|
||||
background-color: rgb(125 125 125 / 20%);
|
||||
}
|
||||
|
||||
&[aria-disabled='true'] {
|
||||
opacity: 0.2;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ol-cm-toolbar-wrapper-needs-border
|
||||
.ol-editor-toolbar-button-group:first-child {
|
||||
border-left: 1px solid rgb(125 125 125 / 30%);
|
||||
}
|
||||
|
||||
.ol-toolbar-layout-right {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.ol-cm-toolbar-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
margin: 0 1px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.ol-toolbar-layout-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
Reference in New Issue
Block a user