feat(manacore/web): wire TagField, FavoriteButton, ColorPicker into module UIs

Add shared TagField component (ID-based wrapper for TagSelector).
Wire TagField into: calendar EventForm, times EntryForm, cards
CreateDeckModal, contacts detail page. Wire FavoriteButton into
contacts list (replaces inline Star toggle). Add ColorPicker to
cards CreateDeckModal for deck color selection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-02 17:20:46 +02:00
parent 39af8f8480
commit 7ba82472b2
81 changed files with 10403 additions and 600 deletions

View file

@ -29,6 +29,7 @@ export {
TagColorPicker,
TagEditModal,
TagSelector,
TagField,
TagList,
TAG_COLORS,
DEFAULT_TAG_COLOR,

View file

@ -21,6 +21,7 @@ export {
TagColorPicker,
TagEditModal,
TagSelector,
TagField,
TagList,
TAG_COLORS,
DEFAULT_TAG_COLOR,

View file

@ -0,0 +1,55 @@
<script lang="ts">
import TagSelector from './TagSelector.svelte';
import type { Tag } from './constants';
/**
* Form field wrapper for TagSelector.
* Works with tag IDs (string[]) — the common pattern across all modules.
* Pass all available tags and the currently selected IDs.
*/
interface Props {
/** All available tags */
tags: Array<{ id: string; name: string; color?: string | null }>;
/** Currently selected tag IDs */
selectedIds: string[];
/** Called when selection changes */
onChange: (ids: string[]) => void;
/** Max number of tags (optional) */
maxTags?: number;
/** Label for the add button */
addLabel?: string;
/** Placeholder text */
placeholder?: string;
}
let {
tags,
selectedIds,
onChange,
maxTags,
addLabel = 'Tag hinzufügen',
placeholder = 'Tag suchen...',
}: Props = $props();
const tagObjects: Tag[] = $derived(
tags.map((t) => ({ id: t.id, name: t.name, color: t.color ?? undefined }))
);
const selectedTags: Tag[] = $derived(
selectedIds.map((id) => tagObjects.find((t) => t.id === id)).filter((t): t is Tag => t != null)
);
function handleChange(newTags: Tag[]) {
onChange(newTags.map((t) => t.id));
}
</script>
<TagSelector
tags={tagObjects}
{selectedTags}
onTagsChange={handleChange}
addTagLabel={addLabel}
searchPlaceholder={placeholder}
{maxTags}
/>

View file

@ -4,6 +4,7 @@ export { default as TagChip } from './TagChip.svelte';
export { default as TagColorPicker } from './TagColorPicker.svelte';
export { default as TagEditModal } from './TagEditModal.svelte';
export { default as TagSelector } from './TagSelector.svelte';
export { default as TagField } from './TagField.svelte';
export { default as TagList } from './TagList.svelte';
// Constants and Types