diff --git a/src/lib/components/notes/NoteEditor.svelte b/src/lib/components/notes/NoteEditor.svelte index ea707b0d2d..6458b5015c 100644 --- a/src/lib/components/notes/NoteEditor.svelte +++ b/src/lib/components/notes/NoteEditor.svelte @@ -38,11 +38,12 @@ WEBUI_NAME } from '$lib/stores'; - import NotePanel from '$lib/components/notes/NotePanel.svelte'; + import { downloadPdf } from './utils'; import Controls from './NoteEditor/Controls.svelte'; import Chat from './NoteEditor/Chat.svelte'; + import NotePanel from '$lib/components/notes/NotePanel.svelte'; import AccessControlModal from '$lib/components/workspace/common/AccessControlModal.svelte'; async function loadLocale(locales) { @@ -566,117 +567,11 @@ ${content} const blob = new Blob([note.data.content.md], { type: 'text/markdown' }); saveAs(blob, `${note.title}.md`); } else if (type === 'pdf') { - await downloadPdf(note); - } - }; - - const downloadPdf = async (note) => { - try { - const [{ default: jsPDF }, { default: html2canvas }] = await Promise.all([ - import('jspdf'), - import('html2canvas-pro') - ]); - - // Define a fixed virtual screen size - const virtualWidth = 1024; // Fixed width (adjust as needed) - const virtualHeight = 1400; // Fixed height (adjust as needed) - - // STEP 1. Get a DOM node to render - const html = note.data?.content?.html ?? ''; - const isDarkMode = document.documentElement.classList.contains('dark'); - - let node; - if (html instanceof HTMLElement) { - node = html; - } else { - const virtualWidth = 800; // px, fixed width for cloned element - - // Clone and style - node = document.createElement('div'); - - // title node - const titleNode = document.createElement('div'); - titleNode.textContent = note.title; - titleNode.style.fontSize = '24px'; - titleNode.style.fontWeight = 'medium'; - titleNode.style.paddingBottom = '20px'; - titleNode.style.color = isDarkMode ? 'white' : 'black'; - node.appendChild(titleNode); - - const contentNode = document.createElement('div'); - - contentNode.innerHTML = html; - - node.appendChild(contentNode); - - node.classList.add('text-black'); - node.classList.add('dark:text-white'); - node.style.width = `${virtualWidth}px`; - node.style.position = 'absolute'; - node.style.left = '-9999px'; - node.style.height = 'auto'; - node.style.padding = '40px 40px'; - - console.log(node); - document.body.appendChild(node); + try { + await downloadPdf(note); + } catch (error) { + toast.error(`${error}`); } - - // Render to canvas with predefined width - const canvas = await html2canvas(node, { - useCORS: true, - backgroundColor: isDarkMode ? '#000' : '#fff', - scale: 2, // Keep at 1x to avoid unexpected enlargements - width: virtualWidth, // Set fixed virtual screen width - windowWidth: virtualWidth, // Ensure consistent rendering - windowHeight: virtualHeight - }); - - // Remove hidden node if needed - if (!(html instanceof HTMLElement)) { - document.body.removeChild(node); - } - - const imgData = canvas.toDataURL('image/jpeg', 0.7); - - // A4 page settings - const pdf = new jsPDF('p', 'mm', 'a4'); - const imgWidth = 210; // A4 width in mm - const pageWidthMM = 210; // A4 width in mm - const pageHeight = 297; // A4 height in mm - const pageHeightMM = 297; // A4 height in mm - - if (isDarkMode) { - pdf.setFillColor(0, 0, 0); - pdf.rect(0, 0, pageWidthMM, pageHeightMM, 'F'); // black bg - } - - // Maintain aspect ratio - const imgHeight = (canvas.height * imgWidth) / canvas.width; - let heightLeft = imgHeight; - let position = 0; - - pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight); - heightLeft -= pageHeight; - - // Handle additional pages - while (heightLeft > 0) { - position -= pageHeight; - pdf.addPage(); - - if (isDarkMode) { - pdf.setFillColor(0, 0, 0); - pdf.rect(0, 0, pageWidthMM, pageHeightMM, 'F'); // black bg - } - - pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight); - heightLeft -= pageHeight; - } - - pdf.save(`${note.title}.pdf`); - } catch (error) { - console.error('Error generating PDF', error); - - toast.error(`${error}`); } }; diff --git a/src/lib/components/notes/Notes.svelte b/src/lib/components/notes/Notes.svelte index 3f4294cf5b..14f1392625 100644 --- a/src/lib/components/notes/Notes.svelte +++ b/src/lib/components/notes/Notes.svelte @@ -36,6 +36,8 @@ import { createNewNote, deleteNoteById, getNotes } from '$lib/apis/notes'; import { capitalizeFirstLetter, copyToClipboard, getTimeRange } from '$lib/utils'; + import { downloadPdf } from './utils'; + import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte'; import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte'; import Search from '../icons/Search.svelte'; @@ -124,82 +126,18 @@ }; const downloadHandler = async (type) => { - console.log('downloadHandler', type); - console.log('selectedNote', selectedNote); - if (type === 'md') { + if (type === 'txt') { + const blob = new Blob([selectedNote.data.content.md], { type: 'text/plain' }); + saveAs(blob, `${selectedNote.title}.txt`); + } else if (type === 'md') { const blob = new Blob([selectedNote.data.content.md], { type: 'text/markdown' }); saveAs(blob, `${selectedNote.title}.md`); } else if (type === 'pdf') { - await downloadPdf(selectedNote); - } - }; - - const downloadPdf = async (note) => { - try { - const [{ default: jsPDF }, { default: html2canvas }] = await Promise.all([ - import('jspdf'), - import('html2canvas-pro') - ]); - - // Define a fixed virtual screen size - const virtualWidth = 1024; // Fixed width (adjust as needed) - const virtualHeight = 1400; // Fixed height (adjust as needed) - - // STEP 1. Get a DOM node to render - const html = note.data?.content?.html ?? ''; - let node; - if (html instanceof HTMLElement) { - node = html; - } else { - // If it's HTML string, render to a temporary hidden element - node = document.createElement('div'); - node.innerHTML = html; - document.body.appendChild(node); + try { + await downloadPdf(selectedNote); + } catch (error) { + toast.error(`${error}`); } - - // Render to canvas with predefined width - const canvas = await html2canvas(node, { - useCORS: true, - scale: 2, // Keep at 1x to avoid unexpected enlargements - width: virtualWidth, // Set fixed virtual screen width - windowWidth: virtualWidth, // Ensure consistent rendering - windowHeight: virtualHeight - }); - - // Remove hidden node if needed - if (!(html instanceof HTMLElement)) { - document.body.removeChild(node); - } - - const imgData = canvas.toDataURL('image/jpeg', 0.7); - - // A4 page settings - const pdf = new jsPDF('p', 'mm', 'a4'); - const imgWidth = 210; // A4 width in mm - const pageHeight = 297; // A4 height in mm - - // Maintain aspect ratio - const imgHeight = (canvas.height * imgWidth) / canvas.width; - let heightLeft = imgHeight; - let position = 0; - - pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight); - heightLeft -= pageHeight; - - // Handle additional pages - while (heightLeft > 0) { - position -= pageHeight; - pdf.addPage(); - - pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight); - heightLeft -= pageHeight; - } - - pdf.save(`${note.title}.pdf`); - } catch (error) { - console.error('Error generating PDF', error); - - toast.error(`${error}`); } }; diff --git a/src/lib/components/notes/utils.ts b/src/lib/components/notes/utils.ts new file mode 100644 index 0000000000..46a7ea8458 --- /dev/null +++ b/src/lib/components/notes/utils.ts @@ -0,0 +1,103 @@ +export const downloadPdf = async (note) => { + const [{ default: jsPDF }, { default: html2canvas }] = await Promise.all([ + import('jspdf'), + import('html2canvas-pro') + ]); + + // Define a fixed virtual screen size + const virtualWidth = 1024; // Fixed width (adjust as needed) + const virtualHeight = 1400; // Fixed height (adjust as needed) + + // STEP 1. Get a DOM node to render + const html = note.data?.content?.html ?? ''; + const isDarkMode = document.documentElement.classList.contains('dark'); + + let node; + if (html instanceof HTMLElement) { + node = html; + } else { + const virtualWidth = 800; // px, fixed width for cloned element + + // Clone and style + node = document.createElement('div'); + + // title node + const titleNode = document.createElement('div'); + titleNode.textContent = note.title; + titleNode.style.fontSize = '24px'; + titleNode.style.fontWeight = 'medium'; + titleNode.style.paddingBottom = '20px'; + titleNode.style.color = isDarkMode ? 'white' : 'black'; + node.appendChild(titleNode); + + const contentNode = document.createElement('div'); + + contentNode.innerHTML = html; + + node.appendChild(contentNode); + + node.classList.add('text-black'); + node.classList.add('dark:text-white'); + node.style.width = `${virtualWidth}px`; + node.style.position = 'absolute'; + node.style.left = '-9999px'; + node.style.height = 'auto'; + node.style.padding = '40px 40px'; + + console.log(node); + document.body.appendChild(node); + } + + // Render to canvas with predefined width + const canvas = await html2canvas(node, { + useCORS: true, + backgroundColor: isDarkMode ? '#000' : '#fff', + scale: 2, // Keep at 1x to avoid unexpected enlargements + width: virtualWidth, // Set fixed virtual screen width + windowWidth: virtualWidth, // Ensure consistent rendering + windowHeight: virtualHeight + }); + + // Remove hidden node if needed + if (!(html instanceof HTMLElement)) { + document.body.removeChild(node); + } + + const imgData = canvas.toDataURL('image/jpeg', 0.7); + + // A4 page settings + const pdf = new jsPDF('p', 'mm', 'a4'); + const imgWidth = 210; // A4 width in mm + const pageWidthMM = 210; // A4 width in mm + const pageHeight = 297; // A4 height in mm + const pageHeightMM = 297; // A4 height in mm + + if (isDarkMode) { + pdf.setFillColor(0, 0, 0); + pdf.rect(0, 0, pageWidthMM, pageHeightMM, 'F'); // black bg + } + + // Maintain aspect ratio + const imgHeight = (canvas.height * imgWidth) / canvas.width; + let heightLeft = imgHeight; + let position = 0; + + pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight); + heightLeft -= pageHeight; + + // Handle additional pages + while (heightLeft > 0) { + position -= pageHeight; + pdf.addPage(); + + if (isDarkMode) { + pdf.setFillColor(0, 0, 0); + pdf.rect(0, 0, pageWidthMM, pageHeightMM, 'F'); // black bg + } + + pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight); + heightLeft -= pageHeight; + } + + pdf.save(`${note.title}.pdf`); +};