From 06ebc6271dfcb08550a575d7ce8459b9ef28e820 Mon Sep 17 00:00:00 2001 From: Till JS Date: Fri, 3 Apr 2026 00:20:54 +0200 Subject: [PATCH] feat(manacore/web): add tag drag-and-drop to workbench pages - Mount DragPreview + draggable tag bar on workbench homepage - Add dropTarget on list items in todo, calendar, contacts ListViews - Show assigned tags as colored dots on list items - Tags can be dragged from the tag bar onto any item to assign them - Drop target highlights with module-colored outline on hover Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/lib/modules/calendar/ListView.svelte | 51 +++++++++++- .../src/lib/modules/contacts/ListView.svelte | 41 ++++++++++ .../web/src/lib/modules/todo/ListView.svelte | 52 +++++++++++- .../apps/web/src/routes/(app)/+page.svelte | 79 +++++++++++++++++++ 4 files changed, 219 insertions(+), 4 deletions(-) diff --git a/apps/manacore/apps/web/src/lib/modules/calendar/ListView.svelte b/apps/manacore/apps/web/src/lib/modules/calendar/ListView.svelte index d23fad335..e2ac83c2d 100644 --- a/apps/manacore/apps/web/src/lib/modules/calendar/ListView.svelte +++ b/apps/manacore/apps/web/src/lib/modules/calendar/ListView.svelte @@ -10,9 +10,21 @@ import { eventsStore } from './stores/events.svelte'; import { Plus } from '@manacore/shared-icons'; import type { ViewProps } from '$lib/components/workbench/nav-stack'; + import { dropTarget } from '@manacore/shared-ui/dnd'; + import type { TagDragData } from '@manacore/shared-ui/dnd'; + import { getTagsByIds } from '$lib/stores/tags.svelte'; let { navigate, goBack, params }: ViewProps = $props(); + function handleTagDrop(eventId: string, tagData: TagDragData) { + const event = events.find((e) => e.id === eventId); + if (!event) return; + const current = event.tagIds ?? []; + if (!current.includes(tagData.id)) { + eventsStore.updateTagIds(eventId, [...current, tagData.id]); + } + } + let events = $state([]); const now = new Date(); @@ -121,6 +133,7 @@ {#each todayEvents as event (event.id)} + {@const eventTags = getTagsByIds(event.tagIds ?? [])} @@ -282,10 +312,26 @@ :global(.dark) .task-title.completed { color: #6b7280; } + .task-meta { + display: flex; + align-items: center; + gap: 0.375rem; + margin: 0; + } .task-due { font-size: 0.6875rem; color: #9ca3af; - margin: 0; + } + .tag-dot { + width: 6px; + height: 6px; + border-radius: 9999px; + flex-shrink: 0; + } + :global(.task-item.mana-drop-target-hover) { + outline: 2px solid rgba(139, 92, 246, 0.4); + outline-offset: -2px; + background: rgba(139, 92, 246, 0.06) !important; } .empty { padding: 2rem 0; diff --git a/apps/manacore/apps/web/src/routes/(app)/+page.svelte b/apps/manacore/apps/web/src/routes/(app)/+page.svelte index db8f7f65b..87c85d1d9 100644 --- a/apps/manacore/apps/web/src/routes/(app)/+page.svelte +++ b/apps/manacore/apps/web/src/routes/(app)/+page.svelte @@ -4,6 +4,19 @@ import { PageCarousel, type CarouselPage } from '$lib/components/page-carousel'; import { getAppEntry } from '$lib/components/workbench/app-registry'; import { createAppSettingsStore } from '@manacore/shared-stores'; + import { DragPreview, dragSource } from '@manacore/shared-ui/dnd'; + import { useAllTags } from '$lib/stores/tags.svelte'; + import type { Tag } from '@manacore/shared-tags'; + + // ── Tags for drag & drop ─────────────────────────────── + const allTags$ = useAllTags(); + let allTags = $state([]); + $effect(() => { + const sub = allTags$.subscribe((val) => { + allTags = val ?? []; + }); + return () => sub.unsubscribe(); + }); // ── Persisted workbench state ─────────────────────────── const DEFAULT_WIDTH = 480; @@ -131,7 +144,26 @@ Home - ManaCore + +
+ {#if allTags.length > 0} +
+ {#each allTags as tag (tag.id)} + + {/each} +
+ {/if} +