mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[cm6] Add toolbar to Source Mode for Beta users (#13429)
* [cm6] toolbar for source mode * top:0 for new toolbar * empty div for extensions * fix legacy css top pos * show source toolbar split test * prettier * show beta icon in source editor * dropdown toolbar wip * fix wrong conflict resolve * math dropdown, chrome extension fixes * math dropdown cleanup * sort en.json * fix sort en.json * using isVisual * getMeta in component, pug update * using flex grow * toolbar beta badge * remove extra whitespace * has-legacy-toolbar class * Increase container size * fix tests * prettier * styling fixes, using SplitTestBadge * only show source toolbar if flag is set * fix typo --------- Co-authored-by: Alf Eaton <alf.eaton@overleaf.com> GitOrigin-RevId: 34b01a9421f4a0d6defc40925c5092901575946e
This commit is contained in:
parent
a14e2aecfb
commit
17452b51d7
21 changed files with 357 additions and 88 deletions
|
@ -683,6 +683,21 @@ const ProjectController = {
|
|||
cb()
|
||||
})
|
||||
},
|
||||
sourceEditorToolbarAssigment(cb) {
|
||||
SplitTestHandler.getAssignment(
|
||||
req,
|
||||
res,
|
||||
'source-editor-toolbar',
|
||||
(error, assignment) => {
|
||||
// do not fail editor load if assignment fails
|
||||
if (error) {
|
||||
cb(null, { variant: 'default' })
|
||||
} else {
|
||||
cb(null, assignment)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
historyViewAssignment(cb) {
|
||||
SplitTestHandler.getAssignment(
|
||||
req,
|
||||
|
@ -729,6 +744,7 @@ const ProjectController = {
|
|||
pdfjsAssignment,
|
||||
editorLeftMenuAssignment,
|
||||
richTextAssignment,
|
||||
sourceEditorToolbarAssigment,
|
||||
historyViewAssignment,
|
||||
reviewPanelAssignment,
|
||||
}
|
||||
|
@ -919,6 +935,9 @@ const ProjectController = {
|
|||
pdfjsVariant: pdfjsAssignment.variant,
|
||||
debugPdfDetach,
|
||||
showLegacySourceEditor,
|
||||
showSourceToolbar:
|
||||
!showLegacySourceEditor &&
|
||||
sourceEditorToolbarAssigment.variant === 'enabled',
|
||||
showSymbolPalette,
|
||||
galileoEnabled,
|
||||
galileoFeatures,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
include ./file-view
|
||||
|
||||
.editor-container.full-size(
|
||||
class={"has-source-toolbar" : showSourceToolbar},
|
||||
ng-show="ui.view == 'editor' && editor.multiSelectedCount === 0"
|
||||
vertical-resizable-panes="south-pane-resizer"
|
||||
vertical-resizable-panes-hidden-externally-on="south-pane-toggled"
|
||||
|
|
|
@ -22,6 +22,7 @@ meta(name="ol-wsRetryHandshake" data-type="json" content=settings.wsRetryHandsha
|
|||
meta(name="ol-pdfjsVariant" content=pdfjsVariant)
|
||||
meta(name="ol-debugPdfDetach" data-type="boolean" content=debugPdfDetach)
|
||||
meta(name="ol-showLegacySourceEditor", data-type="boolean" content=showLegacySourceEditor)
|
||||
meta(name="ol-showSourceToolbar", data-type="boolean" content=showSourceToolbar)
|
||||
meta(name="ol-showSymbolPalette" data-type="boolean" content=showSymbolPalette)
|
||||
meta(name="ol-galileoEnabled" data-type="string" content=galileoEnabled)
|
||||
meta(name="ol-galileoPromptWords" data-type="string" content=galileoPromptWords)
|
||||
|
|
|
@ -1016,6 +1016,7 @@
|
|||
"toolbar_insert_figure": "",
|
||||
"toolbar_insert_inline_math": "",
|
||||
"toolbar_insert_link": "",
|
||||
"toolbar_insert_math": "",
|
||||
"toolbar_insert_table": "",
|
||||
"toolbar_numbered_list": "",
|
||||
"toolbar_redo": "",
|
||||
|
|
|
@ -13,6 +13,13 @@ 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 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 getMeta from '../../../utils/meta'
|
||||
import { isVisual } from '../extensions/visual/visual'
|
||||
import SplitTestBadge from '../../../shared/components/split-test-badge'
|
||||
|
||||
export const CodeMirrorToolbar = () => {
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
@ -26,7 +33,10 @@ export const CodeMirrorToolbar = () => {
|
|||
}
|
||||
|
||||
const Toolbar = memo(function Toolbar() {
|
||||
const showSourceToolbar: boolean = getMeta('ol-showSourceToolbar')
|
||||
|
||||
const state = useCodeMirrorStateContext()
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
||||
const [overflowed, setOverflowed] = useState(false)
|
||||
const [collapsed, setCollapsed] = useState(false)
|
||||
|
@ -85,9 +95,13 @@ const Toolbar = memo(function Toolbar() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="ol-cm-toolbar" ref={resizeRef}>
|
||||
<div className="ol-cm-toolbar toolbar-editor" ref={resizeRef}>
|
||||
{showSourceToolbar && <EditorSwitch />}
|
||||
<ToolbarItems state={state} />
|
||||
<div className="ol-cm-toolbar-button-group" ref={overflowBeforeRef}>
|
||||
<div
|
||||
className="ol-cm-toolbar-button-group ol-cm-toolbar-stretch"
|
||||
ref={overflowBeforeRef}
|
||||
>
|
||||
<ToolbarOverflow
|
||||
overflowed={overflowed}
|
||||
target={overflowBeforeRef.current ?? undefined}
|
||||
|
@ -97,6 +111,7 @@ const Toolbar = memo(function Toolbar() {
|
|||
>
|
||||
<ToolbarItems state={state} overflowed={overflowedItemsRef.current} />
|
||||
</ToolbarOverflow>
|
||||
<div className="formatting-buttons-wrapper" />
|
||||
</div>
|
||||
<div className="ol-cm-toolbar-button-group ol-cm-toolbar-end">
|
||||
<ToolbarButton
|
||||
|
@ -106,6 +121,19 @@ const Toolbar = memo(function Toolbar() {
|
|||
active={searchPanelOpen(state)}
|
||||
icon="search"
|
||||
/>
|
||||
{!isVisual(view) && (
|
||||
<SplitTestBadge
|
||||
splitTestName="source-editor-toolbar"
|
||||
displayOnVariants={['enabled']}
|
||||
/>
|
||||
)}
|
||||
{showSourceToolbar && (
|
||||
<>
|
||||
<SwitchToPDFButton />
|
||||
<DetacherSynctexControl />
|
||||
<DetachCompileButtonWrapper />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="ol-cm-toolbar-button-group hidden">
|
||||
<ToolbarButton
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
import { ChangeEvent, FC, memo, useCallback } from 'react'
|
||||
import useScopeValue from '../../../shared/hooks/use-scope-value'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import { sendMB } from '../../../infrastructure/event-tracking'
|
||||
import getMeta from '../../../utils/meta'
|
||||
import SplitTestBadge from '../../../shared/components/split-test-badge'
|
||||
import isValidTeXFile from '../../../main/is-valid-tex-file'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
function Badge() {
|
||||
const content = (
|
||||
<>
|
||||
Overleaf has upgraded the source editor. You can still use the old editor
|
||||
by selecting "Source (legacy)".
|
||||
<br />
|
||||
<br />
|
||||
Click to learn more and give feedback
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
id="editor-switch"
|
||||
description={content}
|
||||
overlayProps={{
|
||||
placement: 'bottom',
|
||||
delayHide: 100,
|
||||
}}
|
||||
tooltipProps={{ className: 'tooltip-wide' }}
|
||||
>
|
||||
<a
|
||||
href="https://forms.gle/GmSs6odZRKRp3VX98"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="info-badge"
|
||||
>
|
||||
<span className="sr-only">{content}</span>
|
||||
</a>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
const showLegacySourceEditor: boolean = getMeta('ol-showLegacySourceEditor')
|
||||
const visualEditorNameVariant: string = getMeta('ol-visualEditorNameVariant')
|
||||
const isParticipatingInVisualEditorNamingTest: boolean = getMeta(
|
||||
'ol-isParticipatingInVisualEditorNamingTest'
|
||||
)
|
||||
|
||||
function EditorSwitch() {
|
||||
const [newSourceEditor, setNewSourceEditor] = useScopeValue(
|
||||
'editor.newSourceEditor'
|
||||
)
|
||||
const [richText, setRichText] = useScopeValue('editor.showRichText')
|
||||
const sourceName =
|
||||
visualEditorNameVariant === 'code-visual'
|
||||
? 'Code Editor'
|
||||
: visualEditorNameVariant === 'source-visual'
|
||||
? 'Source Editor'
|
||||
: 'Source'
|
||||
|
||||
const [visual, setVisual] = useScopeValue('editor.showVisual')
|
||||
|
||||
const [docName] = useScopeValue('editor.open_doc_name')
|
||||
const richTextAvailable = isValidTeXFile(docName)
|
||||
const richTextOrVisual = richText || (richTextAvailable && visual)
|
||||
|
||||
const handleChange = useCallback(
|
||||
event => {
|
||||
const editorType = event.target.value
|
||||
|
||||
switch (editorType) {
|
||||
case 'ace':
|
||||
setRichText(false)
|
||||
setVisual(false)
|
||||
setNewSourceEditor(false)
|
||||
break
|
||||
|
||||
case 'cm6':
|
||||
setRichText(false)
|
||||
setVisual(false)
|
||||
setNewSourceEditor(true)
|
||||
break
|
||||
|
||||
case 'rich-text':
|
||||
if (getMeta('ol-richTextVariant') === 'cm6') {
|
||||
setRichText(false)
|
||||
setVisual(true)
|
||||
setNewSourceEditor(true)
|
||||
} else {
|
||||
setRichText(true)
|
||||
setVisual(false)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
sendMB('editor-switch-change', { editorType })
|
||||
},
|
||||
[setRichText, setVisual, setNewSourceEditor]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="editor-toggle-switch">
|
||||
{showLegacySourceEditor ? <Badge /> : null}
|
||||
|
||||
<fieldset className="toggle-switch">
|
||||
<legend className="sr-only">Editor mode.</legend>
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
name="editor"
|
||||
value="cm6"
|
||||
id="editor-switch-cm6"
|
||||
className="toggle-switch-input"
|
||||
checked={!richTextOrVisual && !!newSourceEditor}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<label htmlFor="editor-switch-cm6" className="toggle-switch-label">
|
||||
<span>{sourceName}</span>
|
||||
</label>
|
||||
|
||||
{showLegacySourceEditor ? (
|
||||
<>
|
||||
<input
|
||||
type="radio"
|
||||
name="editor"
|
||||
value="ace"
|
||||
id="editor-switch-ace"
|
||||
className="toggle-switch-input"
|
||||
checked={!richTextOrVisual && !newSourceEditor}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<label htmlFor="editor-switch-ace" className="toggle-switch-label">
|
||||
<span>Source (legacy)</span>
|
||||
</label>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<RichTextToggle
|
||||
checked={!!richTextOrVisual}
|
||||
disabled={!richTextAvailable}
|
||||
handleChange={handleChange}
|
||||
/>
|
||||
</fieldset>
|
||||
|
||||
{!!richTextOrVisual && !isParticipatingInVisualEditorNamingTest && (
|
||||
<SplitTestBadge splitTestName="rich-text" displayOnVariants={['cm6']} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const RichTextToggle: FC<{
|
||||
checked: boolean
|
||||
disabled: boolean
|
||||
handleChange: (event: ChangeEvent<HTMLInputElement>) => void
|
||||
}> = ({ checked, disabled, handleChange }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const richTextName =
|
||||
visualEditorNameVariant === 'default' ? 'Rich Text' : 'Visual Editor'
|
||||
|
||||
const toggle = (
|
||||
<span>
|
||||
<input
|
||||
type="radio"
|
||||
name="editor"
|
||||
value="rich-text"
|
||||
id="editor-switch-rich-text"
|
||||
className="toggle-switch-input"
|
||||
checked={checked}
|
||||
onChange={handleChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<label htmlFor="editor-switch-rich-text" className="toggle-switch-label">
|
||||
<span>{richTextName}</span>
|
||||
</label>
|
||||
</span>
|
||||
)
|
||||
|
||||
if (disabled) {
|
||||
return (
|
||||
<Tooltip
|
||||
description={t('rich_text_is_only_available_for_tex_files')}
|
||||
id="rich-text-toggle-tooltip"
|
||||
overlayProps={{ placement: 'bottom' }}
|
||||
tooltipProps={{ className: 'tooltip-wide' }}
|
||||
>
|
||||
{toggle}
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
return toggle
|
||||
}
|
||||
|
||||
export default memo(EditorSwitch)
|
|
@ -7,41 +7,6 @@ import isValidTeXFile from '../../../main/is-valid-tex-file'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import SplitTestBadge from '../../../shared/components/split-test-badge'
|
||||
|
||||
function Badge() {
|
||||
const content = (
|
||||
<>
|
||||
Overleaf has upgraded the source editor. You can still use the old editor
|
||||
by selecting "Source (legacy)".
|
||||
<br />
|
||||
<br />
|
||||
Click to learn more and give feedback
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
id="editor-switch"
|
||||
description={content}
|
||||
overlayProps={{
|
||||
placement: 'bottom',
|
||||
delayHide: 100,
|
||||
}}
|
||||
tooltipProps={{ className: 'tooltip-wide' }}
|
||||
>
|
||||
<a
|
||||
href="https://forms.gle/GmSs6odZRKRp3VX98"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="info-badge"
|
||||
>
|
||||
<span className="sr-only">{content}</span>
|
||||
</a>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
const showLegacySourceEditor: boolean = getMeta('ol-showLegacySourceEditor')
|
||||
|
||||
function EditorSwitch() {
|
||||
const { t } = useTranslation()
|
||||
const [newSourceEditor, setNewSourceEditor] = useScopeValue(
|
||||
|
@ -91,8 +56,6 @@ function EditorSwitch() {
|
|||
|
||||
return (
|
||||
<div className="editor-toggle-switch">
|
||||
{showLegacySourceEditor ? <Badge /> : null}
|
||||
|
||||
<fieldset className="toggle-switch">
|
||||
<legend className="sr-only">Editor mode.</legend>
|
||||
|
||||
|
@ -109,23 +72,6 @@ function EditorSwitch() {
|
|||
<span>{t('code_editor')}</span>
|
||||
</label>
|
||||
|
||||
{showLegacySourceEditor ? (
|
||||
<>
|
||||
<input
|
||||
type="radio"
|
||||
name="editor"
|
||||
value="ace"
|
||||
id="editor-switch-ace"
|
||||
className="toggle-switch-input"
|
||||
checked={!richTextOrVisual && !newSourceEditor}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<label htmlFor="editor-switch-ace" className="toggle-switch-label">
|
||||
<span>Source (legacy)</span>
|
||||
</label>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<RichTextToggle
|
||||
checked={!!richTextOrVisual}
|
||||
disabled={!richTextAvailable}
|
||||
|
|
|
@ -6,13 +6,22 @@ import Tooltip from '../../../../shared/components/tooltip'
|
|||
import { EditorView } from '@codemirror/view'
|
||||
import { emitCommandEvent } from '../../extensions/toolbar/utils/analytics'
|
||||
import { useCodeMirrorViewContext } from '../codemirror-editor'
|
||||
import MaterialIcon from '../../../../shared/components/material-icon'
|
||||
|
||||
export const ToolbarButtonMenu: FC<{
|
||||
id: string
|
||||
label: string
|
||||
icon: string
|
||||
materialIcon?: boolean
|
||||
altCommand?: (view: EditorView) => void
|
||||
}> = memo(function ButtonMenu({ icon, id, label, altCommand, children }) {
|
||||
}> = memo(function ButtonMenu({
|
||||
icon,
|
||||
id,
|
||||
label,
|
||||
materialIcon,
|
||||
altCommand,
|
||||
children,
|
||||
}) {
|
||||
const target = useRef<any>(null)
|
||||
const { open, onToggle, ref } = useDropdown()
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
@ -39,7 +48,7 @@ export const ToolbarButtonMenu: FC<{
|
|||
}}
|
||||
ref={target}
|
||||
>
|
||||
<Icon type={icon} fw />
|
||||
{materialIcon ? <MaterialIcon type={icon} /> : <Icon type={icon} fw />}
|
||||
</Button>
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import { ListGroupItem } from 'react-bootstrap'
|
||||
import { ToolbarButtonMenu } from './button-menu'
|
||||
import { emitCommandEvent } from '../../extensions/toolbar/utils/analytics'
|
||||
import MaterialIcon from '../../../../shared/components/material-icon'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useCodeMirrorViewContext } from '../codemirror-editor'
|
||||
import {
|
||||
wrapInDisplayMath,
|
||||
wrapInInlineMath,
|
||||
} from '../../extensions/toolbar/commands'
|
||||
|
||||
export function MathDropdown() {
|
||||
const { t } = useTranslation()
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
||||
return (
|
||||
<ToolbarButtonMenu
|
||||
id="toolbar-math"
|
||||
label={t('toolbar_insert_math')}
|
||||
icon="calculate"
|
||||
materialIcon
|
||||
>
|
||||
<ListGroupItem
|
||||
aria-label={t('toolbar_insert_inline_math')}
|
||||
onClick={event => {
|
||||
emitCommandEvent(view, 'toolbar-inline-math')
|
||||
event.preventDefault()
|
||||
wrapInInlineMath(view)
|
||||
view.focus()
|
||||
}}
|
||||
>
|
||||
<MaterialIcon type="123" />
|
||||
<span>{t('toolbar_insert_inline_math')}</span>
|
||||
</ListGroupItem>
|
||||
<ListGroupItem
|
||||
aria-label={t('toolbar_insert_display_math')}
|
||||
onClick={event => {
|
||||
emitCommandEvent(view, 'toolbar-display-math')
|
||||
event.preventDefault()
|
||||
wrapInDisplayMath(view)
|
||||
view.focus()
|
||||
}}
|
||||
>
|
||||
<MaterialIcon type="view_day" />
|
||||
<span>{t('toolbar_insert_display_math')}</span>
|
||||
</ListGroupItem>
|
||||
</ToolbarButtonMenu>
|
||||
)
|
||||
}
|
|
@ -13,9 +13,10 @@ import { redo, undo } from '@codemirror/commands'
|
|||
import * as commands from '../../extensions/toolbar/commands'
|
||||
import { SectionHeadingDropdown } from './section-heading-dropdown'
|
||||
import { canAddComment } from '../../extensions/toolbar/comments'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import getMeta from '../../../../utils/meta'
|
||||
import { InsertFigureDropdown } from './insert-figure-dropdown'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { MathDropdown } from './math-dropdown'
|
||||
|
||||
const isMac = /Mac/.test(window.navigator?.platform)
|
||||
|
||||
|
@ -98,22 +99,7 @@ export const ToolbarItems: FC<{
|
|||
)}
|
||||
{showGroup('group-math') && (
|
||||
<div className="ol-cm-toolbar-button-group" data-overflow="group-math">
|
||||
<ToolbarButton
|
||||
id="toolbar-inline-math"
|
||||
label={t('toolbar_insert_inline_math')}
|
||||
command={commands.wrapInInlineMath}
|
||||
icon="π"
|
||||
textIcon
|
||||
className="ol-cm-toolbar-button-math"
|
||||
/>
|
||||
<ToolbarButton
|
||||
id="toolbar-display-math"
|
||||
label={t('toolbar_insert_display_math')}
|
||||
command={commands.wrapInDisplayMath}
|
||||
icon="Σ"
|
||||
textIcon
|
||||
className="ol-cm-toolbar-button-math"
|
||||
/>
|
||||
<MathDropdown />
|
||||
<ToolbarButton
|
||||
id="toolbar-toggle-symbol-palette"
|
||||
label={t('toolbar_toggle_symbol_palette')}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import App from '../../../base'
|
||||
import { react2angular } from 'react2angular'
|
||||
import EditorSwitch from '../components/editor-switch'
|
||||
import EditorSwitch from '../components/editor-switch-legacy'
|
||||
import { rootContext } from '../../../shared/context/root-context'
|
||||
|
||||
App.component('editorSwitch', react2angular(rootContext.use(EditorSwitch)))
|
||||
|
|
|
@ -45,7 +45,9 @@ import { keymaps } from './keymaps'
|
|||
import { shortcuts } from './shortcuts'
|
||||
import { effectListeners } from './effect-listeners'
|
||||
import { highlightSpecialChars } from './highlight-special-chars'
|
||||
import { toolbarPanel } from './toolbar/toolbar-panel'
|
||||
import { geometryChangeEvent } from './geometry-change-event'
|
||||
import { isSplitTestEnabled } from '../../../utils/splitTestUtils'
|
||||
|
||||
const moduleExtensions: Array<() => Extension> = importOverleafModules(
|
||||
'sourceEditorExtensions'
|
||||
|
@ -120,6 +122,7 @@ export const createExtensions = (options: Record<string, any>): Extension[] => [
|
|||
emptyLineFiller(),
|
||||
trackChanges(options.currentDoc, options.changeManager),
|
||||
visual(options.currentDoc, options.visual),
|
||||
isSplitTestEnabled('source-editor-toolbar') ? toolbarPanel() : [],
|
||||
verticalOverflow(),
|
||||
highlightActiveLine(options.visual.visual),
|
||||
// The built-in extension that highlights the active line in the gutter.
|
||||
|
|
|
@ -75,6 +75,9 @@ export const toolbarPanel = () => [
|
|||
'& .list-group-item': {
|
||||
width: '100%',
|
||||
textAlign: 'start',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
},
|
||||
},
|
||||
'.ol-cm-toolbar-button-group': {
|
||||
|
@ -90,6 +93,9 @@ export const toolbarPanel = () => [
|
|||
'&.ol-cm-toolbar-end': {
|
||||
borderLeft: 'none',
|
||||
},
|
||||
'&.ol-cm-toolbar-stretch': {
|
||||
flex: 1,
|
||||
},
|
||||
'&.overflow-hidden': {
|
||||
borderLeft: 'none',
|
||||
},
|
||||
|
@ -99,6 +105,9 @@ export const toolbarPanel = () => [
|
|||
padding: 0,
|
||||
},
|
||||
},
|
||||
'.formatting-buttons-wrapper': {
|
||||
flex: 1,
|
||||
},
|
||||
'.ol-cm-toolbar-button': {
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
|
@ -148,8 +157,10 @@ export const toolbarPanel = () => [
|
|||
},
|
||||
},
|
||||
'.ol-cm-toolbar-end': {
|
||||
flex: 1,
|
||||
justifyContent: 'flex-end',
|
||||
'& .badge': {
|
||||
marginRight: '5px',
|
||||
},
|
||||
},
|
||||
'.ol-cm-toolbar-overflow-toggle': {
|
||||
display: 'none',
|
||||
|
|
|
@ -17,11 +17,12 @@ import { findEffect } from '../../utils/effects'
|
|||
import { forceParsing, syntaxTree } from '@codemirror/language'
|
||||
import { hasLanguageLoadedEffect } from '../language'
|
||||
import { restoreScrollPosition } from '../scroll-position'
|
||||
import { toolbarPanel } from '../toolbar/toolbar-panel'
|
||||
import { CurrentDoc } from '../../../../../../types/current-doc'
|
||||
import isValidTeXFile from '../../../../main/is-valid-tex-file'
|
||||
import { listItemMarker } from './list-item-marker'
|
||||
import { figureModalPasteHandler } from '../figure-modal'
|
||||
import { isSplitTestEnabled } from '../../../../utils/splitTestUtils'
|
||||
import { toolbarPanel } from '../toolbar/toolbar-panel'
|
||||
|
||||
type Options = {
|
||||
visual: boolean
|
||||
|
@ -197,8 +198,8 @@ const extension = (options: Options) => [
|
|||
atomicDecorations(options),
|
||||
skipPreambleWithCursor,
|
||||
visualKeymap,
|
||||
toolbarPanel(),
|
||||
scrollJumpAdjuster,
|
||||
isSplitTestEnabled('source-editor-toolbar') ? [] : toolbarPanel(),
|
||||
showContentWhenParsed,
|
||||
figureModalPasteHandler(),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import EditorSwitch from '../js/features/source-editor/components/editor-switch'
|
||||
import EditorSwitch from '../js/features/source-editor/components/editor-switch-legacy'
|
||||
import { ScopeDecorator } from './decorators/scope'
|
||||
|
||||
export default {
|
||||
|
|
|
@ -95,8 +95,14 @@
|
|||
#editor,
|
||||
#editor-rich-text {
|
||||
.full-size;
|
||||
}
|
||||
|
||||
.editor-container #editor {
|
||||
top: @editor-toolbar-height;
|
||||
}
|
||||
.editor-container.has-source-toolbar #editor {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.pdf-empty,
|
||||
.no-history-available,
|
||||
|
|
|
@ -13,13 +13,16 @@
|
|||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.detach-compile-button-container when (@is-new-css = false) {
|
||||
margin-right: -5px;
|
||||
}
|
||||
// only apply for legacy editor
|
||||
.toolbar-pdf-right {
|
||||
.detach-compile-button-container when (@is-new-css = false) {
|
||||
margin-right: -5px;
|
||||
}
|
||||
|
||||
// because 2px border on :active state
|
||||
.detach-compile-button-container when (@is-new-css = true) {
|
||||
margin-right: -3px;
|
||||
// because 2px border on :active state
|
||||
.detach-compile-button-container when (@is-new-css = true) {
|
||||
margin-right: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-striped-animated {
|
||||
|
|
|
@ -299,6 +299,7 @@
|
|||
.editor-toggle-switch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
|
||||
.toggle-switch {
|
||||
margin-left: 5px;
|
||||
|
@ -317,6 +318,10 @@
|
|||
padding-right: 8px;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************
|
||||
|
|
|
@ -1636,6 +1636,7 @@
|
|||
"toolbar_insert_figure": "Insert Figure",
|
||||
"toolbar_insert_inline_math": "Insert Inline Math",
|
||||
"toolbar_insert_link": "Insert Link",
|
||||
"toolbar_insert_math": "Insert Math",
|
||||
"toolbar_insert_table": "Insert Table",
|
||||
"toolbar_numbered_list": "Numbered List",
|
||||
"toolbar_redo": "Redo",
|
||||
|
|
|
@ -18,7 +18,7 @@ const clickToolbarButton = (text: string) => {
|
|||
}
|
||||
|
||||
const Container: FC = ({ children }) => (
|
||||
<div style={{ width: 785, height: 785 }}>{children}</div>
|
||||
<div style={{ width: 1500, height: 785 }}>{children}</div>
|
||||
)
|
||||
|
||||
const mountEditor = (content: string) => {
|
||||
|
@ -97,6 +97,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
|||
mountEditor('2+3=5')
|
||||
selectAll()
|
||||
|
||||
clickToolbarButton('Insert Math')
|
||||
clickToolbarButton('Insert Inline Math')
|
||||
cy.get('.cm-content').should('have.text', '\\(2+3=5\\)')
|
||||
})
|
||||
|
@ -105,6 +106,7 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
|||
mountEditor('2+3=5')
|
||||
selectAll()
|
||||
|
||||
clickToolbarButton('Insert Math')
|
||||
clickToolbarButton('Insert Display Math')
|
||||
cy.get('.cm-content').should('have.text', '\\[2+3=5\\]')
|
||||
})
|
||||
|
|
|
@ -4,7 +4,7 @@ import { mockScope, rootFolderId } from '../helpers/mock-scope'
|
|||
import { FC } from 'react'
|
||||
|
||||
const Container: FC = ({ children }) => (
|
||||
<div style={{ width: 785, height: 785 }}>{children}</div>
|
||||
<div style={{ width: 1500, height: 785 }}>{children}</div>
|
||||
)
|
||||
|
||||
const clickToolbarButton = (text: string) => {
|
||||
|
|
Loading…
Reference in a new issue