From bd67e8d20b10775bc8130db41f6314a81e37a6de Mon Sep 17 00:00:00 2001 From: Till JS Date: Wed, 1 Apr 2026 21:30:40 +0200 Subject: [PATCH] feat(manacore, shared-ui): integrate cross-type DnD into unified app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Shared TagStrip: add dragSource on tag pills + passiveDropZone for item→tag drops. New onTagDrop and dropAccepts props. DnD CSS for hover/success states. - Unified app layout: add DragPreview, context-based tagDropHandler so child pages can register their own drop logic. - Todo module: add updateLabels() to tasks store (with metadata merge). - Todo page: add dropTarget on task items, tag badge display via getTaskTags(), register tagDropHandler for passive task→tag drops. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../lib/modules/todo/stores/tasks.svelte.ts | 9 ++ .../apps/web/src/routes/(app)/+layout.svelte | 21 ++++- .../web/src/routes/(app)/todo/+page.svelte | 88 +++++++++++++++++++ .../shared-ui/src/navigation/TagStrip.svelte | 58 ++++++++++++ 4 files changed, 174 insertions(+), 2 deletions(-) diff --git a/apps/manacore/apps/web/src/lib/modules/todo/stores/tasks.svelte.ts b/apps/manacore/apps/web/src/lib/modules/todo/stores/tasks.svelte.ts index 9c3b36f5b..e0101c528 100644 --- a/apps/manacore/apps/web/src/lib/modules/todo/stores/tasks.svelte.ts +++ b/apps/manacore/apps/web/src/lib/modules/todo/stores/tasks.svelte.ts @@ -110,6 +110,15 @@ export const tasksStore = { }); }, + async updateLabels(id: string, labelIds: string[]) { + const existing = await taskTable.get(id); + const existingMeta = (existing?.metadata as Record) ?? {}; + await taskTable.update(id, { + metadata: { ...existingMeta, labelIds }, + updatedAt: new Date().toISOString(), + }); + }, + async reorderTasks(taskIds: string[]) { for (let i = 0; i < taskIds.length; i++) { await taskTable.update(taskIds[i], { diff --git a/apps/manacore/apps/web/src/routes/(app)/+layout.svelte b/apps/manacore/apps/web/src/routes/(app)/+layout.svelte index dbca971b0..9d1570137 100644 --- a/apps/manacore/apps/web/src/routes/(app)/+layout.svelte +++ b/apps/manacore/apps/web/src/routes/(app)/+layout.svelte @@ -2,11 +2,11 @@ import { goto } from '$app/navigation'; import { page } from '$app/stores'; import type { Snippet } from 'svelte'; - import { onMount } from 'svelte'; + import { onMount, setContext } from 'svelte'; import KeyboardShortcutsModal from '$lib/components/KeyboardShortcutsModal.svelte'; import SessionWarning from '$lib/components/SessionWarning.svelte'; import { locale } from 'svelte-i18n'; - import { PillNavigation, TagStrip } from '@manacore/shared-ui'; + import { PillNavigation, TagStrip, DragPreview, ActionZone } from '@manacore/shared-ui'; import type { PillNavItem, PillDropdownItem, SpotlightAction } from '@manacore/shared-ui'; import { tagLocalStore, tagMutations, useAllTags } from '$lib/stores/tags.svelte'; import { linkLocalStore, linkMutations } from '@manacore/shared-links'; @@ -110,6 +110,19 @@ isTagStripVisible = !isTagStripVisible; } + // DnD: tag drop handler — set by child pages via context + import type { DragPayload } from '@manacore/shared-ui/dnd'; + + let tagDropHandler = $state<((tagId: string, payload: DragPayload) => void) | null>(null); + setContext('tagDropHandler', { + set(handler: (tagId: string, payload: DragPayload) => void) { + tagDropHandler = handler; + }, + clear() { + tagDropHandler = null; + }, + }); + // Navigation items for ManaCore const baseNavItems: PillNavItem[] = [ { href: '/home', label: 'Home', icon: 'home' }, @@ -353,11 +366,15 @@ selectedIds={[]} onToggle={() => {}} onClear={() => {}} + onTagDrop={tagDropHandler ?? undefined} managementHref="/tags" loading={allTags.loading} /> {/if} + + +
diff --git a/apps/manacore/apps/web/src/routes/(app)/todo/+page.svelte b/apps/manacore/apps/web/src/routes/(app)/todo/+page.svelte index dd2f28453..341b1680a 100644 --- a/apps/manacore/apps/web/src/routes/(app)/todo/+page.svelte +++ b/apps/manacore/apps/web/src/routes/(app)/todo/+page.svelte @@ -1,6 +1,10 @@