mirror of
https://github.com/docmost/docmost.git
synced 2026-09-11 07:56:54 +08:00
fix minor issues
This commit is contained in:
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|||||||
import { ActionIcon, Box, Modal, Text, Title, Tooltip } from "@mantine/core";
|
import { ActionIcon, Box, Modal, Text, Title, Tooltip } from "@mantine/core";
|
||||||
import { IconChevronLeft, IconChevronRight, IconX } from "@tabler/icons-react";
|
import { IconChevronLeft, IconChevronRight, IconX } from "@tabler/icons-react";
|
||||||
import { useHotkeys } from "@mantine/hooks";
|
import { useHotkeys } from "@mantine/hooks";
|
||||||
import { EditorProvider, type JSONContent } from "@tiptap/react";
|
import { EditorProvider, isNodeEmpty, type JSONContent } from "@tiptap/react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { mainExtensions } from "@/features/editor/extensions/extensions";
|
import { mainExtensions } from "@/features/editor/extensions/extensions";
|
||||||
import { TransclusionLookupProvider } from "@/features/editor/components/transclusion/transclusion-lookup-context";
|
import { TransclusionLookupProvider } from "@/features/editor/components/transclusion/transclusion-lookup-context";
|
||||||
@@ -18,6 +18,8 @@ type MeasuredContentSlide = {
|
|||||||
scrollable: boolean;
|
scrollable: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type MeasuredNode = { node: JSONContent; rect: DOMRect };
|
||||||
|
|
||||||
interface PresentationModalProps {
|
interface PresentationModalProps {
|
||||||
title: string;
|
title: string;
|
||||||
content: JSONContent;
|
content: JSONContent;
|
||||||
@@ -31,6 +33,23 @@ const excludedExtensionNames = new Set([
|
|||||||
"tableReadonlySort",
|
"tableReadonlySort",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const isEmptyJsonNode = (node: JSONContent) =>
|
||||||
|
node.type === "paragraph" && !node.text?.trim() && !node.content?.length;
|
||||||
|
|
||||||
|
const isDivider = (node: JSONContent) => node.type === "horizontalRule";
|
||||||
|
|
||||||
|
const isSectionHeading = (node: JSONContent) =>
|
||||||
|
node.type === "heading" && node.attrs?.level === 1;
|
||||||
|
|
||||||
|
function getAvailableHeight(area: HTMLElement): number {
|
||||||
|
const styles = window.getComputedStyle(area);
|
||||||
|
return (
|
||||||
|
area.clientHeight -
|
||||||
|
parseFloat(styles.paddingTop) -
|
||||||
|
parseFloat(styles.paddingBottom)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function PresentationModal({
|
export default function PresentationModal({
|
||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
@@ -103,47 +122,55 @@ export default function PresentationModal({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const editorElement = editor.view.dom;
|
const renderedNodes = Array.from(editor.view.dom.children) as HTMLElement[];
|
||||||
const renderedNodes = Array.from(editorElement.children) as HTMLElement[];
|
if (!renderedNodes.length) {
|
||||||
|
setContentSlides([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const areaStyles = window.getComputedStyle(area);
|
const availableHeight = getAvailableHeight(area);
|
||||||
const availableHeight =
|
|
||||||
area.clientHeight -
|
|
||||||
parseFloat(areaStyles.paddingTop) -
|
|
||||||
parseFloat(areaStyles.paddingBottom);
|
|
||||||
const slides: MeasuredContentSlide[] = [];
|
const slides: MeasuredContentSlide[] = [];
|
||||||
let currentSlide: JSONContent[] = [];
|
let currentSlide: JSONContent[] = [];
|
||||||
let currentSlideTop = renderedNodes[0].getBoundingClientRect().top;
|
let currentSlideTop = 0;
|
||||||
let currentSlideBottom = currentSlideTop;
|
let currentSlideBottom = 0;
|
||||||
|
|
||||||
const saveCurrentSlide = () => {
|
const saveCurrentSlide = () => {
|
||||||
if (currentSlide.length === 0) return;
|
if (!currentSlide.length) return;
|
||||||
|
|
||||||
slides.push({
|
slides.push({
|
||||||
doc: { type: "doc", content: currentSlide },
|
doc: { type: "doc", content: currentSlide },
|
||||||
scrollable: currentSlideBottom - currentSlideTop > availableHeight,
|
scrollable: currentSlideBottom - currentSlideTop > availableHeight,
|
||||||
});
|
});
|
||||||
|
currentSlide = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
renderedNodes.forEach((renderedNode, index) => {
|
for (let index = 0; index < renderedNodes.length; index++) {
|
||||||
const node = nodes[index];
|
const node = nodes[index];
|
||||||
const nodeRect = renderedNode.getBoundingClientRect();
|
const renderedNode = renderedNodes[index];
|
||||||
const startsNewSection =
|
if (!node || !renderedNode || isEmptyJsonNode(node)) continue;
|
||||||
node.type === "horizontalRule" ||
|
|
||||||
(node.type === "heading" && node.attrs?.level === 1);
|
|
||||||
const exceedsPage =
|
|
||||||
currentSlide.length > 0 &&
|
|
||||||
nodeRect.bottom - currentSlideTop > availableHeight;
|
|
||||||
|
|
||||||
if (currentSlide.length > 0 && (startsNewSection || exceedsPage)) {
|
const rect = renderedNode.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (isDivider(node)) {
|
||||||
saveCurrentSlide();
|
saveCurrentSlide();
|
||||||
currentSlide = [];
|
currentSlideTop = rect.bottom;
|
||||||
currentSlideTop = nodeRect.top;
|
currentSlideBottom = rect.bottom;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSlide.length === 0) {
|
||||||
|
currentSlideTop = rect.top;
|
||||||
|
} else if (
|
||||||
|
isSectionHeading(node) ||
|
||||||
|
rect.bottom - currentSlideTop > availableHeight
|
||||||
|
) {
|
||||||
|
saveCurrentSlide();
|
||||||
|
currentSlideTop = rect.top;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSlide.push(node);
|
currentSlide.push(node);
|
||||||
currentSlideBottom = nodeRect.bottom;
|
currentSlideBottom = rect.bottom;
|
||||||
});
|
}
|
||||||
|
|
||||||
saveCurrentSlide();
|
saveCurrentSlide();
|
||||||
setContentSlides(slides);
|
setContentSlides(slides);
|
||||||
|
|||||||
Reference in New Issue
Block a user