diff --git a/package-lock.json b/package-lock.json index 7629c13..5f015fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "drizzle-orm": "^0.45.1", "nanoid": "^5.1.6", "sharp": "^0.34.5", + "svelecte": "^5.3.0", "svelte-gestures": "^5.2.2", "svelte-lightbox": "^1.1.7", "svelte-persisted-store": "^0.12.0", @@ -5164,6 +5165,15 @@ "node": ">=8" } }, + "node_modules/svelecte": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/svelecte/-/svelecte-5.3.0.tgz", + "integrity": "sha512-9WKD6KxPf31CweyZtObTetGtkq1TncBA2E+aSHcT+bfjALgP+LUGMMQUU+2qhlfSoGpw9JYmLfxphGjb0q350g==", + "license": "MIT", + "peerDependencies": { + "svelte": "^5.2.7" + } + }, "node_modules/svelte": { "version": "5.49.0", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.49.0.tgz", diff --git a/package.json b/package.json index 2e499a8..dcd8771 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "drizzle-orm": "^0.45.1", "nanoid": "^5.1.6", "sharp": "^0.34.5", + "svelecte": "^5.3.0", "svelte-gestures": "^5.2.2", "svelte-lightbox": "^1.1.7", "svelte-persisted-store": "^0.12.0", diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index c9d28e5..04b2adc 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -1,6 +1,6 @@ import type { PageServerLoad, Actions } from './$types'; import { fail } from '@sveltejs/kit'; -import { entryRepository, imageRepository } from '$lib/server/db/repository'; +import { entryRepository, imageRepository, tagRepository } from '$lib/server/db/repository'; import { saveOriginal, saveThumbnail, @@ -13,14 +13,19 @@ export const load: PageServerLoad = async ({ url }) => { const showCompleted = url.searchParams.get('showCompleted') === 'true'; const entries = entryRepository.getOrdered({ showCompleted }); - // Attach images to each entry - const entriesWithImages = entries.map((entry) => ({ + // Attach images AND tags to each entry + const entriesWithData = entries.map((entry) => ({ ...entry, - images: imageRepository.getByEntryId(entry.id) + images: imageRepository.getByEntryId(entry.id), + tags: tagRepository.getByEntryId(entry.id) })); + // Get all tags for autocomplete + const allTags = tagRepository.getAll(); + return { - entries: entriesWithImages, + entries: entriesWithData, + allTags, showCompleted }; }; @@ -260,5 +265,28 @@ export const actions: Actions = { entryRepository.update(id, { dueDate: dueDate || null }); return { success: true }; + }, + + updateTags: async ({ request }) => { + const formData = await request.formData(); + const id = formData.get('id')?.toString(); + const tagsJson = formData.get('tags')?.toString() || '[]'; + + if (!id) { + return fail(400, { error: 'Entry ID is required' }); + } + + const existing = entryRepository.getById(id); + if (!existing) { + return fail(404, { error: 'Entry not found' }); + } + + try { + const tagNames = JSON.parse(tagsJson) as string[]; + tagRepository.updateEntryTags(id, tagNames); + return { success: true }; + } catch { + return fail(400, { error: 'Invalid tags format' }); + } } };