Bladeren bron

enh: note search

Timothy Jaeryang Baek 3 maanden geleden
bovenliggende
commit
de343021c1
1 gewijzigde bestanden met toevoegingen van 71 en 3 verwijderingen
  1. 71 3
      src/lib/components/notes/Notes.svelte

+ 71 - 3
src/lib/components/notes/Notes.svelte

@@ -1,6 +1,8 @@
 <script lang="ts">
 	import { toast } from 'svelte-sonner';
 	import fileSaver from 'file-saver';
+	import Fuse from 'fuse.js';
+
 	const { saveAs } = fileSaver;
 
 	import jsPDF from 'jspdf';
@@ -32,7 +34,7 @@
 	import { WEBUI_NAME, config, prompts as _prompts, user } from '$lib/stores';
 
 	import { createNewNote, deleteNoteById, getNotes } from '$lib/apis/notes';
-	import { capitalizeFirstLetter, copyToClipboard } from '$lib/utils';
+	import { capitalizeFirstLetter, copyToClipboard, getTimeRange } from '$lib/utils';
 
 	import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte';
 	import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
@@ -44,6 +46,7 @@
 	import NoteMenu from './Notes/NoteMenu.svelte';
 	import FilesOverlay from '../chat/MessageInput/FilesOverlay.svelte';
 	import { marked } from 'marked';
+	import XMark from '../icons/XMark.svelte';
 
 	const i18n = getContext('i18n');
 	let loaded = false;
@@ -51,13 +54,50 @@
 	let importFiles = '';
 	let query = '';
 
-	let notes = [];
+	let noteItems = [];
+	let fuse = null;
+
 	let selectedNote = null;
+	let notes = {};
+	$: if (fuse) {
+		notes = groupNotes(
+			query
+				? fuse.search(query).map((e) => {
+						return e.item;
+					})
+				: noteItems
+		);
+	}
 
 	let showDeleteConfirm = false;
 
+	const groupNotes = (res) => {
+		console.log(res);
+		if (!Array.isArray(res)) {
+			return {}; // or throw new Error("Notes response is not an array")
+		}
+
+		// Build the grouped object
+		const grouped: Record<string, any[]> = {};
+		for (const note of res) {
+			const timeRange = getTimeRange(note.updated_at / 1000000000);
+			if (!grouped[timeRange]) {
+				grouped[timeRange] = [];
+			}
+			grouped[timeRange].push({
+				...note,
+				timeRange
+			});
+		}
+		return grouped;
+	};
+
 	const init = async () => {
-		notes = await getNotes(localStorage.token);
+		noteItems = await getNotes(localStorage.token, true);
+
+		fuse = new Fuse(noteItems, {
+			keys: ['title']
+		});
 	};
 
 	const createNoteHandler = async () => {
@@ -293,6 +333,34 @@
 			</div>
 		</DeleteConfirmDialog>
 
+		<div class="flex flex-col gap-1 px-3.5">
+			<div class=" flex flex-1 items-center w-full space-x-2">
+				<div class="flex flex-1 items-center">
+					<div class=" self-center ml-1 mr-3">
+						<Search className="size-3.5" />
+					</div>
+					<input
+						class=" w-full text-sm py-1 rounded-r-xl outline-hidden bg-transparent"
+						bind:value={query}
+						placeholder={$i18n.t('Search Notes')}
+					/>
+
+					{#if query}
+						<div class="self-center pl-1.5 translate-y-[0.5px] rounded-l-xl bg-transparent">
+							<button
+								class="p-0.5 rounded-full hover:bg-gray-100 dark:hover:bg-gray-900 transition"
+								on:click={() => {
+									query = '';
+								}}
+							>
+								<XMark className="size-3" strokeWidth="2" />
+							</button>
+						</div>
+					{/if}
+				</div>
+			</div>
+		</div>
+
 		<div class="px-4.5 @container h-full pt-2">
 			{#if Object.keys(notes).length > 0}
 				<div class="pb-10">