mirror of
https://github.com/docmost/docmost.git
synced 2025-11-13 16:32:36 +10:00
lazy load (#237)
This commit is contained in:
@ -1,13 +1,14 @@
|
|||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from 'react';
|
||||||
import data from "@emoji-mart/data";
|
|
||||||
import Picker from "@emoji-mart/react";
|
|
||||||
import {
|
import {
|
||||||
ActionIcon,
|
ActionIcon,
|
||||||
Popover,
|
Popover,
|
||||||
Button,
|
Button,
|
||||||
useMantineColorScheme,
|
useMantineColorScheme,
|
||||||
} from "@mantine/core";
|
} from '@mantine/core';
|
||||||
import { useDisclosure } from "@mantine/hooks";
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
|
const Picker = React.lazy(() => import('@emoji-mart/react'));
|
||||||
|
|
||||||
export interface EmojiPickerInterface {
|
export interface EmojiPickerInterface {
|
||||||
onEmojiSelect: (emoji: any) => void;
|
onEmojiSelect: (emoji: any) => void;
|
||||||
@ -48,23 +49,25 @@ function EmojiPicker({
|
|||||||
{icon}
|
{icon}
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown bg="000" style={{ border: "none" }}>
|
<Popover.Dropdown bg="000" style={{ border: 'none' }}>
|
||||||
|
<Suspense fallback={null}>
|
||||||
<Picker
|
<Picker
|
||||||
data={data}
|
data={async () => (await import('@emoji-mart/data')).default}
|
||||||
onEmojiSelect={handleEmojiSelect}
|
onEmojiSelect={handleEmojiSelect}
|
||||||
perLine={8}
|
perLine={8}
|
||||||
skinTonePosition="search"
|
skinTonePosition="search"
|
||||||
theme={colorScheme}
|
theme={colorScheme}
|
||||||
/>
|
/>
|
||||||
|
</Suspense>
|
||||||
<Button
|
<Button
|
||||||
variant="default"
|
variant="default"
|
||||||
c="gray"
|
c="gray"
|
||||||
size="xs"
|
size="xs"
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
bottom: "1rem",
|
bottom: '1rem',
|
||||||
right: "1rem",
|
right: '1rem',
|
||||||
}}
|
}}
|
||||||
onClick={handleRemoveEmoji}
|
onClick={handleRemoveEmoji}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,15 +1,21 @@
|
|||||||
import { NodeViewContent, NodeViewProps, NodeViewWrapper } from "@tiptap/react";
|
import { NodeViewContent, NodeViewProps, NodeViewWrapper } from '@tiptap/react';
|
||||||
import { ActionIcon, CopyButton, Group, Select, Tooltip } from "@mantine/core";
|
import { ActionIcon, CopyButton, Group, Select, Tooltip } from '@mantine/core';
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from 'react';
|
||||||
import { IconCheck, IconCopy } from "@tabler/icons-react";
|
import { IconCheck, IconCopy } from '@tabler/icons-react';
|
||||||
import MermaidView from "@/features/editor/components/code-block/mermaid-view.tsx";
|
//import MermaidView from "@/features/editor/components/code-block/mermaid-view.tsx";
|
||||||
import classes from "./code-block.module.css";
|
import classes from './code-block.module.css';
|
||||||
|
import React from 'react';
|
||||||
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
|
const MermaidView = React.lazy(
|
||||||
|
() => import('@/features/editor/components/code-block/mermaid-view.tsx')
|
||||||
|
);
|
||||||
|
|
||||||
export default function CodeBlockView(props: NodeViewProps) {
|
export default function CodeBlockView(props: NodeViewProps) {
|
||||||
const { node, updateAttributes, extension, editor, getPos } = props;
|
const { node, updateAttributes, extension, editor, getPos } = props;
|
||||||
const { language } = node.attrs;
|
const { language } = node.attrs;
|
||||||
const [languageValue, setLanguageValue] = useState<string | null>(
|
const [languageValue, setLanguageValue] = useState<string | null>(
|
||||||
language || null,
|
language || null
|
||||||
);
|
);
|
||||||
const [isSelected, setIsSelected] = useState(false);
|
const [isSelected, setIsSelected] = useState(false);
|
||||||
|
|
||||||
@ -24,9 +30,9 @@ export default function CodeBlockView(props: NodeViewProps) {
|
|||||||
setIsSelected(isNodeSelected);
|
setIsSelected(isNodeSelected);
|
||||||
};
|
};
|
||||||
|
|
||||||
editor.on("selectionUpdate", updateSelection);
|
editor.on('selectionUpdate', updateSelection);
|
||||||
return () => {
|
return () => {
|
||||||
editor.off("selectionUpdate", updateSelection);
|
editor.off('selectionUpdate', updateSelection);
|
||||||
};
|
};
|
||||||
}, [editor, getPos(), node.nodeSize]);
|
}, [editor, getPos(), node.nodeSize]);
|
||||||
|
|
||||||
@ -47,7 +53,7 @@ export default function CodeBlockView(props: NodeViewProps) {
|
|||||||
value={languageValue}
|
value={languageValue}
|
||||||
onChange={changeLanguage}
|
onChange={changeLanguage}
|
||||||
searchable
|
searchable
|
||||||
style={{ maxWidth: "130px" }}
|
style={{ maxWidth: '130px' }}
|
||||||
classNames={{ input: classes.selectInput }}
|
classNames={{ input: classes.selectInput }}
|
||||||
disabled={!editor.isEditable}
|
disabled={!editor.isEditable}
|
||||||
/>
|
/>
|
||||||
@ -55,12 +61,12 @@ export default function CodeBlockView(props: NodeViewProps) {
|
|||||||
<CopyButton value={node?.textContent} timeout={2000}>
|
<CopyButton value={node?.textContent} timeout={2000}>
|
||||||
{({ copied, copy }) => (
|
{({ copied, copy }) => (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
label={copied ? "Copied" : "Copy"}
|
label={copied ? 'Copied' : 'Copy'}
|
||||||
withArrow
|
withArrow
|
||||||
position="right"
|
position="right"
|
||||||
>
|
>
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
color={copied ? "teal" : "gray"}
|
color={copied ? 'teal' : 'gray'}
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
onClick={copy}
|
onClick={copy}
|
||||||
>
|
>
|
||||||
@ -74,15 +80,19 @@ export default function CodeBlockView(props: NodeViewProps) {
|
|||||||
<pre
|
<pre
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
hidden={
|
hidden={
|
||||||
((language === "mermaid" && !editor.isEditable) ||
|
((language === 'mermaid' && !editor.isEditable) ||
|
||||||
(language === "mermaid" && !isSelected)) &&
|
(language === 'mermaid' && !isSelected)) &&
|
||||||
node.textContent.length > 0
|
node.textContent.length > 0
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<NodeViewContent as="code" className={`language-${language}`} />
|
<NodeViewContent as="code" className={`language-${language}`} />
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
{language === "mermaid" && <MermaidView props={props} />}
|
{language === 'mermaid' && (
|
||||||
|
<Suspense fallback={null}>
|
||||||
|
<MermaidView props={props} />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
</NodeViewWrapper>
|
</NodeViewWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import {
|
|||||||
useComputedColorScheme,
|
useComputedColorScheme,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Excalidraw, exportToSvg, loadFromBlob } from '@excalidraw/excalidraw';
|
|
||||||
import { uploadFile } from '@/features/page/services/page-service.ts';
|
import { uploadFile } from '@/features/page/services/page-service.ts';
|
||||||
import { svgStringToFile } from '@/lib';
|
import { svgStringToFile } from '@/lib';
|
||||||
import { useDisclosure } from '@mantine/hooks';
|
import { useDisclosure } from '@mantine/hooks';
|
||||||
@ -19,6 +18,14 @@ import { IAttachment } from '@/lib/types';
|
|||||||
import ReactClearModal from 'react-clear-modal';
|
import ReactClearModal from 'react-clear-modal';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { IconEdit } from '@tabler/icons-react';
|
import { IconEdit } from '@tabler/icons-react';
|
||||||
|
import { lazy } from 'react';
|
||||||
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
|
const Excalidraw = lazy(() =>
|
||||||
|
import('@excalidraw/excalidraw').then((module) => ({
|
||||||
|
default: module.Excalidraw,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
export default function ExcalidrawView(props: NodeViewProps) {
|
export default function ExcalidrawView(props: NodeViewProps) {
|
||||||
const { node, updateAttributes, editor, selected } = props;
|
const { node, updateAttributes, editor, selected } = props;
|
||||||
@ -43,6 +50,8 @@ export default function ExcalidrawView(props: NodeViewProps) {
|
|||||||
cache: 'no-store',
|
cache: 'no-store',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { loadFromBlob } = await import('@excalidraw/excalidraw');
|
||||||
|
|
||||||
const data = await loadFromBlob(await request.blob(), null, null);
|
const data = await loadFromBlob(await request.blob(), null, null);
|
||||||
setExcalidrawData(data);
|
setExcalidrawData(data);
|
||||||
}
|
}
|
||||||
@ -58,6 +67,8 @@ export default function ExcalidrawView(props: NodeViewProps) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { exportToSvg } = await import('@excalidraw/excalidraw');
|
||||||
|
|
||||||
const svg = await exportToSvg({
|
const svg = await exportToSvg({
|
||||||
elements: excalidrawAPI?.getSceneElements(),
|
elements: excalidrawAPI?.getSceneElements(),
|
||||||
appState: {
|
appState: {
|
||||||
@ -129,6 +140,7 @@ export default function ExcalidrawView(props: NodeViewProps) {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
<div style={{ height: '90vh' }}>
|
<div style={{ height: '90vh' }}>
|
||||||
|
<Suspense fallback={null}>
|
||||||
<Excalidraw
|
<Excalidraw
|
||||||
excalidrawAPI={(api) => setExcalidrawAPI(api)}
|
excalidrawAPI={(api) => setExcalidrawAPI(api)}
|
||||||
initialData={{
|
initialData={{
|
||||||
@ -136,6 +148,7 @@ export default function ExcalidrawView(props: NodeViewProps) {
|
|||||||
scrollToContent: true,
|
scrollToContent: true,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
</ReactClearModal>
|
</ReactClearModal>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user