added additional styles

This commit is contained in:
Nate Kelley 2025-08-08 11:05:55 -06:00
parent 124997a1c0
commit fb5abb8a75
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
3 changed files with 43 additions and 28 deletions

View File

@ -46,7 +46,7 @@ export const MetricTitle: React.FC<{
{`${name}`} {`${name}`}
</Title> </Title>
) : ( ) : (
<div className="bg-item-active h-3.5 w-4/5 rounded-lg" /> <div className="bg-item-active/75 h-3.5 w-4/5 rounded-lg" />
)} )}
</div> </div>
@ -64,7 +64,7 @@ export const MetricTitle: React.FC<{
{description} {description}
</Text> </Text>
) : ( ) : (
<div className="bg-item-active mt-1 h-3.5 w-full rounded-lg" /> <div className="bg-item-active/75 mt-1 h-3.5 w-full rounded-lg" />
)} )}
</div> </div>
</div> </div>

View File

@ -12,7 +12,10 @@ export const useExportReport = () => {
const getCanvas = async (editor: PlateEditor) => { const getCanvas = async (editor: PlateEditor) => {
const { default: html2canvas } = await import('html2canvas-pro'); const { default: html2canvas } = await import('html2canvas-pro');
// Create a temporary style element to isolate any styles needed during export.
// Ensure it is always cleaned up, even if an error occurs during rendering.
const style = document.createElement('style'); const style = document.createElement('style');
style.setAttribute('data-report-export-style', 'true');
document.head.append(style); document.head.append(style);
// Standard width for consistent PDF output (equivalent to A4 width with margins) // Standard width for consistent PDF output (equivalent to A4 width with margins)
@ -21,36 +24,41 @@ export const useExportReport = () => {
const node = editor.api.toDOMNode(editor)!; const node = editor.api.toDOMNode(editor)!;
if (!node) { if (!node) {
// Ensure cleanup of style element if editor is missing
style.remove();
throw new Error('Editor not found'); throw new Error('Editor not found');
} }
const canvas = await html2canvas(node, { try {
onclone: (document: Document) => { const canvas = await html2canvas(node, {
const editorElement = document.querySelector('[contenteditable="true"]'); onclone: (document: Document) => {
if (editorElement) { const editorElement = document.querySelector('[contenteditable="true"]');
// Force consistent width for the editor element if (editorElement) {
const existingStyle = editorElement.getAttribute('style') || ''; // Force consistent width for the editor element
editorElement.setAttribute( const existingStyle = editorElement.getAttribute('style') || '';
'style', editorElement.setAttribute(
`${existingStyle}; width: ${standardWidth} !important; max-width: ${standardWidth} !important; min-width: ${standardWidth} !important;`
);
// Apply consistent font family to all elements
Array.from(editorElement.querySelectorAll('*')).forEach((element) => {
const elementStyle = element.getAttribute('style') || '';
element.setAttribute(
'style', 'style',
`${elementStyle}; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important` `${existingStyle}; width: ${standardWidth} !important; max-width: ${standardWidth} !important; min-width: ${standardWidth} !important;`
); );
});
} else {
throw new Error('Editor element not found');
}
}
});
style.remove();
return canvas; // Apply consistent font family to all elements
Array.from(editorElement.querySelectorAll('*')).forEach((element) => {
const elementStyle = element.getAttribute('style') || '';
element.setAttribute(
'style',
`${elementStyle}; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important`
);
});
} else {
throw new Error('Editor element not found');
}
}
});
return canvas;
} finally {
// Always remove temporary style tag
style.remove();
}
}; };
const downloadFile = async (url: string, filename: string) => { const downloadFile = async (url: string, filename: string) => {
@ -89,6 +97,7 @@ export const useExportReport = () => {
await downloadFile(pdfBase64, 'plate.pdf'); await downloadFile(pdfBase64, 'plate.pdf');
openInfoMessage(NodeTypeLabels.pdfExportedSuccessfully.label); openInfoMessage(NodeTypeLabels.pdfExportedSuccessfully.label);
} catch (error) { } catch (error) {
console.error(error);
openErrorMessage(NodeTypeLabels.failedToExportPdf.label); openErrorMessage(NodeTypeLabels.failedToExportPdf.label);
} }
}; };
@ -99,6 +108,7 @@ export const useExportReport = () => {
await downloadFile(canvas.toDataURL('image/png'), 'plate.png'); await downloadFile(canvas.toDataURL('image/png'), 'plate.png');
openInfoMessage(NodeTypeLabels.imageExportedSuccessfully.label); openInfoMessage(NodeTypeLabels.imageExportedSuccessfully.label);
} catch (error) { } catch (error) {
console.error(error);
openErrorMessage(NodeTypeLabels.failedToExportImage.label); openErrorMessage(NodeTypeLabels.failedToExportImage.label);
} }
}; };
@ -154,6 +164,7 @@ export const useExportReport = () => {
await downloadFile(url, 'plate.html'); await downloadFile(url, 'plate.html');
openInfoMessage(NodeTypeLabels.htmlExportedSuccessfully.label); openInfoMessage(NodeTypeLabels.htmlExportedSuccessfully.label);
} catch (error) { } catch (error) {
console.error(error);
openErrorMessage(NodeTypeLabels.failedToExportHtml.label); openErrorMessage(NodeTypeLabels.failedToExportHtml.label);
} }
}; };
@ -165,6 +176,7 @@ export const useExportReport = () => {
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);
openErrorMessage(NodeTypeLabels.failedToExportMarkdown.label); openErrorMessage(NodeTypeLabels.failedToExportMarkdown.label);
} }
}; };

View File

@ -314,19 +314,22 @@ 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 editor = getReportEditor(reportId);
const { exportToPdf } = useExportReport(); const { exportToPdf } = useExportReport();
const onClick = async () => { const onClick = async () => {
try { try {
const editor = getReportEditor(reportId);
if (!editor) { if (!editor) {
console.error('Editor not found');
openErrorMessage(NodeTypeLabels.failedToExportPdf.label); openErrorMessage(NodeTypeLabels.failedToExportPdf.label);
return; return;
} }
await exportToPdf(editor); await exportToPdf(editor);
} catch (error) { } catch (error) {
openErrorMessage('Failed to export PDF'); console.error(error);
openErrorMessage('Failed to export report as PDF');
} }
}; };