Skip to content

Commit b1927bc

Browse files
committed
feat: sync scroll, editor & preview area
1 parent 54afc5c commit b1927bc

File tree

11 files changed

+79
-66
lines changed

11 files changed

+79
-66
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
.nextra-editor-container {
1+
.markdown-editor-container {
22
display: none;
33
@media (min-width: 1024px) {
4-
display: block;
4+
display: flex;
55
}
66
}

packages/markdown-editor/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
"scroll-into-view-if-needed": "^3.1.0",
9393
"shiki": "^0.14.3",
9494
"slash": "3.0.0",
95+
"throttle-debounce": "^5.0.0",
9596
"title": "3.5.3",
9697
"tsx": "^4.11.2",
9798
"unist-util-remove": "^4.0.0",
@@ -109,6 +110,7 @@
109110
"@types/mdast": "3.0.12",
110111
"@types/react": "^18.2.21",
111112
"@types/react-dom": "^18.2.7",
113+
"@types/throttle-debounce": "^5.0.1",
112114
"@types/title": "^3.4.3",
113115
"@typescript-eslint/eslint-plugin": "^7.11.0",
114116
"@typescript-eslint/parser": "^7.11.0",

packages/markdown-editor/src/components/header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export function Header({ flatDirectories, items }: NavBarProps): ReactElement {
7575
const { menu, setMenu } = useMenu()
7676

7777
return (
78-
<div className="nextra-header-container nx-w-full">
78+
<div className="nextra-header-container nx-flex nx-w-full">
7979
<div
8080
className={cn(
8181
'nextra-header-container-blur',

packages/markdown-editor/src/components/markdown-editor/events/handle-keydown.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ export const handleKeydown = (event: Event, view: EditorView): void => {
66
if (!preview) return
77

88
const head = view.state.selection.main.head
9-
109
const cursorLine = view.state.doc.lineAt(head).number
1110
const lastLine = view.state.doc.lineAt(view.state.doc.length).number
1211

13-
if (lastLine - cursorLine < 5) {
12+
if (lastLine - cursorLine < 15) {
1413
const previewHeight = preview.scrollHeight ?? 0
1514
preview.scrollTop = previewHeight
1615
}
Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
import { EditorView } from 'codemirror'
2+
import { throttle } from 'throttle-debounce'
23

3-
export const handleScroll = (event: Event, view: EditorView): void => {
4+
export const handleScroll = throttle(100, (event: Event, view: EditorView): void => {
45
if (!event.target) return
56
const preview = document.getElementById('markdown-editor-preview')
67
if (!preview) return
7-
// TODO: 비율에 따라서 스크롤 위치를 조정해야함
88

9-
if (view.scrollDOM.scrollTop > 100) {
10-
const previewHeight = preview.scrollHeight ?? 0
11-
preview.scrollTop = previewHeight
9+
if (view.scrollDOM.scrollTop < 200) {
10+
preview.scrollTop = 0
11+
return
1212
}
13-
}
13+
14+
const head = view.state.selection.main.head
15+
const cursorLine = view.state.doc.lineAt(head).number
16+
const lastLine = view.state.doc.lineAt(view.state.doc.length).number
17+
if (lastLine - cursorLine < 15) {
18+
return
19+
}
20+
21+
const previewScrollHeight = preview.scrollHeight - preview.clientHeight
22+
const editorScrollHeight = view.scrollDOM.scrollHeight - view.scrollDOM.clientHeight
23+
24+
// editor 영역에서 스크롤 비율 구하기
25+
const percent = view.scrollDOM.scrollTop / editorScrollHeight
26+
27+
// preview 영역에 스크롤 위치 설정
28+
preview.scrollTop = percent * previewScrollHeight
29+
})

packages/markdown-editor/src/components/markdown-editor/markdown-editor.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import cn from 'clsx'
2-
import { useRef } from 'react'
2+
import { useRef } from 'react'
33
import { Toolbar } from './toolbar'
44
import { useCodemirror } from '@/hooks'
55

6-
interface MarkdownEditorProps {}
6+
interface MarkdownEditorProps {
7+
height: string
8+
}
79

8-
export const MarkdownEditor = ({}: MarkdownEditorProps) => {
10+
export const MarkdownEditor = ({ height }: MarkdownEditorProps) => {
911
const codemirror = useRef<HTMLDivElement | null>(null)
1012
const { state, view } = useCodemirror(codemirror, {
1113
autoFocus: true,
@@ -26,10 +28,7 @@ export const MarkdownEditor = ({}: MarkdownEditorProps) => {
2628
ref={codemirror}
2729
suppressHydrationWarning={true}
2830
suppressContentEditableWarning={true}
29-
style={{
30-
height:
31-
'calc(100vh - (var(--nextra-navbar-height)) - var(--nextra-editor-toolbar-height))',
32-
}}
31+
style={{ height }}
3332
/>
3433
</>
3534
)

packages/markdown-editor/src/components/markdown-preview/markdown-preview.tsx

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import { MDXRemote } from 'next-mdx-remote'
55
import { getComponents } from '@/mdx-components'
66
import { useMarkdownEditor } from '@/contexts/markdown-editor'
77

8-
interface MarkdownPreviewProps {}
8+
interface MarkdownPreviewProps {
9+
height: string
10+
}
911

10-
export const MarkdownPreview = ({}: MarkdownPreviewProps): ReactElement => {
12+
export const MarkdownPreview = ({ height }: MarkdownPreviewProps): ReactElement => {
1113
const config = useConfig()
1214
const { mdxSource } = useMarkdownEditor()
1315

@@ -16,24 +18,27 @@ export const MarkdownPreview = ({}: MarkdownPreviewProps): ReactElement => {
1618
}
1719

1820
return (
19-
<div
20-
id="markdown-editor-preview"
21-
className={cn(
22-
'markdown-editor-preview',
23-
'markdown-editor-scrollbar nx-h-screen nx-overflow-y-auto nx-break-words nx-pb-16',
24-
)}
25-
>
26-
<main className="nx-mt-6 nx-w-full nx-min-w-0 nx-max-w-6xl nx-px-6 nx-pb-[8rem] nx-pt-6">
27-
<MDXRemote
28-
compiledSource={mdxSource.compiledSource}
29-
frontmatter={mdxSource.frontmatter}
30-
scope={mdxSource.scope}
31-
components={getComponents({
32-
isRawLayout: false,
33-
components: config.components,
34-
})}
35-
/>
36-
</main>
37-
</div>
21+
<>
22+
<div
23+
id="markdown-editor-preview"
24+
className={cn(
25+
'markdown-editor-preview',
26+
'markdown-editor-scrollbar nx-h-screen nx-overflow-y-auto nx-scroll-smooth nx-break-words',
27+
)}
28+
style={{ height }}
29+
>
30+
<main className="nx-w-full nx-px-6 ">
31+
<MDXRemote
32+
compiledSource={mdxSource.compiledSource}
33+
frontmatter={mdxSource.frontmatter}
34+
scope={mdxSource.scope}
35+
components={getComponents({
36+
isRawLayout: false,
37+
components: config.components,
38+
})}
39+
/>
40+
</main>
41+
</div>
42+
</>
3843
)
3944
}

packages/markdown-editor/src/hooks/use-codemirror.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export const useCodemirror = (container: RefObject<HTMLDivElement>, config: Conf
7979
scrollbarColor: 'oklch(55.55% 0 0 / 40%) transparent',
8080
scrollbarGutter: 'stable',
8181
'overflow-x': 'hidden',
82+
'scroll-behavior': 'smooth',
8283
},
8384
'.cm-heading1': { fontSize: '24px' },
8485
'.cm-heading2': { fontSize: '20px' },

packages/markdown-editor/src/layouts/main.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export const Main = ({ frontMatter, headings, pageMap }: MainProps): ReactElemen
3131
const themeContext = { ...activeThemeContext, ...frontMatter }
3232
const direction = 'ltr'
3333
const mainHeight = 'calc(100vh - (var(--nextra-navbar-height)))'
34-
34+
const height = 'calc(100vh - (var(--nextra-navbar-height)) - var(--nextra-editor-toolbar-height))'
3535
return (
3636
<div
3737
dir={direction}
@@ -60,14 +60,16 @@ export const Main = ({ frontMatter, headings, pageMap }: MainProps): ReactElemen
6060
asPopover={false}
6161
includePlaceholder={themeContext.layout === 'default'}
6262
/>
63-
<div className={cn('nx-flex nx-overflow-hidden')} style={{ width: 'calc(100% - 320px)' }}>
64-
<div className={cn('nextra-editor-container nx-h-[100%] nx-w-1/2')}>
65-
<MarkdownEditor />
63+
<main className={cn('markdown-main nx-flex nx-w-full nx-overflow-hidden')}>
64+
<div
65+
className={cn('markdown-editor-container nx-relative nx-flex nx-w-1/2 nx-flex-col')}
66+
>
67+
<MarkdownEditor height={height} />
6668
</div>
67-
<div className={cn('nextra-preview-container nx-h-[100%] nx-w-1/2')}>
68-
<MarkdownPreview />
69+
<div className={cn('markdown-preview-container nx-flex nx-w-1/2')}>
70+
<MarkdownPreview height={height} />
6971
</div>
70-
</div>
72+
</main>
7173
</ActiveAnchorProvider>
7274
</div>
7375
</div>

packages/markdown-editor/style.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-lock.yaml

Lines changed: 8 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)