diff --git a/apps/manacore/apps/web/src/lib/modules/calendar/views/DetailView.svelte b/apps/manacore/apps/web/src/lib/modules/calendar/views/DetailView.svelte
index 5b434d539..27a208db2 100644
--- a/apps/manacore/apps/web/src/lib/modules/calendar/views/DetailView.svelte
+++ b/apps/manacore/apps/web/src/lib/modules/calendar/views/DetailView.svelte
@@ -6,9 +6,10 @@
import { liveQuery } from 'dexie';
import { db } from '$lib/data/database';
import { eventsStore } from '../stores/events.svelte';
- import { Trash, MapPin, Clock } from '@manacore/shared-icons';
+ import { Trash, MapPin, Clock, X } from '@manacore/shared-icons';
import type { ViewProps } from '$lib/components/workbench/nav-stack';
import type { LocalEvent } from '../types';
+ import { useAllTags, getTagsByIds } from '$lib/stores/tags.svelte';
let { navigate, goBack, params }: ViewProps = $props();
let eventId = $derived(params.eventId as string);
@@ -26,6 +27,18 @@
let focused = $state(false);
+ const tagsQuery = useAllTags();
+ let allTags = $derived(tagsQuery.value ?? []);
+ let eventTags = $derived(getTagsByIds(allTags, event?.tagIds ?? []));
+
+ async function removeTag(tagId: string) {
+ const current = event?.tagIds ?? [];
+ await eventsStore.updateTagIds(
+ eventId,
+ current.filter((id) => id !== tagId)
+ );
+ }
+
$effect(() => {
eventId; // track
confirmDelete = false;
@@ -145,6 +158,26 @@
{/if}
+
+ {#if eventTags.length > 0}
+
+
Tags
+
+ {#each eventTags as tag (tag.id)}
+
+ {/each}
+
+
+ {/if}
+
Beschreibung
@@ -298,6 +331,42 @@
flex-direction: column;
gap: 0.375rem;
}
+ .tags-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.375rem;
+ }
+ .tag-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ padding: 0.125rem 0.5rem;
+ border-radius: 9999px;
+ border: none;
+ background: color-mix(in srgb, var(--tag-color) 12%, transparent);
+ font-size: 0.6875rem;
+ color: #6b7280;
+ cursor: pointer;
+ transition: all 0.15s;
+ }
+ .tag-pill:hover {
+ background: color-mix(in srgb, var(--tag-color) 20%, transparent);
+ color: #ef4444;
+ }
+ :global(.dark) .tag-pill {
+ background: color-mix(in srgb, var(--tag-color) 18%, transparent);
+ color: #9ca3af;
+ }
+ :global(.dark) .tag-pill:hover {
+ background: color-mix(in srgb, var(--tag-color) 28%, transparent);
+ color: #ef4444;
+ }
+ .tag-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 9999px;
+ flex-shrink: 0;
+ }
.section-label {
font-size: 0.6875rem;
font-weight: 600;
diff --git a/apps/manacore/apps/web/src/lib/modules/contacts/views/DetailView.svelte b/apps/manacore/apps/web/src/lib/modules/contacts/views/DetailView.svelte
index 24a135f6f..fcb09da32 100644
--- a/apps/manacore/apps/web/src/lib/modules/contacts/views/DetailView.svelte
+++ b/apps/manacore/apps/web/src/lib/modules/contacts/views/DetailView.svelte
@@ -14,9 +14,11 @@
MapPin,
Briefcase,
Globe,
+ X,
} from '@manacore/shared-icons';
import type { ViewProps } from '$lib/components/workbench/nav-stack';
import type { LocalContact } from '../types';
+ import { useAllTags, getTagsByIds } from '$lib/stores/tags.svelte';
let { navigate, goBack, params }: ViewProps = $props();
let contactId = $derived(params.contactId as string);
@@ -40,6 +42,18 @@
let editWebsite = $state('');
let editNotes = $state('');
+ const tagsQuery = useAllTags();
+ let allTags = $derived(tagsQuery.value ?? []);
+ let contactTags = $derived(getTagsByIds(allTags, contact?.tagIds ?? []));
+
+ async function removeTag(tagId: string) {
+ const current = contact?.tagIds ?? [];
+ await contactsStore.updateTagIds(
+ contactId,
+ current.filter((id) => id !== tagId)
+ );
+ }
+
$effect(() => {
contactId; // track
confirmDelete = false;
@@ -255,6 +269,26 @@
+
+ {#if contactTags.length > 0}
+
+
Tags
+
+ {#each contactTags as tag (tag.id)}
+
+ {/each}
+
+
+ {/if}
+
Notizen
@@ -447,6 +481,42 @@
flex-direction: column;
gap: 0.375rem;
}
+ .tags-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.375rem;
+ }
+ .tag-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ padding: 0.125rem 0.5rem;
+ border-radius: 9999px;
+ border: none;
+ background: color-mix(in srgb, var(--tag-color) 12%, transparent);
+ font-size: 0.6875rem;
+ color: #6b7280;
+ cursor: pointer;
+ transition: all 0.15s;
+ }
+ .tag-pill:hover {
+ background: color-mix(in srgb, var(--tag-color) 20%, transparent);
+ color: #ef4444;
+ }
+ :global(.dark) .tag-pill {
+ background: color-mix(in srgb, var(--tag-color) 18%, transparent);
+ color: #9ca3af;
+ }
+ :global(.dark) .tag-pill:hover {
+ background: color-mix(in srgb, var(--tag-color) 28%, transparent);
+ color: #ef4444;
+ }
+ .tag-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 9999px;
+ flex-shrink: 0;
+ }
.section-label {
font-size: 0.6875rem;
font-weight: 600;
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/views/DetailView.svelte b/apps/manacore/apps/web/src/lib/modules/todo/views/DetailView.svelte
index 949d95b1d..56c2685fe 100644
--- a/apps/manacore/apps/web/src/lib/modules/todo/views/DetailView.svelte
+++ b/apps/manacore/apps/web/src/lib/modules/todo/views/DetailView.svelte
@@ -6,9 +6,10 @@
import { liveQuery } from 'dexie';
import { db } from '$lib/data/database';
import { tasksStore } from '../stores/tasks.svelte';
- import { Check, Trash } from '@manacore/shared-icons';
+ import { Check, Trash, X } from '@manacore/shared-icons';
import type { ViewProps } from '$lib/components/workbench/nav-stack';
import type { LocalTask, TaskPriority } from '../types';
+ import { useAllTags, getTagsByIds } from '$lib/stores/tags.svelte';
let { navigate, goBack, params }: ViewProps = $props();
let taskId = $derived(params.taskId as string);
@@ -25,6 +26,23 @@
// Track whether user is actively editing to prevent overwrite from liveQuery
let focused = $state(false);
+ const tagsQuery = useAllTags();
+ let allTags = $derived(tagsQuery.value ?? []);
+
+ function getTaskTagIds(): string[] {
+ return ((task?.metadata as Record)?.labelIds as string[]) ?? [];
+ }
+
+ let taskTags = $derived(getTagsByIds(allTags, getTaskTagIds()));
+
+ async function removeTag(tagId: string) {
+ const current = getTaskTagIds();
+ await tasksStore.updateLabels(
+ taskId,
+ current.filter((id) => id !== tagId)
+ );
+ }
+
$effect(() => {
taskId; // track
confirmDelete = false;
@@ -152,6 +170,26 @@
{/if}
+
+ {#if taskTags.length > 0}
+
+
Tags
+
+ {#each taskTags as tag (tag.id)}
+
+ {/each}
+
+
+ {/if}
+
Beschreibung
@@ -349,6 +387,42 @@
flex-direction: column;
gap: 0.375rem;
}
+ .tags-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.375rem;
+ }
+ .tag-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ padding: 0.125rem 0.5rem;
+ border-radius: 9999px;
+ border: none;
+ background: color-mix(in srgb, var(--tag-color) 12%, transparent);
+ font-size: 0.6875rem;
+ color: #6b7280;
+ cursor: pointer;
+ transition: all 0.15s;
+ }
+ .tag-pill:hover {
+ background: color-mix(in srgb, var(--tag-color) 20%, transparent);
+ color: #ef4444;
+ }
+ :global(.dark) .tag-pill {
+ background: color-mix(in srgb, var(--tag-color) 18%, transparent);
+ color: #9ca3af;
+ }
+ :global(.dark) .tag-pill:hover {
+ background: color-mix(in srgb, var(--tag-color) 28%, transparent);
+ color: #ef4444;
+ }
+ .tag-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 9999px;
+ flex-shrink: 0;
+ }
.section-label {
font-size: 0.6875rem;
font-weight: 600;