Преглед изворни кода

Merge pull request #8023 from weseek/imprv/115672-129273-sync-scroll-in-slide-preview

imprv: Synchronise the scrolling of slides and editor in slide preview.
Yuki Takei пре 2 година
родитељ
комит
72d7bb5d0b

+ 3 - 0
apps/app/src/client/services/renderer/slide-viewer-renderer.tsx

@@ -14,6 +14,7 @@ import * as mermaid from '~/features/mermaid';
 import { RehypeSanitizeOption } from '~/interfaces/rehype';
 import type { RendererOptions } from '~/interfaces/renderer-options';
 import type { RendererConfig } from '~/interfaces/services/renderer';
+import * as addLineNumberAttribute from '~/services/renderer/rehype-plugins/add-line-number-attribute';
 import * as attachment from '~/services/renderer/remark-plugins/attachment';
 import * as plantuml from '~/services/renderer/remark-plugins/plantuml';
 import * as xsvToTable from '~/services/renderer/remark-plugins/xsv-to-table';
@@ -55,6 +56,7 @@ export const generatePresentationViewOptions = (
       attachment.sanitizeOption,
       lsxGrowiDirective.sanitizeOption,
       refsGrowiDirective.sanitizeOption,
+      addLineNumberAttribute.sanitizeOption,
     )]
     : () => {};
 
@@ -63,6 +65,7 @@ export const generatePresentationViewOptions = (
     [lsxGrowiDirective.rehypePlugin, { pagePath, isSharedPage: config.isSharedPage }],
     [refsGrowiDirective.rehypePlugin, { pagePath }],
     rehypeSanitizePlugin,
+    addLineNumberAttribute.rehypePlugin,
     katex,
   );
 

+ 1 - 1
apps/app/src/components/PagePresentationModal.tsx

@@ -88,7 +88,7 @@ const PagePresentationModal = (): JSX.Element => {
               },
               isDarkMode,
             }}
-            isEnabledMarp = {isEnabledMarp}
+            isEnabledMarp={isEnabledMarp}
           >
             {markdown}
           </Presentation>

+ 35 - 2
packages/presentation/src/services/growi-marpit.ts

@@ -3,6 +3,39 @@ import { Element } from '@marp-team/marpit';
 
 export const MARP_CONTAINER_CLASS_NAME = 'marpit';
 
+// Add data-line to Marp slide.
+// https://github.com/marp-team/marp-vscode/blob/d9af184ed12b65bb28c0f328e250955d548ac1d1/src/plugins/line-number.ts
+const sourceMapIgnoredTypesForElements = ['inline', 'marpit_slide_open'];
+const lineNumber = (md) => {
+
+  const { marpit_slide_containers_open: marpitSlideContainersOpen } = md.renderer.rules;
+
+  // Enable line sync by per slides
+  md.renderer.rules.marpit_slide_containers_open = (tks, i, opts, env, slf) => {
+    const slide = tks.slice(i + 1).find(t => t.type === 'marpit_slide_open');
+
+    if (slide?.map?.length) {
+      tks[i].attrJoin('class', 'has-data-line');
+      tks[i].attrSet('data-line', slide.map[0]);
+    }
+
+    const renderer = marpitSlideContainersOpen || slf.renderToken;
+    return renderer.call(slf, tks, i, opts, env, slf);
+  };
+  // Enables line sync per elements
+  md.core.ruler.push('marp_growi_source_map_attr', (state) => {
+    for (const token of state.tokens) {
+      if (
+        token.map?.length
+        && !sourceMapIgnoredTypesForElements.includes(token.type)
+      ) {
+        token.attrJoin('class', 'has-data-line');
+        token.attrSet('data-line', token.map[0]);
+      }
+    }
+  });
+};
+
 export const slideMarpit = new Marp({
   container: [
     new Element('div', { class: `slides ${MARP_CONTAINER_CLASS_NAME}` }),
@@ -14,7 +47,7 @@ export const slideMarpit = new Marp({
   emoji: undefined,
   html: false,
   math: false,
-});
+}).use(lineNumber);
 
 export const presentationMarpit = new Marp({
   container: [
@@ -27,4 +60,4 @@ export const presentationMarpit = new Marp({
   emoji: undefined,
   html: false,
   math: false,
-});
+}).use(lineNumber);