mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: migrate old data logic
This commit is contained in:
parent
f4faa1e0b2
commit
b4ccc720b5
@ -1,5 +1,7 @@
|
||||
import { generateJSON, getSchema } from "@tiptap/core";
|
||||
import { Selection } from "@tiptap/pm/state";
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { CoreEditorExtensionsWithoutProps } from "src/ui/extensions/core-without-props";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
interface EditorClassNames {
|
||||
noBorder?: boolean;
|
||||
@ -58,3 +60,15 @@ export const isValidHttpUrl = (string: string): boolean => {
|
||||
|
||||
return url.protocol === "http:" || url.protocol === "https:";
|
||||
};
|
||||
|
||||
export const generateJSONfromHTML = (html: string) => {
|
||||
const extensions = CoreEditorExtensionsWithoutProps();
|
||||
// @ts-expect-error update types
|
||||
const contentJSON = generateJSON(html ?? "<p></p>", extensions);
|
||||
// @ts-expect-error update types
|
||||
const editorSchema = getSchema(extensions);
|
||||
return {
|
||||
contentJSON,
|
||||
editorSchema,
|
||||
};
|
||||
};
|
||||
|
121
packages/editor/core/src/ui/extensions/core-without-props.tsx
Normal file
121
packages/editor/core/src/ui/extensions/core-without-props.tsx
Normal file
@ -0,0 +1,121 @@
|
||||
import TaskItem from "@tiptap/extension-task-item";
|
||||
import TaskList from "@tiptap/extension-task-list";
|
||||
import TextStyle from "@tiptap/extension-text-style";
|
||||
import TiptapUnderline from "@tiptap/extension-underline";
|
||||
import Placeholder from "@tiptap/extension-placeholder";
|
||||
import { Markdown } from "tiptap-markdown";
|
||||
|
||||
import { Table } from "src/ui/extensions/table/table";
|
||||
import { TableCell } from "src/ui/extensions/table/table-cell/table-cell";
|
||||
import { TableHeader } from "src/ui/extensions/table/table-header/table-header";
|
||||
import { TableRow } from "src/ui/extensions/table/table-row/table-row";
|
||||
|
||||
import { isValidHttpUrl } from "src/lib/utils";
|
||||
|
||||
import { CustomCodeBlockExtension } from "src/ui/extensions/code";
|
||||
import { CustomKeymap } from "src/ui/extensions/keymap";
|
||||
import { CustomQuoteExtension } from "src/ui/extensions/quote";
|
||||
|
||||
import { CustomLinkExtension } from "src/ui/extensions/custom-link";
|
||||
import { CustomCodeInlineExtension } from "src/ui/extensions/code-inline";
|
||||
import { CustomTypographyExtension } from "src/ui/extensions/typography";
|
||||
import { CustomHorizontalRule } from "src/ui/extensions/horizontal-rule/horizontal-rule";
|
||||
import { CustomCodeMarkPlugin } from "src/ui/extensions/custom-code-inline/inline-code-plugin";
|
||||
import { MentionsWithoutProps } from "src/ui/mentions/mention-without-props";
|
||||
import { ImageExtensionWithoutProps } from "src/ui/extensions/image/image-extension-without-props";
|
||||
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
|
||||
export const CoreEditorExtensionsWithoutProps = () => [
|
||||
StarterKit.configure({
|
||||
bulletList: {
|
||||
HTMLAttributes: {
|
||||
class: "list-disc pl-7 space-y-2",
|
||||
},
|
||||
},
|
||||
orderedList: {
|
||||
HTMLAttributes: {
|
||||
class: "list-decimal pl-7 space-y-2",
|
||||
},
|
||||
},
|
||||
listItem: {
|
||||
HTMLAttributes: {
|
||||
class: "not-prose space-y-2",
|
||||
},
|
||||
},
|
||||
code: false,
|
||||
codeBlock: false,
|
||||
horizontalRule: false,
|
||||
blockquote: false,
|
||||
dropcursor: {
|
||||
color: "rgba(var(--color-text-100))",
|
||||
width: 1,
|
||||
},
|
||||
}),
|
||||
CustomQuoteExtension,
|
||||
CustomHorizontalRule.configure({
|
||||
HTMLAttributes: {
|
||||
class: "my-4 border-custom-border-400",
|
||||
},
|
||||
}),
|
||||
CustomKeymap,
|
||||
// ListKeymap,
|
||||
CustomLinkExtension.configure({
|
||||
openOnClick: true,
|
||||
autolink: true,
|
||||
linkOnPaste: true,
|
||||
protocols: ["http", "https"],
|
||||
validate: (url: string) => isValidHttpUrl(url),
|
||||
HTMLAttributes: {
|
||||
class:
|
||||
"text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
|
||||
},
|
||||
}),
|
||||
CustomTypographyExtension,
|
||||
ImageExtensionWithoutProps().configure({
|
||||
HTMLAttributes: {
|
||||
class: "rounded-md",
|
||||
},
|
||||
}),
|
||||
TiptapUnderline,
|
||||
TextStyle,
|
||||
TaskList.configure({
|
||||
HTMLAttributes: {
|
||||
class: "not-prose pl-2 space-y-2",
|
||||
},
|
||||
}),
|
||||
TaskItem.configure({
|
||||
HTMLAttributes: {
|
||||
class: "flex",
|
||||
},
|
||||
nested: true,
|
||||
}),
|
||||
CustomCodeBlockExtension.configure({
|
||||
HTMLAttributes: {
|
||||
class: "",
|
||||
},
|
||||
}),
|
||||
CustomCodeMarkPlugin,
|
||||
CustomCodeInlineExtension,
|
||||
Markdown.configure({
|
||||
html: true,
|
||||
transformPastedText: true,
|
||||
}),
|
||||
Table,
|
||||
TableHeader,
|
||||
TableCell,
|
||||
TableRow,
|
||||
MentionsWithoutProps(),
|
||||
Placeholder.configure({
|
||||
placeholder: ({ editor, node }) => {
|
||||
if (node.type.name === "heading") return `Heading ${node.attrs.level}`;
|
||||
|
||||
const shouldHidePlaceholder =
|
||||
editor.isActive("table") || editor.isActive("codeBlock") || editor.isActive("image");
|
||||
if (shouldHidePlaceholder) return "";
|
||||
|
||||
return "Press '/' for commands...";
|
||||
},
|
||||
includeChildren: true,
|
||||
}),
|
||||
];
|
@ -0,0 +1,33 @@
|
||||
import ImageExt from "@tiptap/extension-image";
|
||||
import { insertLineBelowImageAction } from "./utilities/insert-line-below-image";
|
||||
import { insertLineAboveImageAction } from "./utilities/insert-line-above-image";
|
||||
|
||||
export const ImageExtensionWithoutProps = () =>
|
||||
ImageExt.extend({
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
ArrowDown: insertLineBelowImageAction,
|
||||
ArrowUp: insertLineAboveImageAction,
|
||||
};
|
||||
},
|
||||
|
||||
// storage to keep track of image states Map<src, isDeleted>
|
||||
addStorage() {
|
||||
return {
|
||||
images: new Map<string, boolean>(),
|
||||
uploadInProgress: false,
|
||||
};
|
||||
},
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
...this.parent?.(),
|
||||
width: {
|
||||
default: "35%",
|
||||
},
|
||||
height: {
|
||||
default: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
@ -0,0 +1,79 @@
|
||||
import { CustomMention } from "./custom";
|
||||
import { ReactRenderer } from "@tiptap/react";
|
||||
import { Editor } from "@tiptap/core";
|
||||
import tippy from "tippy.js";
|
||||
|
||||
import { MentionList } from "./mention-list";
|
||||
|
||||
export const MentionsWithoutProps = () =>
|
||||
CustomMention.configure({
|
||||
HTMLAttributes: {
|
||||
class: "mention",
|
||||
},
|
||||
// mentionHighlights: mentionHighlights,
|
||||
suggestion: {
|
||||
// @ts-expect-error - Tiptap types are incorrect
|
||||
render: () => {
|
||||
let component: ReactRenderer | null = null;
|
||||
let popup: any | null = null;
|
||||
|
||||
return {
|
||||
onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
|
||||
if (!props.clientRect) {
|
||||
return;
|
||||
}
|
||||
component = new ReactRenderer(MentionList, {
|
||||
props: { ...props },
|
||||
editor: props.editor,
|
||||
});
|
||||
props.editor.storage.mentionsOpen = true;
|
||||
// @ts-expect-error - Tippy types are incorrect
|
||||
popup = tippy("body", {
|
||||
getReferenceClientRect: props.clientRect,
|
||||
appendTo: () => document.querySelector(".active-editor") ?? document.querySelector("#editor-container"),
|
||||
content: component.element,
|
||||
showOnCreate: true,
|
||||
interactive: true,
|
||||
trigger: "manual",
|
||||
placement: "bottom-start",
|
||||
});
|
||||
},
|
||||
onUpdate: (props: { editor: Editor; clientRect: DOMRect }) => {
|
||||
component?.updateProps(props);
|
||||
|
||||
if (!props.clientRect) {
|
||||
return;
|
||||
}
|
||||
|
||||
popup &&
|
||||
popup[0].setProps({
|
||||
getReferenceClientRect: props.clientRect,
|
||||
});
|
||||
},
|
||||
|
||||
onKeyDown: (props: { event: KeyboardEvent }) => {
|
||||
if (props.event.key === "Escape") {
|
||||
popup?.[0].hide();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const navigationKeys = ["ArrowUp", "ArrowDown", "Enter"];
|
||||
|
||||
if (navigationKeys.includes(props.event.key)) {
|
||||
// @ts-expect-error - Tippy types are incorrect
|
||||
component?.ref?.onKeyDown(props);
|
||||
event?.stopPropagation();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onExit: (props: { editor: Editor; event: KeyboardEvent }) => {
|
||||
props.editor.storage.mentionsOpen = false;
|
||||
popup?.[0].destroy();
|
||||
component?.destroy();
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import { useLayoutEffect, useMemo } from "react";
|
||||
import { useEffect, useLayoutEffect, useMemo } from "react";
|
||||
import { EditorProps } from "@tiptap/pm/view";
|
||||
import { IndexeddbPersistence } from "y-indexeddb";
|
||||
import * as Y from "yjs";
|
||||
@ -10,12 +10,11 @@ import { CollaborationProvider } from "src/providers/collaboration-provider";
|
||||
import { DocumentEditorExtensions } from "src/ui/extensions";
|
||||
|
||||
type DocumentEditorProps = {
|
||||
id?: string;
|
||||
id: string;
|
||||
fileHandler: TFileHandler;
|
||||
value: Uint8Array;
|
||||
editorClassName: string;
|
||||
onChange: (binaryString: string) => void;
|
||||
extensions?: any;
|
||||
editorProps?: EditorProps;
|
||||
forwardedRef?: React.MutableRefObject<EditorRefApi | null>;
|
||||
mentionHandler: {
|
||||
@ -29,7 +28,7 @@ type DocumentEditorProps = {
|
||||
};
|
||||
|
||||
export const useDocumentEditor = ({
|
||||
id = "",
|
||||
id,
|
||||
editorProps = {},
|
||||
value,
|
||||
editorClassName,
|
||||
@ -52,11 +51,10 @@ export const useDocumentEditor = ({
|
||||
[id]
|
||||
);
|
||||
|
||||
const yDoc = useMemo(() => {
|
||||
// update document on value change
|
||||
useEffect(() => {
|
||||
if (value.byteLength > 0) Y.applyUpdate(provider.document, value);
|
||||
return provider.document;
|
||||
}, [value, provider.document]);
|
||||
console.log("yDoc", yDoc);
|
||||
|
||||
// indexedDB provider
|
||||
useLayoutEffect(() => {
|
||||
|
@ -3,6 +3,8 @@ export { DocumentReadOnlyEditor, DocumentReadOnlyEditorWithRef } from "src/ui/re
|
||||
|
||||
// hooks
|
||||
export { useEditorMarkings } from "src/hooks/use-editor-markings";
|
||||
// utils
|
||||
export { proseMirrorJSONToBinaryString } from "src/utils/yjs";
|
||||
|
||||
export type { EditorRefApi, EditorReadOnlyRefApi, EditorMenuItem, EditorMenuItemNames } from "@plane/editor-core";
|
||||
|
||||
|
@ -35,6 +35,7 @@ export class CollaborationProvider {
|
||||
|
||||
this.configuration.document = configuration.document ?? new Y.Doc();
|
||||
this.document.on("update", this.documentUpdateHandler.bind(this));
|
||||
this.document.on("destroy", this.documentDestroyHandler.bind(this));
|
||||
}
|
||||
|
||||
public setConfiguration(configuration: Partial<CompleteCollaboratorProviderConfiguration> = {}): void {
|
||||
@ -64,4 +65,10 @@ export class CollaborationProvider {
|
||||
this.timeoutId = null;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
documentDestroyHandler() {
|
||||
if (this.timeoutId !== null) clearTimeout(this.timeoutId);
|
||||
this.document.off("update", this.documentUpdateHandler);
|
||||
this.document.off("destroy", this.documentDestroyHandler);
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ const DocumentEditor = (props: IDocumentEditor) => {
|
||||
onChange,
|
||||
id,
|
||||
value,
|
||||
// value,
|
||||
fileHandler,
|
||||
containerClassName,
|
||||
editorClassName = "",
|
||||
|
50
packages/editor/document-editor/src/utils/yjs.ts
Normal file
50
packages/editor/document-editor/src/utils/yjs.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { Schema } from "@tiptap/pm/model";
|
||||
import { prosemirrorJSONToYDoc } from "y-prosemirror";
|
||||
import * as Y from "yjs";
|
||||
|
||||
const defaultSchema: Schema = new Schema({
|
||||
nodes: {
|
||||
text: {},
|
||||
doc: { content: "text*" },
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @description converts ProseMirror JSON to Yjs document
|
||||
* @param document prosemirror JSON
|
||||
* @param fieldName
|
||||
* @param schema
|
||||
* @returns {Y.Doc} Yjs document
|
||||
*/
|
||||
export const proseMirrorJSONToBinaryString = (
|
||||
document: any,
|
||||
fieldName: string | Array<string> = "default",
|
||||
schema?: Schema
|
||||
): string => {
|
||||
if (!document) {
|
||||
throw new Error(
|
||||
`You've passed an empty or invalid document to the Transformer. Make sure to pass ProseMirror-compatible JSON. Actually passed JSON: ${document}`
|
||||
);
|
||||
}
|
||||
|
||||
// allow a single field name
|
||||
if (typeof fieldName === "string") {
|
||||
const yDoc = prosemirrorJSONToYDoc(schema ?? defaultSchema, document, fieldName);
|
||||
const docAsUint8Array = Y.encodeStateAsUpdate(yDoc);
|
||||
const base64Doc = Buffer.from(docAsUint8Array).toString("base64");
|
||||
return base64Doc;
|
||||
}
|
||||
|
||||
const yDoc = new Y.Doc();
|
||||
|
||||
fieldName.forEach((field) => {
|
||||
const update = Y.encodeStateAsUpdate(prosemirrorJSONToYDoc(schema ?? defaultSchema, document, field));
|
||||
|
||||
Y.applyUpdate(yDoc, update);
|
||||
});
|
||||
|
||||
const docAsUint8Array = Y.encodeStateAsUpdate(yDoc);
|
||||
const base64Doc = Buffer.from(docAsUint8Array).toString("base64");
|
||||
|
||||
return base64Doc;
|
||||
};
|
@ -1,15 +1,17 @@
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
// document editor
|
||||
// editor
|
||||
import {
|
||||
DocumentEditorWithRef,
|
||||
DocumentReadOnlyEditorWithRef,
|
||||
EditorReadOnlyRefApi,
|
||||
EditorRefApi,
|
||||
IMarking,
|
||||
proseMirrorJSONToBinaryString,
|
||||
} from "@plane/document-editor";
|
||||
import { generateJSONfromHTML } from "@plane/editor-core";
|
||||
// types
|
||||
import { IUserLite } from "@plane/types";
|
||||
// components
|
||||
@ -53,6 +55,8 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
||||
sidePeekVisible,
|
||||
updateMarkings,
|
||||
} = props;
|
||||
// states
|
||||
const [isDescriptionReady, setIsDescriptionReady] = useState(false);
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
@ -65,10 +69,10 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
||||
} = useMember();
|
||||
// derived values
|
||||
const workspaceId = workspaceSlug ? getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "" : "";
|
||||
const pageId = pageStore?.id ?? "";
|
||||
const pageId = pageStore?.id;
|
||||
const pageTitle = pageStore?.name ?? "";
|
||||
const pageDescription = pageStore?.description_html;
|
||||
const { description_html, isContentEditable, isSubmitting, updateTitle, setIsSubmitting } = pageStore;
|
||||
const { isContentEditable, isSubmitting, updateTitle, updateDescription, setIsSubmitting } = pageStore;
|
||||
const projectMemberIds = projectId ? getProjectMemberIds(projectId.toString()) : [];
|
||||
const projectMemberDetails = projectMemberIds?.map((id) => getUserDetails(id) as IUserLite);
|
||||
// use-mention
|
||||
@ -83,22 +87,41 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
||||
|
||||
useReloadConfirmations(isSubmitting === "submitting");
|
||||
|
||||
const { data: descriptionYJS } = useSWR(
|
||||
const { data: descriptionYJS, mutate: mutateDescriptionYJS } = useSWR(
|
||||
workspaceSlug && projectId && pageId ? `PAGE_DESCRIPTION_${workspaceSlug}_${projectId}_${pageId}` : null,
|
||||
workspaceSlug && projectId && pageId
|
||||
? () => pageService.fetchDescriptionYJS(workspaceSlug.toString(), projectId.toString(), pageId.toString())
|
||||
: null,
|
||||
{
|
||||
refreshInterval: 20000,
|
||||
refreshInterval: 15000,
|
||||
revalidateOnFocus: true,
|
||||
revalidateOnReconnect: true,
|
||||
}
|
||||
);
|
||||
const pageDescriptionYJS = new Uint8Array(descriptionYJS);
|
||||
const pageDescriptionYJS = useMemo(
|
||||
() => (descriptionYJS ? new Uint8Array(descriptionYJS) : undefined),
|
||||
[descriptionYJS]
|
||||
);
|
||||
|
||||
// if description_yjs field is empty, convert description_html to yDoc and update the DB
|
||||
// TODO: this is a one-time operation, and needs to be removed once all the pages are updated
|
||||
useEffect(() => {
|
||||
if (!pageDescriptionYJS || !pageDescription) return;
|
||||
if (pageDescriptionYJS.byteLength === 0) {
|
||||
const { contentJSON, editorSchema } = generateJSONfromHTML(pageDescription ?? "<p></p>");
|
||||
const yDocBinaryString = proseMirrorJSONToBinaryString(contentJSON, "default", editorSchema);
|
||||
updateDescription(yDocBinaryString, pageDescription ?? "<p></p>").then(async () => {
|
||||
await mutateDescriptionYJS();
|
||||
setIsDescriptionReady(true);
|
||||
});
|
||||
} else setIsDescriptionReady(true);
|
||||
}, [mutateDescriptionYJS, pageDescription, pageDescriptionYJS, updateDescription]);
|
||||
|
||||
useEffect(() => {
|
||||
updateMarkings(description_html ?? "<p></p>");
|
||||
}, [description_html, updateMarkings]);
|
||||
updateMarkings(pageDescription ?? "<p></p>");
|
||||
}, [pageDescription, updateMarkings]);
|
||||
|
||||
if (pageId === undefined || !descriptionYJS || !pageDescriptionYJS) return <PageContentLoader />;
|
||||
if (pageId === undefined || !pageDescriptionYJS || !isDescriptionReady) return <PageContentLoader />;
|
||||
|
||||
return (
|
||||
<div className="flex items-center h-full w-full overflow-y-auto">
|
||||
|
@ -4,6 +4,5 @@ export * from "./header";
|
||||
export * from "./list";
|
||||
export * from "./loaders";
|
||||
export * from "./modals";
|
||||
export * from "./page-detail";
|
||||
export * from "./pages-list-main-content";
|
||||
export * from "./pages-list-view";
|
||||
|
@ -2,27 +2,116 @@
|
||||
import { Loader } from "@plane/ui";
|
||||
|
||||
export const PageContentLoader = () => (
|
||||
<div className="flex">
|
||||
<div className="w-[5%]" />
|
||||
<Loader className="flex-shrink-0 flex-grow">
|
||||
<div className="mt-10 space-y-2">
|
||||
<Loader.Item height="20px" />
|
||||
<Loader.Item height="20px" width="80%" />
|
||||
<Loader.Item height="20px" width="80%" />
|
||||
<div className="relative w-full h-full flex flex-col">
|
||||
{/* header */}
|
||||
<div className="px-4 flex-shrink-0 relative flex items-center justify-between h-12 border-b border-custom-border-100">
|
||||
{/* left options */}
|
||||
<Loader className="flex-shrink-0 w-[280px]">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
|
||||
{/* editor options */}
|
||||
<div className="w-full relative flex items-center divide-x divide-custom-border-100">
|
||||
<Loader className="relative flex items-center gap-1 pr-2">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
<Loader className="relative flex items-center gap-1 px-2">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
<Loader className="relative flex items-center gap-1 px-2">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
<Loader className="relative flex items-center gap-1 pl-2">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
</div>
|
||||
<div className="mt-12 space-y-10">
|
||||
{Array.from(Array(4)).map((i) => (
|
||||
<div key={i}>
|
||||
<Loader.Item height="25px" width="20%" />
|
||||
<div className="mt-5 space-y-3">
|
||||
<Loader.Item height="15px" width="40%" />
|
||||
<Loader.Item height="15px" width="30%" />
|
||||
<Loader.Item height="15px" width="35%" />
|
||||
|
||||
{/* right options */}
|
||||
<Loader className="w-full relative flex justify-end items-center gap-1">
|
||||
<Loader.Item width="60px" height="26px" />
|
||||
<Loader.Item width="40px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
</div>
|
||||
|
||||
{/* content */}
|
||||
<div className="px-4 w-full h-full overflow-hidden relative flex">
|
||||
{/* table of content loader */}
|
||||
<div className="flex-shrink-0 w-[280px] pr-5 py-5">
|
||||
<Loader className="w-full space-y-4">
|
||||
<Loader.Item width="100%" height="24px" />
|
||||
<div className="space-y-2">
|
||||
<Loader.Item width="60%" height="12px" />
|
||||
<div className="ml-6 space-y-2">
|
||||
<Loader.Item width="80%" height="12px" />
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
</div>
|
||||
<Loader.Item width="60%" height="12px" />
|
||||
<div className="ml-6 space-y-2">
|
||||
<Loader.Item width="80%" height="12px" />
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
</div>
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
<Loader.Item width="60%" height="12px" />
|
||||
<div className="ml-6 space-y-2">
|
||||
<Loader.Item width="80%" height="12px" />
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
</div>
|
||||
<Loader.Item width="80%" height="12px" />
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
</div>
|
||||
</Loader>
|
||||
</div>
|
||||
|
||||
{/* editor loader */}
|
||||
<div className="w-full h-full py-5">
|
||||
<Loader className="relative space-y-4">
|
||||
<Loader.Item width="50%" height="36px" />
|
||||
<div className="space-y-2">
|
||||
<div className="py-2">
|
||||
<Loader.Item width="100%" height="36px" />
|
||||
</div>
|
||||
<Loader.Item width="80%" height="22px" />
|
||||
<div className="relative flex items-center gap-2">
|
||||
<Loader.Item width="30px" height="30px" />
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<Loader.Item width="60%" height="36px" />
|
||||
</div>
|
||||
<Loader.Item width="70%" height="22px" />
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
<div className="relative flex items-center gap-2">
|
||||
<Loader.Item width="30px" height="30px" />
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<Loader.Item width="50%" height="30px" />
|
||||
</div>
|
||||
<Loader.Item width="100%" height="22px" />
|
||||
<div className="py-2">
|
||||
<Loader.Item width="30%" height="30px" />
|
||||
</div>
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
<div className="relative flex items-center gap-2">
|
||||
<div className="py-2">
|
||||
<Loader.Item width="30px" height="30px" />
|
||||
</div>
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</Loader>
|
||||
</div>
|
||||
</Loader>
|
||||
<div className="w-[5%]" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,3 +0,0 @@
|
||||
export * from "./loader";
|
||||
|
||||
export * from "./root";
|
@ -1,118 +0,0 @@
|
||||
import { FC } from "react";
|
||||
// components/ui
|
||||
import { Loader } from "@plane/ui";
|
||||
|
||||
export const PageDetailRootLoader: FC = () => (
|
||||
<div className=" relative w-full h-full flex flex-col">
|
||||
{/* header */}
|
||||
<div className="px-4 flex-shrink-0 relative flex items-center justify-between h-12 border-b border-custom-border-100">
|
||||
{/* left options */}
|
||||
<Loader className="flex-shrink-0 w-[280px]">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
|
||||
{/* editor options */}
|
||||
<div className="w-full relative flex items-center divide-x divide-custom-border-100">
|
||||
<Loader className="relative flex items-center gap-1 pr-2">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
<Loader className="relative flex items-center gap-1 px-2">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
<Loader className="relative flex items-center gap-1 px-2">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
<Loader className="relative flex items-center gap-1 pl-2">
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
</div>
|
||||
|
||||
{/* right options */}
|
||||
<Loader className="w-full relative flex justify-end items-center gap-1">
|
||||
<Loader.Item width="60px" height="26px" />
|
||||
<Loader.Item width="40px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
<Loader.Item width="26px" height="26px" />
|
||||
</Loader>
|
||||
</div>
|
||||
|
||||
{/* content */}
|
||||
<div className="px-4 w-full h-full overflow-hidden relative flex">
|
||||
{/* table of content loader */}
|
||||
<div className="flex-shrink-0 w-[280px] pr-5 py-5">
|
||||
<Loader className="w-full space-y-4">
|
||||
<Loader.Item width="100%" height="24px" />
|
||||
<div className="space-y-2">
|
||||
<Loader.Item width="60%" height="12px" />
|
||||
<div className="ml-6 space-y-2">
|
||||
<Loader.Item width="80%" height="12px" />
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
</div>
|
||||
<Loader.Item width="60%" height="12px" />
|
||||
<div className="ml-6 space-y-2">
|
||||
<Loader.Item width="80%" height="12px" />
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
</div>
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
<Loader.Item width="60%" height="12px" />
|
||||
<div className="ml-6 space-y-2">
|
||||
<Loader.Item width="80%" height="12px" />
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
</div>
|
||||
<Loader.Item width="80%" height="12px" />
|
||||
<Loader.Item width="100%" height="12px" />
|
||||
</div>
|
||||
</Loader>
|
||||
</div>
|
||||
|
||||
{/* editor loader */}
|
||||
<div className="w-full h-full py-5">
|
||||
<Loader className="relative space-y-4">
|
||||
<Loader.Item width="50%" height="36px" />
|
||||
<div className="space-y-2">
|
||||
<div className="py-2">
|
||||
<Loader.Item width="100%" height="36px" />
|
||||
</div>
|
||||
<Loader.Item width="80%" height="22px" />
|
||||
<div className="relative flex items-center gap-2">
|
||||
<Loader.Item width="30px" height="30px" />
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<Loader.Item width="60%" height="36px" />
|
||||
</div>
|
||||
<Loader.Item width="70%" height="22px" />
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
<div className="relative flex items-center gap-2">
|
||||
<Loader.Item width="30px" height="30px" />
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<Loader.Item width="50%" height="30px" />
|
||||
</div>
|
||||
<Loader.Item width="100%" height="22px" />
|
||||
<div className="py-2">
|
||||
<Loader.Item width="30%" height="30px" />
|
||||
</div>
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
<div className="relative flex items-center gap-2">
|
||||
<div className="py-2">
|
||||
<Loader.Item width="30px" height="30px" />
|
||||
</div>
|
||||
<Loader.Item width="30%" height="22px" />
|
||||
</div>
|
||||
</div>
|
||||
</Loader>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
@ -1,54 +0,0 @@
|
||||
import { FC, Fragment } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
// hooks
|
||||
import { PageHead } from "@/components/core";
|
||||
import { useProjectPages, usePage } from "@/hooks/store";
|
||||
// components
|
||||
import { PageDetailRootLoader } from "./";
|
||||
|
||||
type TPageDetailRoot = {
|
||||
projectId: string;
|
||||
pageId: string;
|
||||
};
|
||||
|
||||
export const PageDetailRoot: FC<TPageDetailRoot> = observer((props) => {
|
||||
const { projectId, pageId } = props;
|
||||
// hooks
|
||||
const { loader } = useProjectPages(projectId);
|
||||
const { id, name } = usePage(pageId);
|
||||
|
||||
if (loader === "init-loader") return <PageDetailRootLoader />;
|
||||
|
||||
if (!id) return <div className="">No page is available.</div>;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHead title={name || "Pages"} />
|
||||
|
||||
<div className="relative w-full h-full flex flex-col">
|
||||
<div className="flex-shrink-0 px-4 relative flex items-center justify-between h-12 border-b border-custom-border-100">
|
||||
{/* header left container */}
|
||||
<div className="flex-shrink-0 w-[280px]">Icon</div>
|
||||
{/* header editor tool container */}
|
||||
<div className="w-full relative hidden md:flex items-center divide-x divide-custom-border-100 ">
|
||||
Editor keys
|
||||
</div>
|
||||
{/* header right operations container */}
|
||||
<div className="w-full relative flex justify-end">right saved</div>
|
||||
</div>
|
||||
|
||||
{/* editor container for small screens */}
|
||||
<div className="px-4 h-12 relative flex md:hidden items-center border-b border-custom-border-100">
|
||||
Editor keys
|
||||
</div>
|
||||
|
||||
<div className="px-4 w-full h-full overflow-hidden relative flex">
|
||||
{/* editor table of content content container */}
|
||||
<div className="flex-shrink-0 w-[280px] pr-5 py-5">Table of content</div>
|
||||
{/* editor container */}
|
||||
<div className="w-full h-full py-5">Editor Container</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
});
|
244
yarn.lock
244
yarn.lock
@ -2373,20 +2373,25 @@
|
||||
dependencies:
|
||||
tippy.js "^6.3.1"
|
||||
|
||||
"@tiptap/core@^2.1.13", "@tiptap/core@^2.3.1":
|
||||
"@tiptap/core@^2.1.13":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.3.1.tgz#e6980554882899b2c600f40b688c33b6b58628c2"
|
||||
integrity sha512-ycpQlmczAOc05TgB5sc3RUTEEBXAVmS8MR9PqQzg96qidaRfVkgE+2w4k7t83PMHl2duC0MGqOCy96pLYwSpeg==
|
||||
|
||||
"@tiptap/extension-blockquote@^2.1.13", "@tiptap/extension-blockquote@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.3.1.tgz#df779c2143a445f741a6277ef134b705d52bbc8b"
|
||||
integrity sha512-eyw3/Zn/XbIP2Yo11iE4vYcJ0471aBPMLD56YOyUC0PIF7D5tvPutDesSg95R+BDa5Tq/Id2zV5pZerw1dwwOQ==
|
||||
"@tiptap/core@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.4.0.tgz#6f8eee8beb5b89363582366b201ccc4798ac98a9"
|
||||
integrity sha512-YJSahk8pkxpCs8SflCZfTnJpE7IPyUWIylfgXM2DefjRQa5DZ+c6sNY0s/zbxKYFQ6AuHVX40r9pCfcqHChGxQ==
|
||||
|
||||
"@tiptap/extension-bold@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.3.1.tgz#73ccc70b339b95bc68f452851933fdd1d45c7c98"
|
||||
integrity sha512-szHDXKOQfrlCzsys401zBtPWE5gyY3LcpPlrn2zBRrBmzU2U/1A7Y3HkoqZo3SSrTY37eG1Vr2J2aHySK6Uj/w==
|
||||
"@tiptap/extension-blockquote@^2.1.13", "@tiptap/extension-blockquote@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.4.0.tgz#0179076ea2fa12e41a198dad087b81d368653b8d"
|
||||
integrity sha512-nJJy4KsPgQqWTTDOWzFRdjCfG5+QExfZj44dulgDFNh+E66xhamnbM70PklllXJgEcge7xmT5oKM0gKls5XgFw==
|
||||
|
||||
"@tiptap/extension-bold@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.4.0.tgz#b5ced2c3bf51f304890137dbdf394d58c01eb208"
|
||||
integrity sha512-csnW6hMDEHoRfxcPRLSqeJn+j35Lgtt1YRiOwn7DlS66sAECGRuoGfCvQSPij0TCDp4VCR9if5Sf8EymhnQumQ==
|
||||
|
||||
"@tiptap/extension-bubble-menu@^2.3.1":
|
||||
version "2.3.1"
|
||||
@ -2395,35 +2400,35 @@
|
||||
dependencies:
|
||||
tippy.js "^6.3.7"
|
||||
|
||||
"@tiptap/extension-bullet-list@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.3.1.tgz#7156e4b8898da8b27c5272476d4f8596d8f633cc"
|
||||
integrity sha512-pif0AB4MUoA1Xm26y1ovH7vfXaV19T9EEQH4tgN2g2eTfdFnQWDmKI0r3XRxudtg40RstBJRa81N9xEO79o8ag==
|
||||
"@tiptap/extension-bullet-list@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.4.0.tgz#60eea05b5ac8c8e8d615c057559fddb95033abeb"
|
||||
integrity sha512-9S5DLIvFRBoExvmZ+/ErpTvs4Wf1yOEs8WXlKYUCcZssK7brTFj99XDwpHFA29HKDwma5q9UHhr2OB2o0JYAdw==
|
||||
|
||||
"@tiptap/extension-code-block@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.3.1.tgz#1a3e80133ccd67bd06e1d8383563430e648c3e21"
|
||||
integrity sha512-rM7T+DWuOShariPl5vknNFMesPOFQrhMjmms9Ql636sSxOcnkb0d39NFbUpI/r5noFDC6Km+lAebF0Rx2MxpKQ==
|
||||
"@tiptap/extension-code-block@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.4.0.tgz#b7f1da4825677a2ea6b8e970a1197877551e5dc8"
|
||||
integrity sha512-QWGdv1D56TBGbbJSj2cIiXGJEKguPiAl9ONzJ/Ql1ZksiQsYwx0YHriXX6TOC//T4VIf6NSClHEtwtxWBQ/Csg==
|
||||
|
||||
"@tiptap/extension-code@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.3.1.tgz#cea919becab684688819b29481a5c43ee1ee9c52"
|
||||
integrity sha512-bVX0EnDZoRXnoA7dyoZe7w2gdRjxmFEcsatHLkcr3R3x4k9oSgZXLe1C2jGbjJWr4j32tYXZ1cpKte6f1WUKzg==
|
||||
"@tiptap/extension-code@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.4.0.tgz#3a9fed3585bf49f445505c2e9ad71fd66e117304"
|
||||
integrity sha512-wjhBukuiyJMq4cTcK3RBTzUPV24k5n1eEPlpmzku6ThwwkMdwynnMGMAmSF3fErh3AOyOUPoTTjgMYN2d10SJA==
|
||||
|
||||
"@tiptap/extension-collaboration@^2.3.2":
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-collaboration/-/extension-collaboration-2.3.2.tgz#0780eabbe2e72665ed83f86dc70790589d1d0ff1"
|
||||
integrity sha512-1vN+crj5KgqoJhDV+CrfIrBWDIjfpVxiEWHBk+yQU/G2vmyQfbN/R/5gH6rOw5GT3mHqgWFtCDJo4+H/2Ete4w==
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-collaboration/-/extension-collaboration-2.4.0.tgz#d830694ac61a4b9857ffb77f24585e13a9cd6a0c"
|
||||
integrity sha512-achU+GU9tqxn3zsU61CbwWrCausf0U23MJIpo8vnywOIx6E955by6okHEHoUazLIGVFXVc5DBzBP7bf+Snzk0Q==
|
||||
|
||||
"@tiptap/extension-document@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.3.1.tgz#c2c3a1d1f87e262872012508555eda8227a3bc7a"
|
||||
integrity sha512-uWYbzAV95JnetFBduWRI9n2QbQfmznQ7I6XzfZxuTAO2KcWGvHPBS7F00COO9Y67FZAPMbuQ1njtCJK0nClOPw==
|
||||
"@tiptap/extension-document@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.4.0.tgz#a396b2cbcc8708aa2a0a41d0be481fda4b61c77b"
|
||||
integrity sha512-3jRodQJZDGbXlRPERaloS+IERg/VwzpC1IO6YSJR9jVIsBO6xC29P3cKTQlg1XO7p6ZH/0ksK73VC5BzzTwoHg==
|
||||
|
||||
"@tiptap/extension-dropcursor@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.3.1.tgz#2a594264c9b56c23d9a8e46e8538d6b72860e10f"
|
||||
integrity sha512-xDG1Z01ftRI4mIOY+bPuG53xZ9FfVd6hzjNchwFHRlU3E+/2O+DsEBy/pJuHmpnFx1B/1ANbssoidGvK3LIPYw==
|
||||
"@tiptap/extension-dropcursor@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.4.0.tgz#8f54908f84a4ab7d2d7de7fc0197511138445740"
|
||||
integrity sha512-c46HoG2PEEpSZv5rmS5UX/lJ6/kP1iVO0Ax+6JrNfLEIiDULUoi20NqdjolEa38La2VhWvs+o20OviiTOKEE9g==
|
||||
|
||||
"@tiptap/extension-floating-menu@^2.3.1":
|
||||
version "2.3.1"
|
||||
@ -2432,95 +2437,95 @@
|
||||
dependencies:
|
||||
tippy.js "^6.3.7"
|
||||
|
||||
"@tiptap/extension-gapcursor@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.3.1.tgz#a31d87995ca7d8b58af27e55a14e6eb6b5c0a2c5"
|
||||
integrity sha512-jhMw0LtEV/HVovUDRdoH0QLnBWLDyw4Su7UZ0bkMtsnCO9MujLKths3SKsPstuAckZQKR5smokEytxDHH0aglg==
|
||||
"@tiptap/extension-gapcursor@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.4.0.tgz#2a738509d40f5f856492c11e32b10e4462f71216"
|
||||
integrity sha512-F4y/0J2lseohkFUw9P2OpKhrJ6dHz69ZScABUvcHxjznJLd6+0Zt7014Lw5PA8/m2d/w0fX8LZQ88pZr4quZPQ==
|
||||
|
||||
"@tiptap/extension-hard-break@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.3.1.tgz#c174915cc32865f9c742104d1c75ffa3afc477f4"
|
||||
integrity sha512-HO47iS2KQJLxhZM4ghZz5t2qgESH6D/mKJbjO7jM0eCYEyUfPyYJwV2VgjQP7x+1axcvsrhpzkJrjSg5+KqtQQ==
|
||||
"@tiptap/extension-hard-break@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.4.0.tgz#b5bf5b065827280e450fba8f53d137654509d836"
|
||||
integrity sha512-3+Z6zxevtHza5IsDBZ4lZqvNR3Kvdqwxq/QKCKu9UhJN1DUjsg/l1Jn2NilSQ3NYkBYh2yJjT8CMo9pQIu776g==
|
||||
|
||||
"@tiptap/extension-heading@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.3.1.tgz#ddc5810e41cff528924ac873ff444bb8d715742d"
|
||||
integrity sha512-epdIrg1xpuk5ApnNyM/NJO1dhVZgD7kDPem6QH4fug5UJtCueze942yNzUhCuvckmIegfdferAb1p4ug4674ig==
|
||||
"@tiptap/extension-heading@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.4.0.tgz#16302ce691714244c3d3fa92d2db86a5c895a025"
|
||||
integrity sha512-fYkyP/VMo7YHO76YVrUjd95Qeo0cubWn/Spavmwm1gLTHH/q7xMtbod2Z/F0wd6QHnc7+HGhO7XAjjKWDjldaw==
|
||||
|
||||
"@tiptap/extension-history@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.3.1.tgz#de6ec11ac686856ea1f0806b69452f2e39696baf"
|
||||
integrity sha512-m+W6qTP4V0PHqqKnXw/ma18a62O0Cqp5FDWtSarOuxx6W4FpVr4A3Uxfbp4RigZEYanLcX4UJOWL4nWsFdYWHw==
|
||||
"@tiptap/extension-history@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.4.0.tgz#1dbf8410c091175627414d48a0d857232a8f4094"
|
||||
integrity sha512-gr5qsKAXEVGr1Lyk1598F7drTaEtAxqZiuuSwTCzZzkiwgEQsWMWTWc9F8FlneCEaqe1aIYg6WKWlmYPaFwr0w==
|
||||
|
||||
"@tiptap/extension-horizontal-rule@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.3.1.tgz#82330ab9a6a27484145bc73b9b7d23dce0e5594f"
|
||||
integrity sha512-IPgCFkiT6Y5BSFBQMTXS6gq2Ust6otMzRwddoI0RC8tl/tMftFBEPqYKADWVQeQb4C6AQydRjUbmAwHpBH31Eg==
|
||||
"@tiptap/extension-horizontal-rule@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.4.0.tgz#7f27c0778004602686251af7e2f7a8461a3d77ba"
|
||||
integrity sha512-yDgxy+YxagcEsBbdWvbQiXYxsv3noS1VTuGwc9G7ZK9xPmBHJ5y0agOkB7HskwsZvJHoaSqNRsh7oZTkf0VR3g==
|
||||
|
||||
"@tiptap/extension-image@^2.1.13":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.3.1.tgz#3dd730a69bb2fc432b908ca5231cb32f7dcce77e"
|
||||
integrity sha512-3RhVBySQA2LbftWhtZ0p2Mqf9lihNAYs3uQ3iyaB+BYViQiHyVpui09Wny0BwNy0oV6ryUWjBifko2Z1AZgANw==
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.4.0.tgz#21a18e80ed6bc330cf8ab2ca990a3addb40916c8"
|
||||
integrity sha512-NIVhRPMO/ONo8OywEd+8zh0Q6Q7EbFHtBxVsvfOKj9KtZkaXQfUO4MzONTyptkvAchTpj9pIzeaEY5fyU87gFA==
|
||||
|
||||
"@tiptap/extension-italic@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.3.1.tgz#376a1957dff7b687ce247f8a79dc397cb9c7565a"
|
||||
integrity sha512-yEAn0dT1LH1vAULmZv3L1fs7M1Fn/8wZCw7LDGw2/E+VYbDeXgy7XwMPyzhrzV1oV9Z+3gugCbYV0IJ4PBwudA==
|
||||
"@tiptap/extension-italic@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.4.0.tgz#42ab003e04e1e8d825f698914c0e80ac849144f1"
|
||||
integrity sha512-aaW/L9q+KNHHK+X73MPloHeIsT191n3VLd3xm6uUcFDnUNvzYJ/q65/1ZicdtCaOLvTutxdrEvhbkrVREX6a8g==
|
||||
|
||||
"@tiptap/extension-list-item@^2.1.13", "@tiptap/extension-list-item@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.3.1.tgz#241970a6fe50aa3d5c0a28efa9ba05f31e2f0f12"
|
||||
integrity sha512-GyHLNoXVo9u29NVqijwZPBcv9MzXMGyIiQiO5FxRpuT4Ei4ZmsaJrJ2dmhO3KZhX0HdTSc65/omM2XBr6PDoLA==
|
||||
"@tiptap/extension-list-item@^2.1.13", "@tiptap/extension-list-item@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.4.0.tgz#a97a48850b81e94b9a60cc2aa16e515aa5311456"
|
||||
integrity sha512-reUVUx+2cI2NIAqMZhlJ9uK/+zvRzm1GTmlU2Wvzwc7AwLN4yemj6mBDsmBLEXAKPvitfLh6EkeHaruOGymQtg==
|
||||
|
||||
"@tiptap/extension-mention@^2.1.13":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-2.3.1.tgz#bdc8bbc2f7b1e376d88f074cdc1b04af856985de"
|
||||
integrity sha512-60N1L9bTPVsE6zPDtYQqpZGZNuFpFfw4Opd26Xnfuwx14xvFLC34gDN7hpwVgqncVg9CefFigi1o9L5C+mXDBg==
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-2.4.0.tgz#35f13d71e207280cafe5b00e76f17b4c372fbe8b"
|
||||
integrity sha512-7BqCNfqF1Mv9IrtdlHADwXMFo968UNmthf/TepVXC7EX2Ke6/Y4vvxmpYVNZc55FdswFwpVyZ2VeXBj3AC2JcA==
|
||||
|
||||
"@tiptap/extension-ordered-list@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.3.1.tgz#964bcc082e08a9019359ecd097d0aab608bcc166"
|
||||
integrity sha512-+6I76b7fu0FghUtzB0LyIC5GB0xfrpAKtXjbrmeUGsOEL7jxKsE6+A5RoTrgQTfuP7oItdCZGTSC/8WtGbtEMg==
|
||||
"@tiptap/extension-ordered-list@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.4.0.tgz#6cf82e10d7e7f7cc44156d29b0b71a22dec31612"
|
||||
integrity sha512-Zo0c9M0aowv+2+jExZiAvhCB83GZMjZsxywmuOrdUbq5EGYKb7q8hDyN3hkrktVHr9UPXdPAYTmLAHztTOHYRA==
|
||||
|
||||
"@tiptap/extension-paragraph@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.3.1.tgz#2aa53a06cfad637640bf65a7cd0ab2ef5f5a5c10"
|
||||
integrity sha512-bHkkHU012clwCrpzmEHGuF8fwLuFL3x9MJ17wnhwanoIM3MG6ZCdeb9copjDvUpZXLKTUYKotoPGNhxmOrP2bQ==
|
||||
"@tiptap/extension-paragraph@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.4.0.tgz#5b9aea8775937b327bbe6754be12ae3144fb09ff"
|
||||
integrity sha512-+yse0Ow67IRwcACd9K/CzBcxlpr9OFnmf0x9uqpaWt1eHck1sJnti6jrw5DVVkyEBHDh/cnkkV49gvctT/NyCw==
|
||||
|
||||
"@tiptap/extension-placeholder@^2.3.0":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.3.1.tgz#08fe48ff5bb75b1be64c50463d5022894293fd63"
|
||||
integrity sha512-iqmwqT+pBaWcL6Bj8ht+SKzFGxEMfAPEKOlxIrfaY/um80q5kmyrmes6LOSAHTylsm3kmna6s0p2TD2zcnBQqw==
|
||||
|
||||
"@tiptap/extension-strike@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.3.1.tgz#2e47c711b85f46c7e575b0b154cedc93ab9bc89b"
|
||||
integrity sha512-fpsVewcnaYk37TAF4JHkwH9O6Ml7JooF1v/Eh9p7PSItNcEfg/3RLlJL3c53RzLWdlunjgptM/M0alPV0Zyq4A==
|
||||
"@tiptap/extension-strike@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.4.0.tgz#f09c4f51f7fed01c356026d7e8d8a1d1f2ac8f18"
|
||||
integrity sha512-pE1uN/fQPOMS3i+zxPYMmPmI3keubnR6ivwM+KdXWOMnBiHl9N4cNpJgq1n2eUUGKLurC2qrQHpnVyGAwBS6Vg==
|
||||
|
||||
"@tiptap/extension-task-item@^2.1.13":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.3.1.tgz#6ff237bad42e5184d01bb327a677471073aa7a06"
|
||||
integrity sha512-iNVLiwJOTp9UulUS6tLk5NR85nNxtxqvaboOwPxoqcFaM/IkybTwZ/hMr9EqbAucigx85OowHKsdgPHIAr3xdw==
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.4.0.tgz#33227e72fcffdf087446f88cdb7a10feab4c2087"
|
||||
integrity sha512-x40vdHnmDiBbA2pjWR/92wVGb6jT13Nk2AhRUI/oP/r4ZGKpTypoB7heDnvLBgH0Y5a51dFqU+G1SFFL30u5uA==
|
||||
|
||||
"@tiptap/extension-task-list@^2.1.13":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.3.1.tgz#dc92096dbe91c6a4f744f9d8e19c9ebde0e30132"
|
||||
integrity sha512-lu/27tetu2KYEjsaD8wyQ4rBthxrW8aRNeSv74jXJLPYN4aCtAl9C2bM7os+A2OYpidPBMbRjp8ZQoUnJ9auNA==
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.4.0.tgz#61a500fe4a89d5c789ad4fb64c8d7eeedfe26b63"
|
||||
integrity sha512-vmUB3wEJU81QbiHUygBlselQW8YIW8/85UTwANvWx8+KEWyM7EUF4utcm5R2UobIprIcWb4hyVkvW/5iou25gg==
|
||||
|
||||
"@tiptap/extension-text-style@^2.1.13":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.3.1.tgz#e9f2b7f1640d32b17c089fa089f595aef1334c22"
|
||||
integrity sha512-eXtuf3AqcOv28BM0dO4lbBNnvM1fo4WWuT+/s1YV5Ovex3T5OS7PsPuR/9p5AD4NuX9QvNrV+eM02mcNzaTBWw==
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.4.0.tgz#9f86d8de4606bc37090b7b02c2aaf40bb37a860f"
|
||||
integrity sha512-H0uPWeZ4sXz3o836TDWnpd38qClqzEM2d6QJ9TK+cQ1vE5Gp8wQ5W4fwUV1KAHzpJKE/15+BXBjLyVYQdmXDaQ==
|
||||
|
||||
"@tiptap/extension-text@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.3.1.tgz#c5ded941eab937ea4743b88ff27c5eac971fe3db"
|
||||
integrity sha512-ZM+Bpty9jChEN/VjUP/fX1Fvoz0Z3YLdjj9+pFA0H7woli+TmxWY6yUUTA2SBDb2mJ52yNOUfRE/sYx6gkDuBQ==
|
||||
"@tiptap/extension-text@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.4.0.tgz#a3a5f45a9856d513e574f24e2c9b6028273f8eb3"
|
||||
integrity sha512-LV0bvE+VowE8IgLca7pM8ll7quNH+AgEHRbSrsI3SHKDCYB9gTHMjWaAkgkUVaO1u0IfCrjnCLym/PqFKa+vvg==
|
||||
|
||||
"@tiptap/extension-underline@^2.1.13":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.3.1.tgz#90a594cc69644464f1070b4bd36ed4bed4ce3c38"
|
||||
integrity sha512-xgLGr7bM5OAKagUKdL5dWxJHgwEp2fk3D5XCVUBwqgeOZtOFteoqPzb/2617w7qrP+9oM9zRjw6z27hM8YxyvQ==
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.4.0.tgz#fb554333aed8a9ac1400b94f362a774c650f5a90"
|
||||
integrity sha512-guWojb7JxUwLz4OKzwNExJwOkhZjgw/ttkXCMBT0PVe55k998MMYe1nvN0m2SeTW9IxurEPtScH4kYJ0XuSm8Q==
|
||||
|
||||
"@tiptap/pm@^2.1.13":
|
||||
version "2.3.1"
|
||||
@ -2555,31 +2560,36 @@
|
||||
"@tiptap/extension-floating-menu" "^2.3.1"
|
||||
|
||||
"@tiptap/starter-kit@^2.1.13":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.3.1.tgz#b7356eb667ae85552a6f666b73daabb3185e1271"
|
||||
integrity sha512-VGk1o5y5f2ZHKkvP2WNj8BH7FGak0d0cjxQiXP1n5w8eS0vFnTkCz3JbCPM+KTKobsBmxd2vSC3ElgP9E9d2xw==
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.4.0.tgz#ad2c2d900af41e55eaaccafa92fd6b2acaebd97e"
|
||||
integrity sha512-DYYzMZdTEnRn9oZhKOeRCcB+TjhNz5icLlvJKoHoOGL9kCbuUyEf8WRR2OSPckI0+KUIPJL3oHRqO4SqSdTjfg==
|
||||
dependencies:
|
||||
"@tiptap/core" "^2.3.1"
|
||||
"@tiptap/extension-blockquote" "^2.3.1"
|
||||
"@tiptap/extension-bold" "^2.3.1"
|
||||
"@tiptap/extension-bullet-list" "^2.3.1"
|
||||
"@tiptap/extension-code" "^2.3.1"
|
||||
"@tiptap/extension-code-block" "^2.3.1"
|
||||
"@tiptap/extension-document" "^2.3.1"
|
||||
"@tiptap/extension-dropcursor" "^2.3.1"
|
||||
"@tiptap/extension-gapcursor" "^2.3.1"
|
||||
"@tiptap/extension-hard-break" "^2.3.1"
|
||||
"@tiptap/extension-heading" "^2.3.1"
|
||||
"@tiptap/extension-history" "^2.3.1"
|
||||
"@tiptap/extension-horizontal-rule" "^2.3.1"
|
||||
"@tiptap/extension-italic" "^2.3.1"
|
||||
"@tiptap/extension-list-item" "^2.3.1"
|
||||
"@tiptap/extension-ordered-list" "^2.3.1"
|
||||
"@tiptap/extension-paragraph" "^2.3.1"
|
||||
"@tiptap/extension-strike" "^2.3.1"
|
||||
"@tiptap/extension-text" "^2.3.1"
|
||||
"@tiptap/core" "^2.4.0"
|
||||
"@tiptap/extension-blockquote" "^2.4.0"
|
||||
"@tiptap/extension-bold" "^2.4.0"
|
||||
"@tiptap/extension-bullet-list" "^2.4.0"
|
||||
"@tiptap/extension-code" "^2.4.0"
|
||||
"@tiptap/extension-code-block" "^2.4.0"
|
||||
"@tiptap/extension-document" "^2.4.0"
|
||||
"@tiptap/extension-dropcursor" "^2.4.0"
|
||||
"@tiptap/extension-gapcursor" "^2.4.0"
|
||||
"@tiptap/extension-hard-break" "^2.4.0"
|
||||
"@tiptap/extension-heading" "^2.4.0"
|
||||
"@tiptap/extension-history" "^2.4.0"
|
||||
"@tiptap/extension-horizontal-rule" "^2.4.0"
|
||||
"@tiptap/extension-italic" "^2.4.0"
|
||||
"@tiptap/extension-list-item" "^2.4.0"
|
||||
"@tiptap/extension-ordered-list" "^2.4.0"
|
||||
"@tiptap/extension-paragraph" "^2.4.0"
|
||||
"@tiptap/extension-strike" "^2.4.0"
|
||||
"@tiptap/extension-text" "^2.4.0"
|
||||
|
||||
"@tiptap/suggestion@^2.0.13", "@tiptap/suggestion@^2.1.13":
|
||||
"@tiptap/suggestion@^2.0.13":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.4.0.tgz#1926cde5f197d116baf7794f55bd971245540e5c"
|
||||
integrity sha512-6dCkjbL8vIzcLWtS6RCBx0jlYPKf2Beuyq5nNLrDDZZuyJow5qJAY0eGu6Xomp9z0WDK/BYOxT4hHNoGMDkoAg==
|
||||
|
||||
"@tiptap/suggestion@^2.1.13":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.3.1.tgz#b0ae3678214240a066b7c0c415a5ca9981819855"
|
||||
integrity sha512-hfUIsC80QivPH833rlqh3x1RCOat2mE0SzR6m2Z1ZNZ86N5BrYDU8e8p81gR//4SlNBJ7BZGVWN3DXj+aAKs2A==
|
||||
|
Loading…
Reference in New Issue
Block a user