mirror of https://github.com/buster-so/buster.git
handle after print
This commit is contained in:
parent
5c6bfdf96a
commit
cb02074cba
|
@ -17,6 +17,7 @@ import { MarkdownKit } from './plugins/markdown-kit';
|
||||||
import { BaseMathKit } from './plugins/math-base-kit';
|
import { BaseMathKit } from './plugins/math-base-kit';
|
||||||
import { BaseMediaKit } from './plugins/media-base-kit';
|
import { BaseMediaKit } from './plugins/media-base-kit';
|
||||||
import { BaseMentionKit } from './plugins/mention-base-kit';
|
import { BaseMentionKit } from './plugins/mention-base-kit';
|
||||||
|
import { MetricBaseKit } from './plugins/metric-kit/metric-base-kit';
|
||||||
import { BaseSuggestionKit } from './plugins/suggestion-base-kit';
|
import { BaseSuggestionKit } from './plugins/suggestion-base-kit';
|
||||||
import { BaseTableKit } from './plugins/table-base-kit';
|
import { BaseTableKit } from './plugins/table-base-kit';
|
||||||
import { BaseTocKit } from './plugins/toc-base-kit';
|
import { BaseTocKit } from './plugins/toc-base-kit';
|
||||||
|
@ -44,5 +45,6 @@ export const BaseEditorKit = [
|
||||||
...BaseCommentKit,
|
...BaseCommentKit,
|
||||||
...BaseSuggestionKit,
|
...BaseSuggestionKit,
|
||||||
...MarkdownKit,
|
...MarkdownKit,
|
||||||
...BusterStreamKit
|
...BusterStreamKit,
|
||||||
|
...MetricBaseKit
|
||||||
];
|
];
|
||||||
|
|
|
@ -34,16 +34,16 @@ export function ExportToolbarButton({ children, ...props }: DropdownMenuProps) {
|
||||||
|
|
||||||
<DropdownMenuContent align="start">
|
<DropdownMenuContent align="start">
|
||||||
<DropdownMenuGroup>
|
<DropdownMenuGroup>
|
||||||
<DropdownMenuItem onSelect={() => exportToHtml(editor)}>
|
<DropdownMenuItem onSelect={() => exportToHtml({ editor })}>
|
||||||
{NodeTypeLabels.exportAsHtml.label}
|
{NodeTypeLabels.exportAsHtml.label}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onSelect={() => exportToPdf(editor)}>
|
<DropdownMenuItem onSelect={() => exportToPdf({ editor })}>
|
||||||
{NodeTypeLabels.exportAsPdf.label}
|
{NodeTypeLabels.exportAsPdf.label}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onSelect={() => exportToImage(editor)}>
|
<DropdownMenuItem onSelect={() => exportToImage({ editor })}>
|
||||||
{NodeTypeLabels.exportAsImage.label}
|
{NodeTypeLabels.exportAsImage.label}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onSelect={() => exportToMarkdown(editor)}>
|
<DropdownMenuItem onSelect={() => exportToMarkdown({ editor })}>
|
||||||
{NodeTypeLabels.exportAsMarkdown.label}
|
{NodeTypeLabels.exportAsMarkdown.label}
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuGroup>
|
</DropdownMenuGroup>
|
||||||
|
|
|
@ -5,17 +5,18 @@ import { useChatLayoutContextSelector } from '@/layouts/ChatLayout';
|
||||||
import { assetParamsToRoute } from '@/lib/assets/assetParamsToRoute';
|
import { assetParamsToRoute } from '@/lib/assets/assetParamsToRoute';
|
||||||
import React, { useMemo, useRef } from 'react';
|
import React, { useMemo, useRef } from 'react';
|
||||||
import { useMetricContentThreeDotMenuItems } from './useMetricContentThreeDotMenuItems';
|
import { useMetricContentThreeDotMenuItems } from './useMetricContentThreeDotMenuItems';
|
||||||
import { cn } from '@/lib/classMerge';
|
|
||||||
|
|
||||||
export const MetricContent = React.memo(
|
export const MetricContent = React.memo(
|
||||||
({
|
({
|
||||||
metricId,
|
metricId,
|
||||||
metricVersionNumber,
|
metricVersionNumber,
|
||||||
|
isBaseElement = false,
|
||||||
readOnly = false
|
readOnly = false
|
||||||
}: {
|
}: {
|
||||||
metricId: string;
|
metricId: string;
|
||||||
metricVersionNumber: number | undefined;
|
metricVersionNumber: number | undefined;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
|
isBaseElement?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const chatId = useChatLayoutContextSelector((x) => x.chatId);
|
const chatId = useChatLayoutContextSelector((x) => x.chatId);
|
||||||
const reportId = useChatLayoutContextSelector((x) => x.reportId) || '';
|
const reportId = useChatLayoutContextSelector((x) => x.reportId) || '';
|
||||||
|
@ -23,7 +24,7 @@ export const MetricContent = React.memo(
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [inViewport] = useInViewport(ref, {
|
const [inViewport] = useInViewport(ref, {
|
||||||
threshold: 0.33
|
threshold: isBaseElement ? 0 : 0.33
|
||||||
});
|
});
|
||||||
const renderChart = inViewport;
|
const renderChart = inViewport;
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ export const MetricContent = React.memo(
|
||||||
return (
|
return (
|
||||||
<MetricCard
|
<MetricCard
|
||||||
metricLink={link}
|
metricLink={link}
|
||||||
animate
|
animate={!isBaseElement}
|
||||||
metricId={metricId}
|
metricId={metricId}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
isDragOverlay={false}
|
isDragOverlay={false}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { ResizableProvider, useResizableValue } from '@platejs/resizable';
|
||||||
import { MetricEmbedPlaceholder } from './MetricPlaceholder';
|
import { MetricEmbedPlaceholder } from './MetricPlaceholder';
|
||||||
import { Caption, CaptionTextarea } from '../CaptionNode';
|
import { Caption, CaptionTextarea } from '../CaptionNode';
|
||||||
import { mediaResizeHandleVariants, Resizable, ResizeHandle } from '../ResizeHandle';
|
import { mediaResizeHandleVariants, Resizable, ResizeHandle } from '../ResizeHandle';
|
||||||
import { type TMetricElement } from '../../plugins/metric-plugin';
|
import { type TMetricElement } from '../../plugins/metric-kit';
|
||||||
import React, { useMemo, useRef, type PropsWithChildren } from 'react';
|
import React, { useMemo, useRef, type PropsWithChildren } from 'react';
|
||||||
import { useSize } from '@/hooks/useSize';
|
import { useSize } from '@/hooks/useSize';
|
||||||
import { MetricContent } from './MetricContent';
|
import { MetricContent } from './MetricContent';
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { MetricContent } from './MetricContent';
|
||||||
|
import type { TMetricElement } from '../../plugins/metric-kit';
|
||||||
|
import {
|
||||||
|
SlateElement,
|
||||||
|
type TCaptionProps,
|
||||||
|
type TResizableProps,
|
||||||
|
type SlateElementProps
|
||||||
|
} from 'platejs';
|
||||||
|
import { MetricEmbedPlaceholder } from './MetricPlaceholder';
|
||||||
|
|
||||||
|
export const MetricElementStatic = (
|
||||||
|
props: SlateElementProps<TMetricElement & TCaptionProps & TResizableProps>
|
||||||
|
) => {
|
||||||
|
const metricId = props.element.metricId;
|
||||||
|
const metricVersionNumber = props.element.metricVersionNumber;
|
||||||
|
const readOnly = true;
|
||||||
|
const { align = 'center', caption, url, width } = props.element;
|
||||||
|
|
||||||
|
const content = metricId ? (
|
||||||
|
<MetricContent
|
||||||
|
metricId={metricId}
|
||||||
|
metricVersionNumber={metricVersionNumber}
|
||||||
|
readOnly={readOnly}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<MetricEmbedPlaceholder />
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SlateElement {...props}>
|
||||||
|
<figure className="group relative m-0 inline-block" style={{ width }}>
|
||||||
|
<div className="relative max-w-full min-w-[92px]" style={{ textAlign: align }}>
|
||||||
|
{content}
|
||||||
|
</div>
|
||||||
|
<div className="h-0">{props.children}</div>
|
||||||
|
</figure>
|
||||||
|
</SlateElement>
|
||||||
|
);
|
||||||
|
};
|
|
@ -13,7 +13,7 @@ import {
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
import { useMemoizedFn } from '@/hooks/useMemoizedFn';
|
||||||
import { AddMetricModal } from '@/components/features/modal/AddMetricModal';
|
import { AddMetricModal } from '@/components/features/modal/AddMetricModal';
|
||||||
import { MetricPlugin, type TMetricElement } from '../../plugins/metric-plugin';
|
import { MetricPlugin, type TMetricElement } from '../../plugins/metric-kit';
|
||||||
|
|
||||||
export const MetricEmbedPlaceholder: React.FC = () => {
|
export const MetricEmbedPlaceholder: React.FC = () => {
|
||||||
const [openModal, setOpenModal] = React.useState(false);
|
const [openModal, setOpenModal] = React.useState(false);
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { TablePlugin } from '@platejs/table/react';
|
||||||
import { insertToc } from '@platejs/toc';
|
import { insertToc } from '@platejs/toc';
|
||||||
import { type NodeEntry, type Path, type TElement, KEYS, PathApi } from 'platejs';
|
import { type NodeEntry, type Path, type TElement, KEYS, PathApi } from 'platejs';
|
||||||
import { CUSTOM_KEYS } from '../config/keys';
|
import { CUSTOM_KEYS } from '../config/keys';
|
||||||
import { insertMetric } from '../plugins/metric-plugin';
|
import { insertMetric } from '../plugins/metric-kit';
|
||||||
|
|
||||||
const ACTION_THREE_COLUMNS = 'action_three_columns';
|
const ACTION_THREE_COLUMNS = 'action_three_columns';
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,18 @@ import { createSlateEditor, serializeHtml } from 'platejs';
|
||||||
// computed CSS styles so no external CSS is required. Additionally,
|
// computed CSS styles so no external CSS is required. Additionally,
|
||||||
// snapshot <canvas> elements inside metrics to <img> tags to avoid
|
// snapshot <canvas> elements inside metrics to <img> tags to avoid
|
||||||
// blank canvases in the exported HTML.
|
// blank canvases in the exported HTML.
|
||||||
export const buildExportHtml = async (editor: PlateEditor): Promise<string> => {
|
// Options for building the export HTML document
|
||||||
|
type BuildExportHtmlOptions = {
|
||||||
|
// Optional document title to embed in the HTML head
|
||||||
|
title?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buildExportHtml = async (
|
||||||
|
editor: PlateEditor,
|
||||||
|
options?: BuildExportHtmlOptions
|
||||||
|
): Promise<string> => {
|
||||||
|
// Resolve the document title with a sensible default
|
||||||
|
const documentTitle = options?.title || 'Buster Report';
|
||||||
// Prefer using the live editor DOM to inline computed styles
|
// Prefer using the live editor DOM to inline computed styles
|
||||||
const liveRoot = document.querySelector('[contenteditable="true"]') as HTMLElement | null;
|
const liveRoot = document.querySelector('[contenteditable="true"]') as HTMLElement | null;
|
||||||
|
|
||||||
|
@ -89,35 +100,7 @@ export const buildExportHtml = async (editor: PlateEditor): Promise<string> => {
|
||||||
wrapper.appendChild(clonedRoot);
|
wrapper.appendChild(clonedRoot);
|
||||||
contentHtml = wrapper.outerHTML;
|
contentHtml = wrapper.outerHTML;
|
||||||
} else {
|
} else {
|
||||||
// Fallback: serialize using static editor and include minimal inline styles
|
throw new Error('No live root found');
|
||||||
const BaseEditorKit = await import('../editor-base-kit').then((module) => module.BaseEditorKit);
|
|
||||||
|
|
||||||
const editorStatic = createSlateEditor({
|
|
||||||
plugins: BaseEditorKit,
|
|
||||||
value: editor.children
|
|
||||||
});
|
|
||||||
|
|
||||||
const serializedHtml = await serializeHtml(editorStatic, {
|
|
||||||
editorComponent: EditorStatic,
|
|
||||||
props: { style: { padding: '0 calc(50% - 350px)', paddingBottom: '' } }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Wrap the serialized HTML to match the centered, fixed-width layout
|
|
||||||
const wrapper = document.createElement('div');
|
|
||||||
wrapper.setAttribute(
|
|
||||||
'style',
|
|
||||||
[
|
|
||||||
'width: 816px',
|
|
||||||
'max-width: 816px',
|
|
||||||
'min-width: 816px',
|
|
||||||
'margin: 24px auto',
|
|
||||||
'background: #ffffff',
|
|
||||||
'padding: 40px',
|
|
||||||
'box-sizing: border-box'
|
|
||||||
].join('; ')
|
|
||||||
);
|
|
||||||
wrapper.innerHTML = serializedHtml;
|
|
||||||
contentHtml = wrapper.outerHTML;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a minimal HTML document without external CSS
|
// Build a minimal HTML document without external CSS
|
||||||
|
@ -127,6 +110,7 @@ export const buildExportHtml = async (editor: PlateEditor): Promise<string> => {
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="color-scheme" content="light dark" />
|
<meta name="color-scheme" content="light dark" />
|
||||||
|
<title>${documentTitle}</title>
|
||||||
<style>
|
<style>
|
||||||
body { margin: 0; background: #f5f5f5; }
|
body { margin: 0; background: #f5f5f5; }
|
||||||
@media print {
|
@media print {
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import type { PlateEditor } from 'platejs/react';
|
||||||
|
|
||||||
|
export const buildExportHtml = async (editor: PlateEditor, options?: {}): Promise<string> => {
|
||||||
|
return '';
|
||||||
|
};
|
|
@ -5,23 +5,29 @@ import { downloadFile } from './downloadFile';
|
||||||
|
|
||||||
type Notifier = (message: string) => void;
|
type Notifier = (message: string) => void;
|
||||||
|
|
||||||
export const exportToHtml = async (
|
type ExportToHtmlOptions = {
|
||||||
editor: PlateEditor,
|
editor: PlateEditor;
|
||||||
openInfoMessage: Notifier,
|
filename?: string;
|
||||||
openErrorMessage: Notifier
|
openInfoMessage?: Notifier;
|
||||||
) => {
|
openErrorMessage?: Notifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const exportToHtml = async ({
|
||||||
|
editor,
|
||||||
|
filename = 'buster-report.html',
|
||||||
|
openInfoMessage,
|
||||||
|
openErrorMessage
|
||||||
|
}: ExportToHtmlOptions) => {
|
||||||
try {
|
try {
|
||||||
const html = await buildExportHtml(editor);
|
const html = await buildExportHtml(editor, { title: filename.replace(/\.html$/i, '') });
|
||||||
const url = `data:text/html;charset=utf-8,${encodeURIComponent(html)}`;
|
const url = `data:text/html;charset=utf-8,${encodeURIComponent(html)}`;
|
||||||
|
|
||||||
await downloadFile(url, 'plate.html');
|
await downloadFile(url, filename);
|
||||||
openInfoMessage(NodeTypeLabels.htmlExportedSuccessfully.label);
|
openInfoMessage?.(NodeTypeLabels.htmlExportedSuccessfully.label);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
openErrorMessage(NodeTypeLabels.failedToExportHtml.label);
|
openErrorMessage?.(NodeTypeLabels.failedToExportHtml.label);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default exportToHtml;
|
export default exportToHtml;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,18 +5,26 @@ import { downloadFile } from './downloadFile';
|
||||||
|
|
||||||
type Notifier = (message: string) => void;
|
type Notifier = (message: string) => void;
|
||||||
|
|
||||||
export const exportToImage = async (
|
type ExportToImageOptions = {
|
||||||
editor: PlateEditor,
|
editor: PlateEditor;
|
||||||
openInfoMessage: Notifier,
|
filename?: string;
|
||||||
openErrorMessage: Notifier
|
openInfoMessage?: Notifier;
|
||||||
) => {
|
openErrorMessage?: Notifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const exportToImage = async ({
|
||||||
|
editor,
|
||||||
|
filename = 'plate.png',
|
||||||
|
openInfoMessage,
|
||||||
|
openErrorMessage
|
||||||
|
}: ExportToImageOptions) => {
|
||||||
try {
|
try {
|
||||||
const canvas = await getCanvas(editor);
|
const canvas = await getCanvas(editor);
|
||||||
await downloadFile(canvas.toDataURL('image/png'), 'plate.png');
|
await downloadFile(canvas.toDataURL('image/png'), filename);
|
||||||
openInfoMessage(NodeTypeLabels.imageExportedSuccessfully.label);
|
openInfoMessage?.(NodeTypeLabels.imageExportedSuccessfully.label);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
openErrorMessage(NodeTypeLabels.failedToExportImage.label);
|
openErrorMessage?.(NodeTypeLabels.failedToExportImage.label);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,22 +5,26 @@ import { downloadFile } from './downloadFile';
|
||||||
|
|
||||||
type Notifier = (message: string) => void;
|
type Notifier = (message: string) => void;
|
||||||
|
|
||||||
export const exportToMarkdown = async (
|
type ExportToMarkdownOptions = {
|
||||||
editor: PlateEditor,
|
editor: PlateEditor;
|
||||||
openInfoMessage: Notifier,
|
openInfoMessage?: Notifier;
|
||||||
openErrorMessage: Notifier
|
openErrorMessage?: Notifier;
|
||||||
) => {
|
};
|
||||||
|
|
||||||
|
export const exportToMarkdown = async ({
|
||||||
|
editor,
|
||||||
|
openInfoMessage,
|
||||||
|
openErrorMessage
|
||||||
|
}: ExportToMarkdownOptions) => {
|
||||||
try {
|
try {
|
||||||
const md = editor.getApi(MarkdownPlugin).markdown.serialize();
|
const md = editor.getApi(MarkdownPlugin).markdown.serialize();
|
||||||
const url = `data:text/markdown;charset=utf-8,${encodeURIComponent(md)}`;
|
const url = `data:text/markdown;charset=utf-8,${encodeURIComponent(md)}`;
|
||||||
await downloadFile(url, 'plate.md');
|
await downloadFile(url, 'plate.md');
|
||||||
openInfoMessage(NodeTypeLabels.markdownExportedSuccessfully.label);
|
openInfoMessage?.(NodeTypeLabels.markdownExportedSuccessfully.label);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
openErrorMessage(NodeTypeLabels.failedToExportMarkdown.label);
|
openErrorMessage?.(NodeTypeLabels.failedToExportMarkdown.label);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default exportToMarkdown;
|
export default exportToMarkdown;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,21 @@ import { buildExportHtml } from './buildExportHtml';
|
||||||
|
|
||||||
type Notifier = (message: string) => void;
|
type Notifier = (message: string) => void;
|
||||||
|
|
||||||
export const exportToPdf = async (
|
type ExportToPdfOptions = {
|
||||||
editor: PlateEditor,
|
filename?: string;
|
||||||
openInfoMessage: Notifier,
|
openInfoMessage?: Notifier;
|
||||||
openErrorMessage: Notifier
|
openErrorMessage?: Notifier;
|
||||||
) => {
|
editor: PlateEditor;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const exportToPdf = async ({
|
||||||
|
editor,
|
||||||
|
filename = 'Buster Report',
|
||||||
|
openInfoMessage,
|
||||||
|
openErrorMessage
|
||||||
|
}: ExportToPdfOptions) => {
|
||||||
try {
|
try {
|
||||||
const html = await buildExportHtml(editor);
|
const html = await buildExportHtml(editor, { title: filename });
|
||||||
|
|
||||||
// Open a print window with the rendered HTML so the user can save as PDF
|
// Open a print window with the rendered HTML so the user can save as PDF
|
||||||
const printWindow = window.open('', '_blank');
|
const printWindow = window.open('', '_blank');
|
||||||
|
@ -20,10 +28,22 @@ export const exportToPdf = async (
|
||||||
printWindow.document.write(html);
|
printWindow.document.write(html);
|
||||||
printWindow.document.close();
|
printWindow.document.close();
|
||||||
|
|
||||||
|
// Close the print window after the user prints or cancels
|
||||||
|
const handleAfterPrint = () => {
|
||||||
|
try {
|
||||||
|
// printWindow.close();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to close print window', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
printWindow.addEventListener('afterprint', handleAfterPrint);
|
||||||
|
|
||||||
// Trigger print when resources are loaded
|
// Trigger print when resources are loaded
|
||||||
const triggerPrint = () => {
|
const triggerPrint = () => {
|
||||||
try {
|
try {
|
||||||
printWindow.focus();
|
printWindow.focus();
|
||||||
|
// Set the title for the print window so the OS save dialog suggests it
|
||||||
|
printWindow.document.title = filename;
|
||||||
printWindow.print();
|
printWindow.print();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to trigger print dialog', e);
|
console.error('Failed to trigger print dialog', e);
|
||||||
|
@ -37,13 +57,11 @@ export const exportToPdf = async (
|
||||||
printWindow.addEventListener('load', () => setTimeout(triggerPrint, 100));
|
printWindow.addEventListener('load', () => setTimeout(triggerPrint, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
openInfoMessage(NodeTypeLabels.pdfExportedSuccessfully.label);
|
openInfoMessage?.(NodeTypeLabels.pdfExportedSuccessfully.label);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
openErrorMessage(NodeTypeLabels.failedToExportPdf.label);
|
openErrorMessage?.(NodeTypeLabels.failedToExportPdf.label);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default exportToPdf;
|
export default exportToPdf;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||||
import type { PlateEditor } from 'platejs/react';
|
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { exportToPdf } from './exportToPdf';
|
import { exportToPdf } from './exportToPdf';
|
||||||
import { exportToImage } from './exportToImage';
|
import { exportToImage } from './exportToImage';
|
||||||
|
@ -9,17 +8,17 @@ import { exportToMarkdown } from './exportToMarkdown';
|
||||||
export const useExportReport = () => {
|
export const useExportReport = () => {
|
||||||
const { openErrorMessage, openInfoMessage } = useBusterNotifications();
|
const { openErrorMessage, openInfoMessage } = useBusterNotifications();
|
||||||
|
|
||||||
const exportToPdfLocal = async (editor: PlateEditor) =>
|
const exportToPdfLocal = async (params: Parameters<typeof exportToPdf>[0]) =>
|
||||||
exportToPdf(editor, openInfoMessage, openErrorMessage);
|
exportToPdf({ ...params, openInfoMessage, openErrorMessage });
|
||||||
|
|
||||||
const exportToImageLocal = async (editor: PlateEditor) =>
|
const exportToImageLocal = async (params: Parameters<typeof exportToImage>[0]) =>
|
||||||
exportToImage(editor, openInfoMessage, openErrorMessage);
|
exportToImage({ ...params, openInfoMessage, openErrorMessage });
|
||||||
|
|
||||||
const exportToHtmlLocal = async (editor: PlateEditor) =>
|
const exportToHtmlLocal = async (params: Parameters<typeof exportToHtml>[0]) =>
|
||||||
exportToHtml(editor, openInfoMessage, openErrorMessage);
|
exportToHtml({ ...params, openInfoMessage, openErrorMessage });
|
||||||
|
|
||||||
const exportToMarkdownLocal = async (editor: PlateEditor) =>
|
const exportToMarkdownLocal = async (params: Parameters<typeof exportToMarkdown>[0]) =>
|
||||||
exportToMarkdown(editor, openInfoMessage, openErrorMessage);
|
exportToMarkdown({ ...params, openInfoMessage, openErrorMessage });
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
import { BannerPlugin } from './banner-plugin';
|
import { BannerPlugin } from './banner-plugin';
|
||||||
import { CharacterCounterPlugin } from './character-counter-kit';
|
import { CharacterCounterPlugin } from './character-counter-kit';
|
||||||
import { MetricPlugin } from './metric-plugin';
|
import { MetricKit } from './metric-kit';
|
||||||
|
|
||||||
export const BusterStreamKit = [
|
export const BusterStreamKit = [
|
||||||
//BannerPlugin,
|
//BannerPlugin,
|
||||||
CharacterCounterPlugin,
|
CharacterCounterPlugin,
|
||||||
MetricPlugin
|
...MetricKit
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export * from './metric-plugin';
|
export * from './metric-kit';
|
||||||
export * from './insert-metric';
|
export * from './insert-metric';
|
|
@ -1,7 +1,7 @@
|
||||||
import type { InsertNodesOptions } from 'platejs';
|
import type { InsertNodesOptions } from 'platejs';
|
||||||
import type { PlateEditor } from 'platejs/react';
|
import type { PlateEditor } from 'platejs/react';
|
||||||
import { CUSTOM_KEYS } from '../../config/keys';
|
import { CUSTOM_KEYS } from '../../config/keys';
|
||||||
import { MetricPlugin, type TMetricElement } from './metric-plugin';
|
import { MetricPlugin, type TMetricElement } from './metric-kit';
|
||||||
|
|
||||||
export const insertMetric = (editor: PlateEditor, options?: InsertNodesOptions) => {
|
export const insertMetric = (editor: PlateEditor, options?: InsertNodesOptions) => {
|
||||||
editor.tf.insertNode<TMetricElement>(
|
editor.tf.insertNode<TMetricElement>(
|
||||||
|
@ -19,5 +19,5 @@ export const insertMetric = (editor: PlateEditor, options?: InsertNodesOptions)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const plugin = editor.getPlugin(MetricPlugin);
|
const plugin = editor.getPlugin(MetricPlugin);
|
||||||
plugin.api.metric.openAddMetricModal();
|
plugin.api.metric.openAddMetricModal();
|
||||||
}, 50);
|
}, 25);
|
||||||
};
|
};
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { createPlatePlugin } from 'platejs/react';
|
||||||
|
import type { CUSTOM_KEYS } from '../../config/keys';
|
||||||
|
import type { TMetricElement } from './metric-kit';
|
||||||
|
import { MetricElementStatic } from '../../elements/MetricElement/MetricElementStatic';
|
||||||
|
|
||||||
|
export const MetricBaseKit = [
|
||||||
|
createPlatePlugin<typeof CUSTOM_KEYS.metric, {}, {}, TMetricElement>({
|
||||||
|
key: 'metric',
|
||||||
|
node: {
|
||||||
|
isElement: true,
|
||||||
|
isVoid: false,
|
||||||
|
component: MetricElementStatic
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
|
@ -48,3 +48,5 @@ export const MetricPlugin = createPlatePlugin<
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const MetricKit = [MetricPlugin];
|
|
@ -314,6 +314,7 @@ const useDuplicateReportSelectMenu = (): DropdownItem => {
|
||||||
// Download as PDF
|
// Download as PDF
|
||||||
const useDownloadPdfSelectMenu = ({ reportId }: { reportId: string }): DropdownItem => {
|
const useDownloadPdfSelectMenu = ({ reportId }: { reportId: string }): DropdownItem => {
|
||||||
const { openErrorMessage } = useBusterNotifications();
|
const { openErrorMessage } = useBusterNotifications();
|
||||||
|
const { data: reportName } = useGetReport({ reportId }, { select: (x) => x.name });
|
||||||
const { exportToPdf } = useExportReport();
|
const { exportToPdf } = useExportReport();
|
||||||
|
|
||||||
const onClick = async () => {
|
const onClick = async () => {
|
||||||
|
@ -326,7 +327,7 @@ const useDownloadPdfSelectMenu = ({ reportId }: { reportId: string }): DropdownI
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await exportToPdf(editor);
|
await exportToPdf({ editor, filename: reportName });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
openErrorMessage('Failed to export report as PDF');
|
openErrorMessage('Failed to export report as PDF');
|
||||||
|
|
Loading…
Reference in New Issue