lazy load (#237)

This commit is contained in:
Philip Okugbe
2024-09-02 15:51:28 +01:00
committed by GitHub
parent 7fdd355cc3
commit 2b9765fb35
3 changed files with 65 additions and 39 deletions

View File

@ -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}
> >

View File

@ -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>
); );
} }

View File

@ -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>