From a6a7ce6b6872483230267119052d856e7f591e49 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 4 May 2025 23:04:15 +0400 Subject: [PATCH] enh: import md notes --- .../components/common/RichTextInput.svelte | 4 + src/lib/components/notes/NoteEditor.svelte | 1 + src/lib/components/notes/Notes.svelte | 352 +++++++++++------- 3 files changed, 231 insertions(+), 126 deletions(-) diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index fa35add42..326b033b2 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -165,6 +165,10 @@ // Usage example content = await tryParse(value); } + } else { + if (html && !content) { + content = html; + } } console.log('content', content); diff --git a/src/lib/components/notes/NoteEditor.svelte b/src/lib/components/notes/NoteEditor.svelte index c247f6909..36651d2a0 100644 --- a/src/lib/components/notes/NoteEditor.svelte +++ b/src/lib/components/notes/NoteEditor.svelte @@ -504,6 +504,7 @@ className="input-prose-sm px-0.5" bind:value={note.data.content.json} placeholder={$i18n.t('Write something...')} + html={note.data?.content?.html} json={true} onChange={(content) => { note.data.content.html = content.html; diff --git a/src/lib/components/notes/Notes.svelte b/src/lib/components/notes/Notes.svelte index 7ec9d830e..932b5a670 100644 --- a/src/lib/components/notes/Notes.svelte +++ b/src/lib/components/notes/Notes.svelte @@ -28,7 +28,7 @@ $: loadLocale($i18n.languages); import { goto } from '$app/navigation'; - import { onMount, getContext } from 'svelte'; + import { onMount, getContext, onDestroy } from 'svelte'; import { WEBUI_NAME, config, prompts as _prompts, user } from '$lib/stores'; import { createNewNote, deleteNoteById, getNotes } from '$lib/apis/notes'; @@ -42,6 +42,8 @@ import Spinner from '../common/Spinner.svelte'; import Tooltip from '../common/Tooltip.svelte'; import NoteMenu from './Notes/NoteMenu.svelte'; + import FilesOverlay from '../chat/MessageInput/FilesOverlay.svelte'; + import { marked } from 'marked'; const i18n = getContext('i18n'); let loaded = false; @@ -166,9 +168,103 @@ } }; + const inputFilesHandler = async (inputFiles) => { + // Check if all the file is a markdown file and extract name and content + + for (const file of inputFiles) { + if (file.type !== 'text/markdown') { + toast.error($i18n.t('Only markdown files are allowed')); + return; + } + + const reader = new FileReader(); + reader.onload = async (event) => { + const content = event.target.result; + let name = file.name.replace(/\.md$/, ''); + + if (typeof content !== 'string') { + toast.error($i18n.t('Invalid file content')); + return; + } + + // Create a new note with the content + const res = await createNewNote(localStorage.token, { + title: name, + data: { + content: { + json: null, + html: marked.parse(content ?? ''), + md: content + } + }, + meta: null, + access_control: null + }).catch((error) => { + toast.error(`${error}`); + return null; + }); + + if (res) { + init(); + } + }; + + reader.readAsText(file); + } + }; + + let dragged = false; + + const onDragOver = (e) => { + e.preventDefault(); + + // Check if a file is being dragged. + if (e.dataTransfer?.types?.includes('Files')) { + dragged = true; + } else { + dragged = false; + } + }; + + const onDragLeave = () => { + dragged = false; + }; + + const onDrop = async (e) => { + e.preventDefault(); + console.log(e); + + if (e.dataTransfer?.files) { + const inputFiles = Array.from(e.dataTransfer?.files); + if (inputFiles && inputFiles.length > 0) { + console.log(inputFiles); + inputFilesHandler(inputFiles); + } + } + + dragged = false; + }; + + onDestroy(() => { + console.log('destroy'); + const dropzoneElement = document.getElementById('notes-container'); + + if (dropzoneElement) { + dropzoneElement?.removeEventListener('dragover', onDragOver); + dropzoneElement?.removeEventListener('drop', onDrop); + dropzoneElement?.removeEventListener('dragleave', onDragLeave); + } + }); + onMount(async () => { await init(); loaded = true; + + const dropzoneElement = document.getElementById('notes-container'); + + dropzoneElement?.addEventListener('dragover', onDragOver); + dropzoneElement?.addEventListener('drop', onDrop); + dropzoneElement?.addEventListener('dragleave', onDragLeave); }); @@ -178,136 +274,139 @@ -{#if loaded} - { - deleteNoteHandler(selectedNote.id); - showDeleteConfirm = false; - }} - > -
- {$i18n.t('This will delete')} {selectedNote.title}. -
-
+ -
- {#if Object.keys(notes).length > 0} - {#each Object.keys(notes) as timeRange} -
- {$i18n.t(timeRange)} -
- - - {/each} - {:else} -
-
-
- {$i18n.t('No Notes')} -
- -
- {$i18n.t('Create your first note by clicking on the plus button below.')} -
-
+
+ {#if loaded} + { + deleteNoteHandler(selectedNote.id); + showDeleteConfirm = false; + }} + > +
+ {$i18n.t('This will delete')} {selectedNote.title}.
- {/if} -
+ -
-
- - - +
+ {#if Object.keys(notes).length > 0} + {#each Object.keys(notes) as timeRange} +
+ {$i18n.t(timeRange)} +
- +
-
- -{:else} -
- -
-{/if} + {:else} +
+ +
+ {/if} +