1
0
Fork 0
mirror of https://github.com/hedgedoc/hedgedoc.git synced 2025-04-11 07:36:35 +00:00

Add sync scroll button ()

* Add disable sync scroll button

Signed-off-by: Tilman Vatteroth <tilman.vatteroth@tu-dortmund.de>
This commit is contained in:
mrdrogdrog 2020-08-25 21:36:25 +02:00 committed by GitHub
parent d488c8e2ad
commit c95a7e0fba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 194 additions and 34 deletions

View file

@ -201,6 +201,12 @@
"switchToDark": "Switch to Dark Mode",
"switchToLight": "Switch to Light Mode"
},
"appBar": {
"syncScroll": {
"disable": "Disable sync scroll",
"enable": "Enable sync scroll"
}
},
"editorToolbar": {
"bold": "Bold",
"italic": "Italic",

View file

@ -9,6 +9,7 @@ import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon'
import { ShowIf } from '../../common/show-if/show-if'
import { SignInButton } from '../../landing-layout/navigation/sign-in-button'
import { UserDropdown } from '../../landing-layout/navigation/user-dropdown'
import { SyncScrollButton } from './sync-scroll-button/sync-scroll-button'
import { EditorPathParams } from '../editor'
import { DarkModeButton } from './dark-mode-button'
import { EditorViewMode } from './editor-view-mode'
@ -25,6 +26,7 @@ export const AppBar: React.FC = () => {
<Nav className="mr-auto d-flex align-items-center">
<NavbarBranding/>
<EditorViewMode/>
<SyncScrollButton/>
<DarkModeButton/>
<Link to={`/p/${id}`} target='_blank'>
<Button title={t('editor.documentBar.slideMode')} className="ml-2 text-secondary" size="sm" variant="outline-light">

View file

@ -3,7 +3,7 @@ import { ToggleButton, ToggleButtonGroup } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import { ApplicationState } from '../../../redux'
import { setEditorModeConfig } from '../../../redux/editor/methods'
import { setEditorMode } from '../../../redux/editor/methods'
import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon'
export enum EditorMode {
@ -21,7 +21,7 @@ export const EditorViewMode: React.FC = () => {
name="options"
value={editorConfig.editorMode}
onChange={(value: EditorMode) => {
setEditorModeConfig(value)
setEditorMode(value)
}}>
<ToggleButton value={EditorMode.PREVIEW} variant="outline-secondary" title={t('editor.viewMode.view')}>
<ForkAwesomeIcon icon="eye"/>

View file

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="512"
height="512"
viewBox="0 0 135.46666 135.46666"
version="1.1"
id="svg8"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="buttonIcon.svg">
<defs
id="defs2" />
<sodipodi:namedview
fit-margin-bottom="0"
fit-margin-right="0"
fit-margin-left="0"
fit-margin-top="0"
id="base"
pagecolor="#545b62"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="151.94971"
inkscape:cy="220.06486"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="3434"
inkscape:window-height="1321"
inkscape:window-x="0"
inkscape:window-y="84"
inkscape:window-maximized="1"
inkscape:pagecheckerboard="false" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(253.17277,890.86874)"
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1">
<path
id="path864"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
d="m -185.5862,-882.45881 c -1.05348,0.0354 -2.05943,0.44876 -2.83393,1.16582 l -17.37672,16.08016 c -1.77986,1.64837 -1.89553,4.45148 -0.25787,6.24199 1.63744,1.79079 4.43758,1.90901 6.21875,0.262 l 14.39653,-13.32218 14.39654,13.32218 c 1.78118,1.64702 4.5813,1.5288 6.21874,-0.262 1.63691,-1.79129 1.52077,-4.59444 -0.25993,-6.24199 l -17.37465,-16.08016 c -0.84861,-0.78564 -1.97318,-1.20418 -3.12746,-1.16582 z" />
<path
id="path851"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
d="m -202.99806,-788.72004 c -1.12724,0.0475 -2.23794,0.52467 -3.05666,1.42007 -1.63766,1.79051 -1.52199,4.59363 0.25787,6.24199 l 17.37672,16.08016 c 0.7745,0.71706 1.78045,1.13042 2.83393,1.16582 1.15428,0.0384 2.27885,-0.38018 3.12746,-1.16582 l 17.37465,-16.08016 c 1.7807,-1.64754 1.89684,-4.4507 0.25993,-6.24199 -1.63744,-1.79081 -4.43756,-1.90902 -6.21874,-0.262 l -14.39654,13.32218 -14.39653,-13.32218 c -0.89058,-0.8235 -2.03485,-1.20561 -3.16209,-1.15807 z" />
<circle
r="16"
cy="-823.13544"
cx="-185.43944"
id="path845"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.565;stroke-linecap:round;stroke-linejoin:round" />
<g
style="display:inline;opacity:1;stroke:none;stroke-opacity:1"
id="g855">
<path
id="path858"
d="m -128.54012,-883.40784 -121.89532,111.71083 8.0967,8.83405 121.89531,-111.71083 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.565;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1" />
<path
id="path860"
d="m -128.61914,-886.18945 a 2.7827783,2.7827783 0 0 0 -1.80078,0.73047 l -121.89453,111.71093 a 2.7827783,2.7827783 0 0 0 -0.17188,3.93164 l 8.09571,8.83399 a 2.7827783,2.7827783 0 0 0 3.93164,0.16992 l 121.89648,-111.70898 a 2.7827783,2.7827783 0 0 0 0.16992,-3.93164 l -8.0957,-8.83399 a 2.7827783,2.7827783 0 0 0 -2.13086,-0.90234 z m -0.0937,6.71289 4.33789,4.73047 -117.79297,107.95117 -4.33594,-4.73047 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#545b62;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.565;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1" />
</g>
</g>
</svg>

After

(image error) Size: 8.9 KiB

View file

@ -0,0 +1 @@
<svg height="512" viewBox="0 0 135.46666 135.46666" width="512" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" transform="translate(253.17277 890.86874)"><path d="m-185.60701-890.86598c-1.20278.0405-2.35129.51236-3.23554 1.33104l-19.83931 18.35901c-2.0321 1.88196-2.16416 5.08233-.29441 7.12658 1.86949 2.04457 5.06645 2.17956 7.10004.29914l16.43678-15.21017 16.43678 15.21017c2.03361 1.88043 5.23055 1.74545 7.10004-.29914 1.86889-2.04514 1.73629-5.24555-.29677-7.12658l-19.83694-18.35901c-.96887-.89698-2.25281-1.37483-3.57067-1.33104z"/><path d="m-205.48644-783.84278c-1.28698.0542-2.55509.59901-3.48983 1.62131-1.86975 2.04426-1.73769 5.24463.29441 7.12659l19.83931 18.359c.88425.81868 2.03276 1.29062 3.23554 1.33104 1.31786.0439 2.6018-.43406 3.57067-1.33104l19.83694-18.359c2.03306-1.88102 2.16566-5.08144.29677-7.12659-1.86949-2.04459-5.06643-2.17956-7.10004-.29913l-16.43678 15.21017-16.43678-15.21017c-1.01679-.94021-2.32321-1.37647-3.61021-1.32218z"/><path d="m-185.49136-841.40292a18.267478 18.267478 0 0 0 -18.21562 18.26754 18.267478 18.267478 0 0 0 .23777 2.93583l22.52379-20.64169a18.267478 18.267478 0 0 0 -4.49402-.56168 18.267478 18.267478 0 0 0 -.0519 0zm18.08169 15.33288-22.5232 20.64052a18.267478 18.267478 0 0 0 4.49343.56168 18.267478 18.267478 0 0 0 18.26754-18.26754 18.267478 18.267478 0 0 0 -.23777-2.93466z" fill-rule="evenodd"/><path d="m-124.79368-883.92129-126.14511 116.28534 4.95067 5.40084 126.14688-116.28534z"/></g></svg>

After

(image error) Size: 1.4 KiB

View file

@ -0,0 +1 @@
<svg height="512" viewBox="0 0 135.46666 135.46666" width="512" xmlns="http://www.w3.org/2000/svg"><g fill="#545b62"><path d="m67.566309.00276674c-1.20278.040417-2.35129.512357-3.23555 1.33103706l-19.83929 18.3589962c-2.0321 1.881973-2.16417 5.082332-.29442 7.126588 1.8695 2.044576 5.06646 2.17955 7.10005.29913l16.43677-15.210163 16.43678 15.210163c2.03361 1.880432 5.23055 1.745458 7.10004-.29913 1.86889-2.045147 1.73629-5.24555-.29677-7.126588l-19.83693-18.3589962c-.96887-.89697906-2.25281-1.37483336-3.57068-1.33103706z"/><path d="m47.686889 107.02594c-1.28698.0542-2.55509.59903-3.48984 1.62132-1.86975 2.04426-1.73768 5.24462.29442 7.12659l19.83929 18.359c.88426.81868 2.03277 1.29062 3.23555 1.33104 1.31787.0438 2.60181-.43406 3.57068-1.33104l19.83693-18.359c2.03306-1.88103 2.16566-5.08144.29677-7.12659-1.86949-2.0446-5.06643-2.17956-7.10004-.29913l-16.43678 15.21016-16.43677-15.21016c-1.01679-.94021-2.32322-1.37647-3.61021-1.32219z"/><circle cx="67.733864" cy="67.733284" fill-rule="evenodd" r="18.267477"/></g></svg>

After

(image error) Size: 1 KiB

View file

@ -0,0 +1,30 @@
import React, { useCallback } from 'react'
import { ToggleButton, ToggleButtonGroup } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import { ApplicationState } from '../../../../redux'
import { setEditorSyncScroll } from '../../../../redux/editor/methods'
import disabledScroll from './disabledScroll.svg'
import enabledScroll from './enabledScroll.svg'
export const SyncScrollButton: React.FC = () => {
const syncScroll: boolean = useSelector((state: ApplicationState) => state.editorConfig.syncScroll)
const translation = syncScroll ? 'editor.appBar.syncScroll.enable' : 'editor.appBar.syncScroll.disable'
const onClick = useCallback(() => {
setEditorSyncScroll(!syncScroll)
}, [syncScroll])
const { t } = useTranslation()
return (
<ToggleButtonGroup type="checkbox" defaultValue={[]} name="sync-scroll" className="ml-2" value={[syncScroll]}>
<ToggleButton
title={ t(translation) }
variant={syncScroll ? 'secondary' : 'light'}
onChange={onClick} value={true}
>
<img src={syncScroll ? disabledScroll : enabledScroll} width={'20px'} alt={t(translation)}/>
</ToggleButton>
</ToggleButtonGroup>
)
}

View file

@ -61,12 +61,14 @@ export const EditorPane: React.FC<EditorPaneProps & ScrollProps> = ({ onContentC
})
const lastScrollPosition = useRef<number>()
const [editorScroll, setEditorScroll] = useState<ScrollInfo>()
const onEditorScroll = useCallback((editor: Editor, data: ScrollInfo) => setEditorScroll(data), [])
const onEditorScroll = useCallback((editor: Editor, data: ScrollInfo) => {
if (!editor || !onScroll) {
useEffect(() => {
if (!editor || !onScroll || !editorScroll) {
return
}
const scrollEventValue = data.top as number
const scrollEventValue = editorScroll.top as number
const line = editor.lineAtHeight(scrollEventValue, 'local')
const startYOfLine = editor.heightAtLine(line, 'local')
const lineInfo = editor.lineInfo(line)
@ -79,7 +81,7 @@ export const EditorPane: React.FC<EditorPaneProps & ScrollProps> = ({ onContentC
const newScrollState: ScrollState = { firstLineInView: line + 1, scrolledPercentage: percentage }
onScroll(newScrollState)
}, [onScroll])
}, [editor, editorScroll, onScroll])
useEffect(() => {
if (!editor || !scrollState) {

View file

@ -3,18 +3,18 @@ import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import useMedia from 'use-media'
import { ApplicationState } from '../../redux'
import { setEditorModeConfig } from '../../redux/editor/methods'
import { setEditorMode } from '../../redux/editor/methods'
import { DocumentTitle } from '../common/document-title/document-title'
import { DocumentRenderPane } from './document-renderer-pane/document-render-pane'
import { EditorPane } from './editor-pane/editor-pane'
import { Splitter } from './splitter/splitter'
import { MotdBanner } from '../common/motd-banner/motd-banner'
import { DocumentBar } from './document-bar/document-bar'
import { editorTestContent } from './editorTestContent'
import { DualScrollState, ScrollState } from './scroll/scroll-props'
import { YAMLMetaData } from './yaml-metadata/yaml-metadata'
import { AppBar } from './app-bar/app-bar'
import { EditorMode } from './app-bar/editor-view-mode'
import { DocumentBar } from './document-bar/document-bar'
import { DocumentRenderPane } from './document-renderer-pane/document-render-pane'
import { EditorPane } from './editor-pane/editor-pane'
import { editorTestContent } from './editorTestContent'
import { DualScrollState, ScrollState } from './scroll/scroll-props'
import { Splitter } from './splitter/splitter'
import { YAMLMetaData } from './yaml-metadata/yaml-metadata'
export interface EditorPathParams {
id: string
@ -28,7 +28,6 @@ export enum ScrollSource {
export const Editor: React.FC = () => {
const { t } = useTranslation()
const untitledNote = t('editor.untitledNote')
const editorMode: EditorMode = useSelector((state: ApplicationState) => state.editorConfig.editorMode)
const [markdownContent, setMarkdownContent] = useState(editorTestContent)
const isWide = useMedia({ minWidth: 576 })
const [firstDraw, setFirstDraw] = useState(true)
@ -37,6 +36,9 @@ export const Editor: React.FC = () => {
const firstHeading = useRef<string>()
const scrollSource = useRef<ScrollSource>(ScrollSource.EDITOR)
const editorMode: EditorMode = useSelector((state: ApplicationState) => state.editorConfig.editorMode)
const editorSyncScroll: boolean = useSelector((state: ApplicationState) => state.editorConfig.syncScroll)
const [scrollState, setScrollState] = useState<DualScrollState>(() => ({
editorScrollState: { firstLineInView: 1, scrolledPercentage: 0 },
rendererScrollState: { firstLineInView: 1, scrolledPercentage: 0 }
@ -68,21 +70,21 @@ export const Editor: React.FC = () => {
useEffect(() => {
if (!firstDraw && !isWide && editorMode === EditorMode.BOTH) {
setEditorModeConfig(EditorMode.PREVIEW)
setEditorMode(EditorMode.PREVIEW)
}
}, [editorMode, firstDraw, isWide])
const onEditorScroll = useCallback((newScrollState: ScrollState) => {
if (scrollSource.current === ScrollSource.EDITOR) {
setScrollState((old) => ({ rendererScrollState: newScrollState, editorScrollState: old.editorScrollState }))
}
}, [])
const onMarkdownRendererScroll = useCallback((newScrollState: ScrollState) => {
if (scrollSource.current === ScrollSource.RENDERER) {
if (scrollSource.current === ScrollSource.RENDERER && editorSyncScroll) {
setScrollState((old) => ({ editorScrollState: newScrollState, rendererScrollState: old.rendererScrollState }))
}
}, [])
}, [editorSyncScroll])
const onEditorScroll = useCallback((newScrollState: ScrollState) => {
if (scrollSource.current === ScrollSource.EDITOR && editorSyncScroll) {
setScrollState((old) => ({ rendererScrollState: newScrollState, editorScrollState: old.editorScrollState }))
}
}, [editorSyncScroll])
return (
<Fragment>
@ -99,7 +101,7 @@ export const Editor: React.FC = () => {
content={markdownContent}
scrollState={scrollState.editorScrollState}
onScroll={onEditorScroll}
onMakeScrollSource={() => { scrollSource.current = ScrollSource.EDITOR }}
onMakeScrollSource={() => scrollSource.current = ScrollSource.EDITOR}
/>
}
showRight={editorMode === EditorMode.PREVIEW || (editorMode === EditorMode.BOTH)}
@ -111,7 +113,9 @@ export const Editor: React.FC = () => {
onScroll={onMarkdownRendererScroll}
onMetadataChange={onMetadataChange}
onFirstHeadingChange={onFirstHeadingChange}
onMakeScrollSource={() => { scrollSource.current = ScrollSource.RENDERER }}/>}
onMakeScrollSource={() => {
scrollSource.current = ScrollSource.RENDERER
}}/>}
containerClassName={'overflow-hidden'}/>
</div>
</Fragment>

View file

@ -1,11 +1,19 @@
import { store } from '..'
import { EditorMode } from '../../components/editor/app-bar/editor-view-mode'
import { EditorConfigActionType, SetEditorConfigAction } from './types'
import { EditorConfigActionType, SetEditorConfigAction, SetEditorSyncScrollAction } from './types'
export const setEditorModeConfig = (editorMode: EditorMode): void => {
export const setEditorMode = (editorMode: EditorMode): void => {
const action: SetEditorConfigAction = {
type: EditorConfigActionType.SET_EDITOR_VIEW_MODE,
mode: editorMode
}
store.dispatch(action)
}
export const setEditorSyncScroll = (syncScroll: boolean): void => {
const action: SetEditorSyncScrollAction = {
type: EditorConfigActionType.SET_SYNC_SCROLL,
syncScroll: syncScroll
}
store.dispatch(action)
}

View file

@ -1,9 +1,16 @@
import { Reducer } from 'redux'
import { EditorConfig, EditorConfigActions, EditorConfigActionType, SetEditorConfigAction } from './types'
import {
EditorConfig,
EditorConfigActions,
EditorConfigActionType,
SetEditorConfigAction,
SetEditorSyncScrollAction
} from './types'
import { EditorMode } from '../../components/editor/app-bar/editor-view-mode'
export const initialState: EditorConfig = {
editorMode: EditorMode.BOTH
editorMode: EditorMode.BOTH,
syncScroll: true
}
export const EditorConfigReducer: Reducer<EditorConfig, EditorConfigActions> = (state: EditorConfig = initialState, action: EditorConfigActions) => {
@ -13,6 +20,11 @@ export const EditorConfigReducer: Reducer<EditorConfig, EditorConfigActions> = (
...state,
editorMode: (action as SetEditorConfigAction).mode
}
case EditorConfigActionType.SET_SYNC_SCROLL:
return {
...state,
syncScroll: (action as SetEditorSyncScrollAction).syncScroll
}
default:
return state
}

View file

@ -1,18 +1,24 @@
import { Action } from 'redux'
import { EditorMode } from '../../components/editor/app-bar/editor-view-mode';
import { EditorMode } from '../../components/editor/app-bar/editor-view-mode'
export enum EditorConfigActionType {
SET_EDITOR_VIEW_MODE = 'editor/mode/set'
SET_EDITOR_VIEW_MODE = 'editor/mode/set',
SET_SYNC_SCROLL = 'editor/syncScroll/set'
}
export interface EditorConfig {
editorMode: EditorMode;
syncScroll: boolean;
}
export interface EditorConfigActions extends Action<EditorConfigActionType> {
type: EditorConfigActionType;
}
export interface SetEditorConfigAction extends EditorConfigActions {
mode: EditorMode;
export interface SetEditorSyncScrollAction extends EditorConfigActions {
syncScroll: boolean
}
export interface SetEditorConfigAction extends EditorConfigActions {
mode: EditorMode
}