From 175bbe27e98f2e09cf05887b52c730659bb6730f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 4 May 2025 16:53:48 +0400 Subject: [PATCH] refac --- src/lib/components/notes/NoteEditor.svelte | 4 +- src/lib/components/notes/Notes.svelte | 89 ++++++++++++++++++- .../components/notes/Notes/NoteMenu.svelte | 87 ++++++++++++++++++ 3 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 src/lib/components/notes/Notes/NoteMenu.svelte diff --git a/src/lib/components/notes/NoteEditor.svelte b/src/lib/components/notes/NoteEditor.svelte index 84f769acd..58cfa3932 100644 --- a/src/lib/components/notes/NoteEditor.svelte +++ b/src/lib/components/notes/NoteEditor.svelte @@ -371,8 +371,8 @@ placeholder={$i18n.t('Write something...')} json={true} onChange={(content) => { - note.data.html = content.html; - note.data.md = content.md; + note.data.content.html = content.html; + note.data.content.md = content.md; }} /> diff --git a/src/lib/components/notes/Notes.svelte b/src/lib/components/notes/Notes.svelte index 4b460b2dc..6fc98ede9 100644 --- a/src/lib/components/notes/Notes.svelte +++ b/src/lib/components/notes/Notes.svelte @@ -3,6 +3,9 @@ import fileSaver from 'file-saver'; const { saveAs } = fileSaver; + import jsPDF from 'jspdf'; + import html2canvas from 'html2canvas-pro'; + import dayjs from '$lib/dayjs'; import duration from 'dayjs/plugin/duration'; import relativeTime from 'dayjs/plugin/relativeTime'; @@ -29,6 +32,7 @@ import { WEBUI_NAME, config, prompts as _prompts, user } from '$lib/stores'; import { createNewNote, getNotes } from '$lib/apis/notes'; + import { capitalizeFirstLetter } from '$lib/utils'; import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte'; import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte'; @@ -37,7 +41,7 @@ import ChevronRight from '../icons/ChevronRight.svelte'; import Spinner from '../common/Spinner.svelte'; import Tooltip from '../common/Tooltip.svelte'; - import { capitalizeFirstLetter } from '$lib/utils'; + import NoteMenu from './Notes/NoteMenu.svelte'; const i18n = getContext('i18n'); let loaded = false; @@ -76,6 +80,62 @@ } }; + const downloadHandler = async (type) => { + console.log('downloadHandler', type); + console.log('selectedNote', selectedNote); + 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 { + // Define a fixed virtual screen size + const virtualWidth = 1024; // Fixed width (adjust as needed) + const virtualHeight = 1400; // Fixed height (adjust as needed) + + // Render to canvas with predefined width + const canvas = await html2canvas(note.data.content.html, { + 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 + }); + + const imgData = canvas.toDataURL('image/png'); + + // 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, 'PNG', 0, position, imgWidth, imgHeight); + heightLeft -= pageHeight; + + // Handle additional pages + while (heightLeft > 0) { + position -= pageHeight; + pdf.addPage(); + + pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); + heightLeft -= pageHeight; + } + + pdf.save(`${note.title}.pdf`); + } catch (error) { + console.error('Error generating PDF', error); + } + }; + onMount(async () => { await init(); loaded = true; @@ -117,15 +177,36 @@ class="w-full -translate-y-0.5 flex flex-col justify-between" >
-
+
{note.title}
+ +
+ { + selectedNote = note; + + downloadHandler(type); + }} + onDelete={() => { + selectedNote = note; + showDeleteConfirm = true; + }} + > + + +
- {#if note.data?.md} - {note.data?.md} + {#if note.data?.content?.md} + {note.data?.content?.md} {:else} {$i18n.t('No content')} {/if} diff --git a/src/lib/components/notes/Notes/NoteMenu.svelte b/src/lib/components/notes/Notes/NoteMenu.svelte new file mode 100644 index 000000000..fb54f9ecc --- /dev/null +++ b/src/lib/components/notes/Notes/NoteMenu.svelte @@ -0,0 +1,87 @@ + + + { + onChange(state); + }} +> + + + + + + fade(e, { duration: 100 })} + > + + + + +
{$i18n.t('Download')}
+
+ + { + onDownload('md'); + }} + > +
{$i18n.t('Plain text (.md)')}
+
+ + { + onDownload('pdf'); + }} + > +
{$i18n.t('PDF document (.pdf)')}
+
+
+
+ { + onDelete(); + }} + > + +
{$i18n.t('Delete')}
+
+
+
+