From cb02074cba49ab8135fead432bb5ee0f6bf2df80 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Fri, 8 Aug 2025 13:58:25 -0600 Subject: [PATCH] handle after print --- .../components/ui/report/editor-base-kit.tsx | 4 +- .../report/elements/ExportToolbarButton.tsx | 8 ++-- .../elements/MetricElement/MetricContent.tsx | 7 +-- .../elements/MetricElement/MetricElement.tsx | 2 +- .../MetricElement/MetricElementStatic.tsx | 39 ++++++++++++++++ .../MetricElement/MetricPlaceholder.tsx | 2 +- .../ui/report/elements/transforms.ts | 2 +- .../ui/report/hooks/buildExportHtml.ts | 44 ++++++------------- .../ui/report/hooks/buildExportHtml2.ts | 5 +++ .../ui/report/hooks/exportToHtml.ts | 28 +++++++----- .../ui/report/hooks/exportToImage.ts | 24 ++++++---- .../ui/report/hooks/exportToMarkdown.ts | 22 ++++++---- .../components/ui/report/hooks/exportToPdf.ts | 38 +++++++++++----- .../ui/report/hooks/useExportReport.ts | 17 ++++--- .../ui/report/plugins/buster-stream-kit.tsx | 4 +- .../{metric-plugin => metric-kit}/index.ts | 2 +- .../insert-metric.ts | 4 +- .../plugins/metric-kit/metric-base-kit.tsx | 15 +++++++ .../metric-kit.tsx} | 2 + .../ReportThreeDotMenu.tsx | 3 +- 20 files changed, 178 insertions(+), 94 deletions(-) create mode 100644 apps/web/src/components/ui/report/elements/MetricElement/MetricElementStatic.tsx create mode 100644 apps/web/src/components/ui/report/hooks/buildExportHtml2.ts rename apps/web/src/components/ui/report/plugins/{metric-plugin => metric-kit}/index.ts (50%) rename apps/web/src/components/ui/report/plugins/{metric-plugin => metric-kit}/insert-metric.ts (89%) create mode 100644 apps/web/src/components/ui/report/plugins/metric-kit/metric-base-kit.tsx rename apps/web/src/components/ui/report/plugins/{metric-plugin/metric-plugin.tsx => metric-kit/metric-kit.tsx} (97%) diff --git a/apps/web/src/components/ui/report/editor-base-kit.tsx b/apps/web/src/components/ui/report/editor-base-kit.tsx index faf0b09bc..5d0ffb1f2 100644 --- a/apps/web/src/components/ui/report/editor-base-kit.tsx +++ b/apps/web/src/components/ui/report/editor-base-kit.tsx @@ -17,6 +17,7 @@ import { MarkdownKit } from './plugins/markdown-kit'; import { BaseMathKit } from './plugins/math-base-kit'; import { BaseMediaKit } from './plugins/media-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 { BaseTableKit } from './plugins/table-base-kit'; import { BaseTocKit } from './plugins/toc-base-kit'; @@ -44,5 +45,6 @@ export const BaseEditorKit = [ ...BaseCommentKit, ...BaseSuggestionKit, ...MarkdownKit, - ...BusterStreamKit + ...BusterStreamKit, + ...MetricBaseKit ]; diff --git a/apps/web/src/components/ui/report/elements/ExportToolbarButton.tsx b/apps/web/src/components/ui/report/elements/ExportToolbarButton.tsx index 84b5c2b0c..974ad41f0 100644 --- a/apps/web/src/components/ui/report/elements/ExportToolbarButton.tsx +++ b/apps/web/src/components/ui/report/elements/ExportToolbarButton.tsx @@ -34,16 +34,16 @@ export function ExportToolbarButton({ children, ...props }: DropdownMenuProps) { - exportToHtml(editor)}> + exportToHtml({ editor })}> {NodeTypeLabels.exportAsHtml.label} - exportToPdf(editor)}> + exportToPdf({ editor })}> {NodeTypeLabels.exportAsPdf.label} - exportToImage(editor)}> + exportToImage({ editor })}> {NodeTypeLabels.exportAsImage.label} - exportToMarkdown(editor)}> + exportToMarkdown({ editor })}> {NodeTypeLabels.exportAsMarkdown.label} diff --git a/apps/web/src/components/ui/report/elements/MetricElement/MetricContent.tsx b/apps/web/src/components/ui/report/elements/MetricElement/MetricContent.tsx index e2fa65c8d..d0a059a31 100644 --- a/apps/web/src/components/ui/report/elements/MetricElement/MetricContent.tsx +++ b/apps/web/src/components/ui/report/elements/MetricElement/MetricContent.tsx @@ -5,17 +5,18 @@ import { useChatLayoutContextSelector } from '@/layouts/ChatLayout'; import { assetParamsToRoute } from '@/lib/assets/assetParamsToRoute'; import React, { useMemo, useRef } from 'react'; import { useMetricContentThreeDotMenuItems } from './useMetricContentThreeDotMenuItems'; -import { cn } from '@/lib/classMerge'; export const MetricContent = React.memo( ({ metricId, metricVersionNumber, + isBaseElement = false, readOnly = false }: { metricId: string; metricVersionNumber: number | undefined; readOnly?: boolean; + isBaseElement?: boolean; }) => { const chatId = useChatLayoutContextSelector((x) => x.chatId); const reportId = useChatLayoutContextSelector((x) => x.reportId) || ''; @@ -23,7 +24,7 @@ export const MetricContent = React.memo( const ref = useRef(null); const [inViewport] = useInViewport(ref, { - threshold: 0.33 + threshold: isBaseElement ? 0 : 0.33 }); const renderChart = inViewport; @@ -72,7 +73,7 @@ export const MetricContent = React.memo( return ( +) => { + const metricId = props.element.metricId; + const metricVersionNumber = props.element.metricVersionNumber; + const readOnly = true; + const { align = 'center', caption, url, width } = props.element; + + const content = metricId ? ( + + ) : ( + + ); + + return ( + +
+
+ {content} +
+
{props.children}
+
+
+ ); +}; diff --git a/apps/web/src/components/ui/report/elements/MetricElement/MetricPlaceholder.tsx b/apps/web/src/components/ui/report/elements/MetricElement/MetricPlaceholder.tsx index a2e8e408f..3c046148e 100644 --- a/apps/web/src/components/ui/report/elements/MetricElement/MetricPlaceholder.tsx +++ b/apps/web/src/components/ui/report/elements/MetricElement/MetricPlaceholder.tsx @@ -13,7 +13,7 @@ import { import React, { useEffect } from 'react'; import { useMemoizedFn } from '@/hooks/useMemoizedFn'; 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 = () => { const [openModal, setOpenModal] = React.useState(false); diff --git a/apps/web/src/components/ui/report/elements/transforms.ts b/apps/web/src/components/ui/report/elements/transforms.ts index c751d66fb..3ccf5d711 100644 --- a/apps/web/src/components/ui/report/elements/transforms.ts +++ b/apps/web/src/components/ui/report/elements/transforms.ts @@ -19,7 +19,7 @@ import { TablePlugin } from '@platejs/table/react'; import { insertToc } from '@platejs/toc'; import { type NodeEntry, type Path, type TElement, KEYS, PathApi } from 'platejs'; 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'; diff --git a/apps/web/src/components/ui/report/hooks/buildExportHtml.ts b/apps/web/src/components/ui/report/hooks/buildExportHtml.ts index 1e4ca1365..2b8b377c7 100644 --- a/apps/web/src/components/ui/report/hooks/buildExportHtml.ts +++ b/apps/web/src/components/ui/report/hooks/buildExportHtml.ts @@ -6,7 +6,18 @@ import { createSlateEditor, serializeHtml } from 'platejs'; // computed CSS styles so no external CSS is required. Additionally, // snapshot elements inside metrics to tags to avoid // blank canvases in the exported HTML. -export const buildExportHtml = async (editor: PlateEditor): Promise => { +// 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 => { + // Resolve the document title with a sensible default + const documentTitle = options?.title || 'Buster Report'; // Prefer using the live editor DOM to inline computed styles const liveRoot = document.querySelector('[contenteditable="true"]') as HTMLElement | null; @@ -89,35 +100,7 @@ export const buildExportHtml = async (editor: PlateEditor): Promise => { wrapper.appendChild(clonedRoot); contentHtml = wrapper.outerHTML; } else { - // Fallback: serialize using static editor and include minimal inline styles - 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; + throw new Error('No live root found'); } // Build a minimal HTML document without external CSS @@ -127,6 +110,7 @@ export const buildExportHtml = async (editor: PlateEditor): Promise => { + ${documentTitle}