mirror of
https://github.com/docmost/docmost.git
synced 2026-08-26 00:07:04 +08:00
* lightbox media display init * revert uninteded changes * load page media more accurately * restrict lock file changes to installed packages * revert changes in lock file * update lockfile * - support diagrams - support readonly mode - use softer backdrop - other enhancments --------- Co-authored-by: Philipinho <16838612+Philipinho@users.noreply.github.com>
160 lines
4.4 KiB
TypeScript
160 lines
4.4 KiB
TypeScript
import "@/features/editor/styles/index.css";
|
|
import React, {
|
|
useCallback,
|
|
useEffect,
|
|
useMemo,
|
|
useRef,
|
|
useState,
|
|
} from "react";
|
|
import { Editor, EditorProvider } from "@tiptap/react";
|
|
import { mainExtensions } from "@/features/editor/extensions/extensions";
|
|
import { Document } from "@tiptap/extension-document";
|
|
import { Heading, UniqueID } from "@docmost/editor-ext";
|
|
import { Text } from "@tiptap/extension-text";
|
|
import { Placeholder } from "@tiptap/extension-placeholder";
|
|
import { useAtom } from "jotai";
|
|
import {
|
|
lightboxRequestAtom,
|
|
readOnlyEditorAtom,
|
|
} from "@/features/editor/atoms/editor-atoms.ts";
|
|
import { useEditorScroll } from "./hooks/use-editor-scroll";
|
|
import { TransclusionLookupProvider } from "@/features/editor/components/transclusion/transclusion-lookup-context";
|
|
import LightboxView, {
|
|
getLightboxClickRequest,
|
|
} from "@/features/editor/components/common/lightbox-view";
|
|
|
|
interface PageEditorProps {
|
|
title: string;
|
|
content: any;
|
|
pageId?: string;
|
|
printMode?: boolean;
|
|
/**
|
|
* When rendering inside a public share, pass the share's id (or key). Lookups
|
|
* for transclusion content then resolve against the share graph instead of
|
|
* the viewer's personal permissions, so a share never leaks source content
|
|
* that isn't itself shared.
|
|
*/
|
|
shareId?: string;
|
|
}
|
|
|
|
export default function ReadonlyPageEditor({
|
|
title,
|
|
content,
|
|
pageId,
|
|
printMode = false,
|
|
shareId,
|
|
}: PageEditorProps) {
|
|
const [, setReadOnlyEditor] = useAtom(readOnlyEditorAtom);
|
|
const [lightboxRequest, setLightboxRequest] = useAtom(lightboxRequestAtom);
|
|
const [contentEditor, setContentEditor] = useState<Editor | null>(null);
|
|
const isComponentMounted = useRef(false);
|
|
const editorCreated = useRef(false);
|
|
|
|
const canScroll = useCallback(
|
|
() => isComponentMounted.current && editorCreated.current,
|
|
[isComponentMounted, editorCreated],
|
|
);
|
|
const initialScrollTo = window.location.hash
|
|
? window.location.hash.slice(1)
|
|
: "";
|
|
const { handleScrollTo } = useEditorScroll({ canScroll, initialScrollTo });
|
|
|
|
useEffect(() => {
|
|
isComponentMounted.current = true;
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!shareId) return;
|
|
setLightboxRequest(null);
|
|
}, [pageId, shareId]);
|
|
|
|
const extensions = useMemo(() => {
|
|
const excludedExtensions = new Set([
|
|
"uniqueID",
|
|
...(printMode ? ["tableHeaderPin", "tableReadonlySort"] : []),
|
|
]);
|
|
const filteredExtensions = mainExtensions.filter(
|
|
(ext) => !excludedExtensions.has(ext.name),
|
|
);
|
|
|
|
return [
|
|
...filteredExtensions,
|
|
UniqueID.configure({
|
|
types: ["heading", "paragraph"],
|
|
updateDocument: false,
|
|
}),
|
|
];
|
|
}, [printMode]);
|
|
|
|
const titleExtensions = [
|
|
Document.extend({
|
|
content: "heading",
|
|
}),
|
|
Heading,
|
|
Text,
|
|
Placeholder.configure({
|
|
placeholder: "Untitled",
|
|
showOnlyWhenEditable: false,
|
|
}),
|
|
];
|
|
|
|
return (
|
|
<TransclusionLookupProvider shareId={shareId}>
|
|
<div className="page-title">
|
|
<EditorProvider
|
|
editable={false}
|
|
immediatelyRender={true}
|
|
textDirection="auto"
|
|
extensions={titleExtensions}
|
|
content={title}
|
|
></EditorProvider>
|
|
</div>
|
|
|
|
<EditorProvider
|
|
editable={false}
|
|
immediatelyRender={true}
|
|
textDirection="auto"
|
|
extensions={extensions}
|
|
content={content}
|
|
editorProps={
|
|
shareId
|
|
? {
|
|
handleClickOn: (_view, _pos, node) => {
|
|
const request = getLightboxClickRequest(node);
|
|
if (!request) return false;
|
|
|
|
setLightboxRequest(request);
|
|
return true;
|
|
},
|
|
}
|
|
: undefined
|
|
}
|
|
onCreate={({ editor }) => {
|
|
if (editor) {
|
|
if (pageId) {
|
|
// @ts-ignore
|
|
editor.storage.pageId = pageId;
|
|
}
|
|
// @ts-ignore
|
|
setReadOnlyEditor(editor);
|
|
setContentEditor(editor);
|
|
|
|
handleScrollTo(editor);
|
|
editorCreated.current = true;
|
|
}
|
|
}}
|
|
></EditorProvider>
|
|
{shareId && contentEditor && (
|
|
<LightboxView
|
|
editor={contentEditor}
|
|
open={!!lightboxRequest}
|
|
src={lightboxRequest?.src ?? ""}
|
|
type={lightboxRequest?.type ?? "image"}
|
|
onClose={() => setLightboxRequest(null)}
|
|
/>
|
|
)}
|
|
<div style={{ paddingBottom: "20vh" }}></div>
|
|
</TransclusionLookupProvider>
|
|
);
|
|
}
|