diff --git a/apps/manacore/apps/web/src/lib/data/database.ts b/apps/manacore/apps/web/src/lib/data/database.ts index e005e7a42..19d48a8fe 100644 --- a/apps/manacore/apps/web/src/lib/data/database.ts +++ b/apps/manacore/apps/web/src/lib/data/database.ts @@ -26,8 +26,7 @@ db.version(1).stores({ tasks: 'id, dueDate, isCompleted, priority, order, projectId, [isCompleted+order], [projectId+order]', todoProjects: 'id, order, isArchived, isDefault', - labels: 'id', - taskLabels: 'id, taskId, labelId', + taskLabels: 'id, taskId, labelId', // junction to globalTags (labelId = tagId) reminders: 'id, taskId', boardViews: 'id, order, groupBy', @@ -47,8 +46,7 @@ db.version(1).stores({ images: 'id, isFavorite, isPublic, archivedAt, prompt', boards: 'id, isPublic', boardItems: 'id, boardId, itemType, zIndex, [boardId+zIndex]', - pictureTags: 'id, name', - imageTags: 'id, imageId, tagId, [imageId+tagId]', + imageTags: 'id, imageId, tagId, [imageId+tagId]', // junction to globalTags // ─── Cards (appId: 'cards') ─── cardDecks: 'id, isPublic', @@ -68,8 +66,7 @@ db.version(1).stores({ // ─── Storage (appId: 'storage') ─── files: 'id, parentFolderId, mimeType, isFavorite, isDeleted, name', storageFolders: 'id, parentFolderId, path, depth, isFavorite, isDeleted', - storageTags: 'id, name', - fileTags: 'id, fileId, tagId, [fileId+tagId]', + fileTags: 'id, fileId, tagId, [fileId+tagId]', // junction to globalTags // ─── Presi (appId: 'presi') ─── presiDecks: 'id, isPublic', @@ -85,8 +82,7 @@ db.version(1).stores({ albums: 'id, isAutoGenerated, name', albumItems: 'id, albumId, mediaId, sortOrder, [albumId+sortOrder]', photoFavorites: 'id, mediaId', - photoTags: 'id, name', - photoMediaTags: 'id, mediaId, tagId, [mediaId+tagId]', + photoMediaTags: 'id, mediaId, tagId, [mediaId+tagId]', // junction to globalTags // ─── SkillTree (appId: 'skilltree') ─── skills: 'id, branch, parentId, level', @@ -103,7 +99,6 @@ db.version(1).stores({ timeProjects: 'id, clientId, isArchived, isBillable, guildId, visibility, order', timeEntries: 'id, projectId, clientId, date, isRunning, [date+projectId], [date+clientId], guildId, visibility', - timeTags: 'id, name, order', timeTemplates: 'id, usageCount, lastUsedAt, projectId', timeSettings: 'id', timeAlarms: 'id, enabled, time', @@ -132,7 +127,6 @@ db.version(1).stores({ // ─── uLoad (appId: 'uload') ─── links: 'id, shortCode, isActive, folderId, order, clickCount, [folderId+order], [isActive+order]', - uloadTags: 'id, slug, name', uloadFolders: 'id, order', linkTags: 'id, linkId, tagId, [linkId+tagId]', @@ -147,8 +141,7 @@ db.version(1).stores({ // ─── Memoro (appId: 'memoro') ─── memos: 'id, processingStatus, isArchived, isPinned, language, [isArchived+createdAt]', memories: 'id, memoId', - memoroTags: 'id, name, sortOrder', - memoTags: 'id, memoId, tagId', + memoTags: 'id, memoId, tagId', // junction to globalTags memoroSpaces: 'id, ownerId', spaceMembers: 'id, spaceId, userId', memoSpaces: 'id, memoId, spaceId', @@ -177,25 +170,24 @@ db.version(1).stores({ export const SYNC_APP_MAP: Record = { manacore: ['userSettings', 'dashboardConfigs'], - todo: ['tasks', 'todoProjects', 'labels', 'taskLabels', 'reminders', 'boardViews'], + todo: ['tasks', 'todoProjects', 'taskLabels', 'reminders', 'boardViews'], calendar: ['calendars', 'events'], contacts: ['contacts'], chat: ['conversations', 'messages', 'chatTemplates'], - picture: ['images', 'boards', 'boardItems', 'pictureTags', 'imageTags'], + picture: ['images', 'boards', 'boardItems', 'imageTags'], cards: ['cardDecks', 'cards'], zitare: ['zitareFavorites', 'zitareLists'], mukke: ['songs', 'mukkePlaylists', 'playlistSongs', 'mukkeProjects', 'markers'], - storage: ['files', 'storageFolders', 'storageTags', 'fileTags'], + storage: ['files', 'storageFolders', 'fileTags'], presi: ['presiDecks', 'slides'], inventar: ['invCollections', 'invItems', 'invLocations', 'invCategories'], - photos: ['albums', 'albumItems', 'photoFavorites', 'photoTags', 'photoMediaTags'], + photos: ['albums', 'albumItems', 'photoFavorites', 'photoMediaTags'], skilltree: ['skills', 'activities', 'achievements'], citycorners: ['cities', 'ccLocations', 'ccFavorites'], times: [ 'timeClients', 'timeProjects', 'timeEntries', - 'timeTags', 'timeTemplates', 'timeSettings', 'timeAlarms', @@ -206,18 +198,10 @@ export const SYNC_APP_MAP: Record = { questions: ['qCollections', 'questions', 'answers'], nutriphi: ['meals', 'goals', 'nutriFavorites'], planta: ['plants', 'plantPhotos', 'wateringSchedules', 'wateringLogs'], - uload: ['links', 'uloadTags', 'uloadFolders', 'linkTags'], + uload: ['links', 'uloadFolders', 'linkTags'], calc: ['calculations', 'savedFormulas'], moodlit: ['moods', 'sequences'], - memoro: [ - 'memos', - 'memories', - 'memoroTags', - 'memoTags', - 'memoroSpaces', - 'spaceMembers', - 'memoSpaces', - ], + memoro: ['memos', 'memories', 'memoTags', 'memoroSpaces', 'spaceMembers', 'memoSpaces'], guides: ['guides', 'sections', 'steps', 'guideCollections', 'runs'], tags: ['globalTags', 'tagGroups'], links: ['manaLinks'], @@ -241,7 +225,6 @@ export const TABLE_TO_SYNC_NAME: Record = { // chat chatTemplates: 'templates', // picture - pictureTags: 'tags', // cards cardDecks: 'decks', // zitare @@ -252,7 +235,6 @@ export const TABLE_TO_SYNC_NAME: Record = { mukkeProjects: 'projects', // storage storageFolders: 'folders', - storageTags: 'tags', // presi presiDecks: 'decks', // inventar @@ -262,7 +244,6 @@ export const TABLE_TO_SYNC_NAME: Record = { invCategories: 'categories', // photos photoFavorites: 'favorites', - photoTags: 'tags', photoMediaTags: 'photoTags', // citycorners ccLocations: 'locations', @@ -270,7 +251,6 @@ export const TABLE_TO_SYNC_NAME: Record = { // times timeClients: 'clients', timeProjects: 'projects', - timeTags: 'tags', timeTemplates: 'templates', timeSettings: 'settings', timeAlarms: 'alarms', @@ -283,10 +263,8 @@ export const TABLE_TO_SYNC_NAME: Record = { // nutriphi nutriFavorites: 'favorites', // memoro - memoroTags: 'tags', memoroSpaces: 'spaces', // uload - uloadTags: 'tags', uloadFolders: 'folders', // guides guideCollections: 'collections', diff --git a/apps/manacore/apps/web/src/lib/modules/inventar/queries.ts b/apps/manacore/apps/web/src/lib/modules/inventar/queries.ts index a19df6be4..3f307f257 100644 --- a/apps/manacore/apps/web/src/lib/modules/inventar/queries.ts +++ b/apps/manacore/apps/web/src/lib/modules/inventar/queries.ts @@ -75,7 +75,7 @@ export interface Category { export type ViewMode = 'list' | 'grid' | 'table'; export interface SortOption { - field: 'name' | 'createdAt' | 'updatedAt' | 'status' | 'quantity'; + field: string; direction: 'asc' | 'desc'; } diff --git a/apps/manacore/apps/web/src/lib/modules/memoro/collections.ts b/apps/manacore/apps/web/src/lib/modules/memoro/collections.ts index 3cc50241c..4c63422f1 100644 --- a/apps/manacore/apps/web/src/lib/modules/memoro/collections.ts +++ b/apps/manacore/apps/web/src/lib/modules/memoro/collections.ts @@ -8,7 +8,6 @@ import { db } from '$lib/data/database'; import type { LocalMemo, LocalMemory, - LocalTag, LocalMemoTag, LocalSpace, LocalSpaceMember, @@ -19,7 +18,6 @@ import type { export const memoTable = db.table('memos'); export const memoryTable = db.table('memories'); -export const memoroTagTable = db.table('memoroTags'); export const memoTagTable = db.table('memoTags'); export const memoroSpaceTable = db.table('memoroSpaces'); export const spaceMemberTable = db.table('spaceMembers'); @@ -55,29 +53,7 @@ export const MEMORO_GUEST_SEED = { 'Memoro bietet Sprachaufnahme, automatische Transkription, KI-gestützte Zusammenfassungen und Tagging.', }, ], - memoroTags: [ - { - id: 'tag-ideen', - name: 'Ideen', - color: '#3b82f6', - isPinned: true, - sortOrder: 0, - }, - { - id: 'tag-notizen', - name: 'Notizen', - color: '#10b981', - isPinned: false, - sortOrder: 1, - }, - ], - memoTags: [ - { - id: 'mt-demo-1', - memoId: DEMO_MEMO_ID, - tagId: 'tag-notizen', - }, - ], + memoTags: [] as Record[], memoroSpaces: [] as Record[], spaceMembers: [] as Record[], memoSpaces: [] as Record[], diff --git a/apps/manacore/apps/web/src/lib/modules/memoro/index.ts b/apps/manacore/apps/web/src/lib/modules/memoro/index.ts index 4dd6b218a..845b8b3ca 100644 --- a/apps/manacore/apps/web/src/lib/modules/memoro/index.ts +++ b/apps/manacore/apps/web/src/lib/modules/memoro/index.ts @@ -3,18 +3,23 @@ */ export { memosStore } from './stores/memos.svelte'; -export { tagsStore } from './stores/tags.svelte'; +export { + tagMutations, + useAllTags, + getTagById, + getTagsByIds, + getTagColor, + memoTagOps, +} from './stores/tags.svelte'; export { memoriesStore } from './stores/memories.svelte'; export { useAllMemos, useArchivedMemos, useMemoriesByMemo, - useAllTags, useAllMemoTags, useAllSpaces, toMemo, toMemory, - toTag, toSpace, sortMemos, filterBySearch, @@ -26,7 +31,6 @@ export { export { memoTable, memoryTable, - memoroTagTable, memoTagTable, memoroSpaceTable, spaceMemberTable, @@ -36,7 +40,6 @@ export { export type { LocalMemo, LocalMemory, - LocalTag, LocalMemoTag, LocalSpace, LocalSpaceMember, diff --git a/apps/manacore/apps/web/src/lib/modules/memoro/queries.ts b/apps/manacore/apps/web/src/lib/modules/memoro/queries.ts index 459343f98..152b7f426 100644 --- a/apps/manacore/apps/web/src/lib/modules/memoro/queries.ts +++ b/apps/manacore/apps/web/src/lib/modules/memoro/queries.ts @@ -7,12 +7,10 @@ import { db } from '$lib/data/database'; import type { LocalMemo, LocalMemory, - LocalTag, LocalMemoTag, LocalSpace, Memo, Memory, - Tag, Space, } from './types'; @@ -46,18 +44,6 @@ export function toMemory(local: LocalMemory): Memory { }; } -export function toTag(local: LocalTag): Tag { - return { - id: local.id, - name: local.name, - color: local.color, - isPinned: local.isPinned ?? false, - sortOrder: local.sortOrder ?? 0, - createdAt: local.createdAt ?? new Date().toISOString(), - updatedAt: local.updatedAt ?? new Date().toISOString(), - }; -} - export function toSpace(local: LocalSpace): Space { return { id: local.id, @@ -98,16 +84,8 @@ export function useMemoriesByMemo(memoId: string) { }); } -/** All tags, sorted by sortOrder. */ -export function useAllTags() { - return liveQuery(async () => { - const locals = await db.table('memoroTags').toArray(); - return locals - .filter((t) => !t.deletedAt) - .map(toTag) - .sort((a, b) => a.sortOrder - b.sortOrder); - }); -} +// Tags: use shared global tags from @manacore/shared-stores +export { useAllTags } from '@manacore/shared-stores'; /** All memo-tag associations. */ export function useAllMemoTags() { diff --git a/apps/manacore/apps/web/src/lib/modules/memoro/stores/tags.svelte.ts b/apps/manacore/apps/web/src/lib/modules/memoro/stores/tags.svelte.ts index 263e92207..8bf722698 100644 --- a/apps/manacore/apps/web/src/lib/modules/memoro/stores/tags.svelte.ts +++ b/apps/manacore/apps/web/src/lib/modules/memoro/stores/tags.svelte.ts @@ -1,71 +1,19 @@ /** - * Tags Store — Mutations Only - * - * Reads come from liveQuery hooks in queries.ts. - * Handles tag CRUD and memo-tag associations. + * Memoro Tags — Uses shared global tags + module-specific junction table. */ -import { memoroTagTable, memoTagTable } from '../collections'; -import { toTag } from '../queries'; -import type { LocalTag, LocalMemoTag } from '../types'; +import { db } from '$lib/data/database'; +import { createTagLinkOps } from '@manacore/shared-stores'; -export const tagsStore = { - /** Create a new tag. */ - async create(data: { name: string; color?: string }) { - const all = await memoroTagTable.toArray(); - const active = all.filter((t) => !t.deletedAt); - const newLocal: LocalTag = { - id: crypto.randomUUID(), - name: data.name, - color: data.color ?? null, - isPinned: false, - sortOrder: active.length, - }; - await memoroTagTable.add(newLocal); - return toTag(newLocal); - }, +export { + tagMutations, + useAllTags, + getTagById, + getTagsByIds, + getTagColor, +} from '@manacore/shared-stores'; - /** Update a tag. */ - async update(id: string, data: Partial>) { - await memoroTagTable.update(id, { - ...data, - updatedAt: new Date().toISOString(), - }); - }, - - /** Soft-delete a tag and its associations. */ - async delete(id: string) { - const now = new Date().toISOString(); - await memoroTagTable.update(id, { deletedAt: now, updatedAt: now }); - // Soft-delete associations - const allMT = await memoTagTable.where('tagId').equals(id).toArray(); - for (const mt of allMT) { - await memoTagTable.update(mt.id, { deletedAt: now, updatedAt: now }); - } - }, - - /** Add a tag to a memo. */ - async addToMemo(memoId: string, tagId: string) { - // Check if association already exists - const existing = await memoTagTable.toArray(); - if (existing.some((mt) => mt.memoId === memoId && mt.tagId === tagId && !mt.deletedAt)) { - return; - } - const newMT: LocalMemoTag = { - id: crypto.randomUUID(), - memoId, - tagId, - }; - await memoTagTable.add(newMT); - }, - - /** Remove a tag from a memo. */ - async removeFromMemo(memoId: string, tagId: string) { - const all = await memoTagTable.toArray(); - const toRemove = all.find((mt) => mt.memoId === memoId && mt.tagId === tagId && !mt.deletedAt); - if (toRemove) { - const now = new Date().toISOString(); - await memoTagTable.update(toRemove.id, { deletedAt: now, updatedAt: now }); - } - }, -}; +export const memoTagOps = createTagLinkOps({ + table: () => db.table('memoTags'), + entityIdField: 'memoId', +}); diff --git a/apps/manacore/apps/web/src/lib/modules/memoro/types.ts b/apps/manacore/apps/web/src/lib/modules/memoro/types.ts index f99e33d48..623ce11c3 100644 --- a/apps/manacore/apps/web/src/lib/modules/memoro/types.ts +++ b/apps/manacore/apps/web/src/lib/modules/memoro/types.ts @@ -51,14 +51,6 @@ export interface LocalMemory extends BaseRecord { metadata?: Record; } -export interface LocalTag extends BaseRecord { - name: string; - color: string | null; - userId?: string; - isPinned?: boolean; - sortOrder?: number; -} - export interface LocalMemoTag extends BaseRecord { memoId: string; tagId: string; diff --git a/apps/manacore/apps/web/src/lib/modules/photos/collections.ts b/apps/manacore/apps/web/src/lib/modules/photos/collections.ts index 6bdc605b4..77a6517c6 100644 --- a/apps/manacore/apps/web/src/lib/modules/photos/collections.ts +++ b/apps/manacore/apps/web/src/lib/modules/photos/collections.ts @@ -5,14 +5,13 @@ */ import { db } from '$lib/data/database'; -import type { LocalAlbum, LocalAlbumItem, LocalFavorite, LocalTag, LocalPhotoTag } from './types'; +import type { LocalAlbum, LocalAlbumItem, LocalFavorite, LocalPhotoTag } from './types'; // ─── Collection Accessors ────────────────────────────────── export const albumTable = db.table('albums'); export const albumItemTable = db.table('albumItems'); export const photoFavoriteTable = db.table('photoFavorites'); -export const photoTagTable = db.table('photoTags'); export const photoMediaTagTable = db.table('photoMediaTags'); // ─── Guest Seed ──────────────────────────────────────────── @@ -26,21 +25,4 @@ export const PHOTOS_GUEST_SEED = { isAutoGenerated: false, }, ], - photoTags: [ - { - id: 'tag-nature', - name: 'Natur', - color: '#22c55e', - }, - { - id: 'tag-people', - name: 'Menschen', - color: '#3b82f6', - }, - { - id: 'tag-travel', - name: 'Reisen', - color: '#f59e0b', - }, - ], }; diff --git a/apps/manacore/apps/web/src/lib/modules/photos/index.ts b/apps/manacore/apps/web/src/lib/modules/photos/index.ts index c236912ab..fb62cb84f 100644 --- a/apps/manacore/apps/web/src/lib/modules/photos/index.ts +++ b/apps/manacore/apps/web/src/lib/modules/photos/index.ts @@ -5,7 +5,7 @@ export { photoStore } from './stores/photos.svelte'; export { albumMutations } from './stores/albums.svelte'; export { - useAllPhotoTags, + useAllTags, getTagById, getTagsByIds, tagMutations, @@ -28,7 +28,6 @@ export { albumTable, albumItemTable, photoFavoriteTable, - photoTagTable, photoMediaTagTable, PHOTOS_GUEST_SEED, } from './collections'; @@ -36,7 +35,6 @@ export type { LocalAlbum, LocalAlbumItem, LocalFavorite, - LocalTag, LocalPhotoTag, Photo, PhotoFilters, diff --git a/apps/manacore/apps/web/src/lib/modules/photos/stores/tags.svelte.ts b/apps/manacore/apps/web/src/lib/modules/photos/stores/tags.svelte.ts index 5655a6879..a87961d90 100644 --- a/apps/manacore/apps/web/src/lib/modules/photos/stores/tags.svelte.ts +++ b/apps/manacore/apps/web/src/lib/modules/photos/stores/tags.svelte.ts @@ -1,146 +1,19 @@ /** - * Photo Tag Store — Local-First via Dexie - * - * Tag CRUD and photo-tag junction table operations. + * Photo Tags — Uses shared global tags + module-specific junction table. */ -import { liveQuery } from 'dexie'; import { db } from '$lib/data/database'; -import type { LocalTag, LocalPhotoTag } from '../types'; +import { createTagLinkOps } from '@manacore/shared-stores'; -// ─── Tag CRUD ───────────────────────────────────────────── +export { + tagMutations, + useAllTags, + getTagById, + getTagsByIds, + getTagColor, +} from '@manacore/shared-stores'; -export function useAllPhotoTags() { - return liveQuery(async () => { - const all = await db.table('photoTags').toArray(); - return all.filter((t) => !t.deletedAt); - }); -} - -export function getTagById(tags: LocalTag[], id: string): LocalTag | undefined { - return tags.find((t) => t.id === id); -} - -export function getTagsByIds(tags: LocalTag[], ids: string[]): LocalTag[] { - const idSet = new Set(ids); - return tags.filter((t) => idSet.has(t.id)); -} - -export const tagMutations = { - async createTag(data: { name: string; color?: string }): Promise { - try { - const now = new Date().toISOString(); - const tag: LocalTag = { - id: crypto.randomUUID(), - name: data.name, - color: data.color ?? null, - createdAt: now, - updatedAt: now, - }; - await db.table('photoTags').add(tag); - return tag; - } catch (e) { - console.error('Failed to create tag:', e); - return null; - } - }, - - async deleteTag(id: string): Promise { - try { - const now = new Date().toISOString(); - await db.table('photoTags').update(id, { deletedAt: now, updatedAt: now }); - // Also soft-delete photo-tag associations - const associations = await db.table('photoMediaTags').toArray(); - for (const a of associations.filter((pt) => pt.tagId === id)) { - await db.table('photoMediaTags').update(a.id, { deletedAt: now, updatedAt: now }); - } - return true; - } catch (e) { - console.error('Failed to delete tag:', e); - return false; - } - }, -}; - -// ─── Photo-Tag Junction ─────────────────────────────────── - -export const photoTagOps = { - /** Get tags for a photo */ - async getPhotoTags(mediaId: string): Promise { - try { - const all = await db.table('photoMediaTags').toArray(); - return all.filter((pt) => pt.mediaId === mediaId && !pt.deletedAt).map((pt) => pt.tagId); - } catch (e) { - console.error('Failed to get photo tags:', e); - return []; - } - }, - - /** Add tag to photo */ - async addTagToPhoto(mediaId: string, tagId: string) { - try { - const all = await db.table('photoMediaTags').toArray(); - const exists = all.some( - (pt) => pt.mediaId === mediaId && pt.tagId === tagId && !pt.deletedAt - ); - if (exists) return true; - - const now = new Date().toISOString(); - await db.table('photoMediaTags').add({ - id: crypto.randomUUID(), - mediaId, - tagId, - createdAt: now, - updatedAt: now, - }); - return true; - } catch (e) { - console.error('Failed to add tag to photo:', e); - return false; - } - }, - - /** Remove tag from photo */ - async removeTagFromPhoto(mediaId: string, tagId: string) { - try { - const all = await db.table('photoMediaTags').toArray(); - const item = all.find((pt) => pt.mediaId === mediaId && pt.tagId === tagId && !pt.deletedAt); - if (item) { - const now = new Date().toISOString(); - await db.table('photoMediaTags').update(item.id, { deletedAt: now, updatedAt: now }); - } - return true; - } catch (e) { - console.error('Failed to remove tag from photo:', e); - return false; - } - }, - - /** Set all tags for a photo (replace) */ - async setPhotoTags(mediaId: string, tagIds: string[]) { - try { - const now = new Date().toISOString(); - // Soft-delete existing tags for this photo - const all = await db.table('photoMediaTags').toArray(); - const existing = all.filter((pt) => pt.mediaId === mediaId && !pt.deletedAt); - for (const item of existing) { - await db.table('photoMediaTags').update(item.id, { deletedAt: now, updatedAt: now }); - } - - // Add new tags - for (const tagId of tagIds) { - await db.table('photoMediaTags').add({ - id: crypto.randomUUID(), - mediaId, - tagId, - createdAt: now, - updatedAt: now, - }); - } - return true; - } catch (e) { - console.error('Failed to set photo tags:', e); - return false; - } - }, -}; +export const photoTagOps = createTagLinkOps({ + table: () => db.table('photoMediaTags'), + entityIdField: 'mediaId', +}); diff --git a/apps/manacore/apps/web/src/lib/modules/photos/types.ts b/apps/manacore/apps/web/src/lib/modules/photos/types.ts index daea2033e..d2fa5947d 100644 --- a/apps/manacore/apps/web/src/lib/modules/photos/types.ts +++ b/apps/manacore/apps/web/src/lib/modules/photos/types.ts @@ -23,11 +23,6 @@ export interface LocalFavorite extends BaseRecord { mediaId: string; } -export interface LocalTag extends BaseRecord { - name: string; - color?: string | null; -} - export interface LocalPhotoTag extends BaseRecord { mediaId: string; tagId: string; diff --git a/apps/manacore/apps/web/src/lib/modules/picture/collections.ts b/apps/manacore/apps/web/src/lib/modules/picture/collections.ts index 63071d282..0552884d4 100644 --- a/apps/manacore/apps/web/src/lib/modules/picture/collections.ts +++ b/apps/manacore/apps/web/src/lib/modules/picture/collections.ts @@ -5,20 +5,13 @@ */ import { db } from '$lib/data/database'; -import type { - LocalImage, - LocalBoard, - LocalBoardItem, - LocalPictureTag, - LocalImageTag, -} from './types'; +import type { LocalImage, LocalBoard, LocalBoardItem, LocalImageTag } from './types'; // ─── Collection Accessors ────────────────────────────────── export const imageTable = db.table('images'); export const boardTable = db.table('boards'); export const boardItemTable = db.table('boardItems'); -export const pictureTagTable = db.table('pictureTags'); export const imageTagTable = db.table('imageTags'); // ─── Guest Seed ──────────────────────────────────────────── @@ -75,9 +68,4 @@ export const PICTURE_GUEST_SEED = { properties: { fontFamily: 'Arial', fontWeight: 'normal', textAlign: 'center' }, }, ] satisfies LocalBoardItem[], - pictureTags: [ - { id: 'tag-landscape', name: 'Landschaft', color: '#22c55e' }, - { id: 'tag-portrait', name: 'Portrait', color: '#3b82f6' }, - { id: 'tag-abstract', name: 'Abstrakt', color: '#a855f7' }, - ] satisfies LocalPictureTag[], }; diff --git a/apps/manacore/apps/web/src/lib/modules/picture/index.ts b/apps/manacore/apps/web/src/lib/modules/picture/index.ts index c7500ef5b..a1c2b441c 100644 --- a/apps/manacore/apps/web/src/lib/modules/picture/index.ts +++ b/apps/manacore/apps/web/src/lib/modules/picture/index.ts @@ -24,7 +24,6 @@ export { imageTable, boardTable, boardItemTable, - pictureTagTable, imageTagTable, PICTURE_GUEST_SEED, } from './collections'; @@ -32,7 +31,6 @@ export type { LocalImage, LocalBoard, LocalBoardItem, - LocalPictureTag, LocalImageTag, ViewMode, Image, diff --git a/apps/manacore/apps/web/src/lib/modules/picture/queries.ts b/apps/manacore/apps/web/src/lib/modules/picture/queries.ts index 8c2dc3d8a..b3085fe09 100644 --- a/apps/manacore/apps/web/src/lib/modules/picture/queries.ts +++ b/apps/manacore/apps/web/src/lib/modules/picture/queries.ts @@ -13,7 +13,6 @@ import type { LocalImage, LocalBoard, LocalBoardItem, - LocalPictureTag, LocalImageTag, Image, Board, @@ -113,13 +112,8 @@ export function useAllBoards() { }, [] as BoardWithCount[]); } -/** All picture tags. */ -export function useAllPictureTags() { - return useLiveQueryWithDefault(async () => { - const locals = await db.table('pictureTags').toArray(); - return locals.filter((t) => !t.deletedAt); - }, [] as LocalPictureTag[]); -} +// Tags: use shared global tags from @manacore/shared-stores +export { useAllTags as useAllPictureTags } from '@manacore/shared-stores'; /** All image-tag associations. */ export function useAllImageTags() { diff --git a/apps/manacore/apps/web/src/lib/modules/picture/types.ts b/apps/manacore/apps/web/src/lib/modules/picture/types.ts index fb4ba801e..53cd7b8e8 100644 --- a/apps/manacore/apps/web/src/lib/modules/picture/types.ts +++ b/apps/manacore/apps/web/src/lib/modules/picture/types.ts @@ -55,11 +55,6 @@ export interface LocalBoardItem extends BaseRecord { properties: Record; } -export interface LocalPictureTag extends BaseRecord { - name: string; - color?: string | null; -} - export interface LocalImageTag extends BaseRecord { imageId: string; tagId: string; diff --git a/apps/manacore/apps/web/src/lib/modules/storage/collections.ts b/apps/manacore/apps/web/src/lib/modules/storage/collections.ts index 7aec05024..a2721cb81 100644 --- a/apps/manacore/apps/web/src/lib/modules/storage/collections.ts +++ b/apps/manacore/apps/web/src/lib/modules/storage/collections.ts @@ -5,13 +5,12 @@ */ import { db } from '$lib/data/database'; -import type { LocalFile, LocalFolder, LocalTag, LocalFileTag } from './types'; +import type { LocalFile, LocalFolder, LocalFileTag } from './types'; // ─── Collection Accessors ────────────────────────────────── export const fileTable = db.table('files'); export const storageFolderTable = db.table('storageFolders'); -export const storageTagTable = db.table('storageTags'); export const fileTagTable = db.table('fileTags'); // ─── Guest Seed ──────────────────────────────────────────── @@ -49,21 +48,4 @@ export const STORAGE_GUEST_SEED = { isDeleted: false, }, ], - storageTags: [ - { - id: 'tag-important', - name: 'Wichtig', - color: '#ef4444', - }, - { - id: 'tag-work', - name: 'Arbeit', - color: '#3b82f6', - }, - { - id: 'tag-personal', - name: 'Privat', - color: '#22c55e', - }, - ], }; diff --git a/apps/manacore/apps/web/src/lib/modules/storage/index.ts b/apps/manacore/apps/web/src/lib/modules/storage/index.ts index f05799703..5697dfe0c 100644 --- a/apps/manacore/apps/web/src/lib/modules/storage/index.ts +++ b/apps/manacore/apps/web/src/lib/modules/storage/index.ts @@ -3,7 +3,14 @@ */ export { filesStore } from './stores/files.svelte'; -export { storageTagStore } from './stores/tags.svelte'; +export { + tagMutations, + useAllTags, + getTagById, + getTagsByIds, + getTagColor, + fileTagOps, +} from './stores/tags.svelte'; export { useAllFiles, useAllFolders, @@ -22,11 +29,5 @@ export { formatFileSize, } from './queries'; export type { StorageFile, StorageFolder, StorageTag } from './queries'; -export { - fileTable, - storageFolderTable, - storageTagTable, - fileTagTable, - STORAGE_GUEST_SEED, -} from './collections'; -export type { LocalFile, LocalFolder, LocalTag, LocalFileTag } from './types'; +export { fileTable, storageFolderTable, fileTagTable, STORAGE_GUEST_SEED } from './collections'; +export type { LocalFile, LocalFolder, LocalFileTag } from './types'; diff --git a/apps/manacore/apps/web/src/lib/modules/storage/queries.ts b/apps/manacore/apps/web/src/lib/modules/storage/queries.ts index 279fad94b..a92d871f7 100644 --- a/apps/manacore/apps/web/src/lib/modules/storage/queries.ts +++ b/apps/manacore/apps/web/src/lib/modules/storage/queries.ts @@ -6,7 +6,7 @@ import { liveQuery } from 'dexie'; import { db } from '$lib/data/database'; -import type { LocalFile, LocalFolder, LocalTag, LocalFileTag } from './types'; +import type { LocalFile, LocalFolder, LocalFileTag } from './types'; // ─── Shared Types (inline to avoid @storage/shared dependency) ─── @@ -92,7 +92,12 @@ export function toFolder(local: LocalFolder): StorageFolder { }; } -export function toTag(local: LocalTag): StorageTag { +export function toTag(local: { + id: string; + name: string; + color?: string | null; + createdAt?: string; +}): StorageTag { return { id: local.id, userId: 'local', @@ -126,16 +131,8 @@ export function useAllFolders() { }); } -/** All tags, sorted by name. Auto-updates on any change. */ -export function useAllStorageTags() { - return liveQuery(async () => { - const locals = await db.table('storageTags').toArray(); - return locals - .filter((t) => !t.deletedAt) - .map(toTag) - .sort((a, b) => a.name.localeCompare(b.name)); - }); -} +// Tags: use shared global tags from @manacore/shared-stores +export { useAllTags as useAllStorageTags } from '@manacore/shared-stores'; // ─── Pure Helper Functions (for $derived) ───────────────── diff --git a/apps/manacore/apps/web/src/lib/modules/storage/stores/tags.svelte.ts b/apps/manacore/apps/web/src/lib/modules/storage/stores/tags.svelte.ts index 17a684183..4ccebad2b 100644 --- a/apps/manacore/apps/web/src/lib/modules/storage/stores/tags.svelte.ts +++ b/apps/manacore/apps/web/src/lib/modules/storage/stores/tags.svelte.ts @@ -1,56 +1,19 @@ /** - * Storage Tag Store — Mutations Only - * - * Reads come from liveQuery hooks in queries.ts. - * This store only handles writes to IndexedDB via the unified database. + * Storage Tags — Uses shared global tags + module-specific junction table. */ -import { storageTagTable, fileTagTable } from '../collections'; -import type { LocalTag, LocalFileTag } from '../types'; +import { db } from '$lib/data/database'; +import { createTagLinkOps } from '@manacore/shared-stores'; -export const storageTagStore = { - async create(name: string, color?: string) { - const newTag: LocalTag = { - id: crypto.randomUUID(), - name, - color: color ?? null, - }; - await storageTagTable.add(newTag); - return newTag; - }, +export { + tagMutations, + useAllTags, + getTagById, + getTagsByIds, + getTagColor, +} from '@manacore/shared-stores'; - async update(id: string, data: Partial>) { - await storageTagTable.update(id, { - ...data, - updatedAt: new Date().toISOString(), - }); - }, - - async delete(id: string) { - await storageTagTable.update(id, { - deletedAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }); - }, - - async tagFile(fileId: string, tagId: string) { - const existing = await fileTagTable.where('[fileId+tagId]').equals([fileId, tagId]).first(); - if (existing) return; - - const newFileTag: LocalFileTag = { - id: crypto.randomUUID(), - fileId, - tagId, - }; - await fileTagTable.add(newFileTag); - }, - - async untagFile(fileId: string, tagId: string) { - const existing = await fileTagTable.where('[fileId+tagId]').equals([fileId, tagId]).first(); - if (existing) { - await fileTagTable.update(existing.id, { - deletedAt: new Date().toISOString(), - }); - } - }, -}; +export const fileTagOps = createTagLinkOps({ + table: () => db.table('fileTags'), + entityIdField: 'fileId', +}); diff --git a/apps/manacore/apps/web/src/lib/modules/storage/types.ts b/apps/manacore/apps/web/src/lib/modules/storage/types.ts index 7d7f644a2..3e06a561c 100644 --- a/apps/manacore/apps/web/src/lib/modules/storage/types.ts +++ b/apps/manacore/apps/web/src/lib/modules/storage/types.ts @@ -30,11 +30,6 @@ export interface LocalFolder extends BaseRecord { isDeleted: boolean; } -export interface LocalTag extends BaseRecord { - name: string; - color?: string | null; -} - export interface LocalFileTag extends BaseRecord { fileId: string; tagId: string; diff --git a/apps/manacore/apps/web/src/lib/modules/times/collections.ts b/apps/manacore/apps/web/src/lib/modules/times/collections.ts index a1f36456d..9c3d8f0cc 100644 --- a/apps/manacore/apps/web/src/lib/modules/times/collections.ts +++ b/apps/manacore/apps/web/src/lib/modules/times/collections.ts @@ -10,7 +10,6 @@ import type { LocalClient, LocalProject, LocalTimeEntry, - LocalTag, LocalTemplate, LocalSettings, LocalAlarm, @@ -23,7 +22,6 @@ import type { export const clientTable = db.table('timeClients'); export const projectTable = db.table('timeProjects'); export const timeEntryTable = db.table('timeEntries'); -export const tagTable = db.table('timeTags'); export const templateTable = db.table('timeTemplates'); export const settingsTable = db.table('timeSettings'); @@ -181,12 +179,6 @@ export const TIMES_GUEST_SEED = { source: { app: 'manual' as const }, }, ], - timeTags: [ - { id: 'times-tag-design', name: 'design', color: '#f59e0b', order: 0 }, - { id: 'times-tag-dev', name: 'development', color: '#3b82f6', order: 1 }, - { id: 'times-tag-meeting', name: 'meeting', color: '#6b7280', order: 2 }, - { id: 'times-tag-review', name: 'review', color: '#22c55e', order: 3 }, - ], timeSettings: [ { id: 'times-default-settings', diff --git a/apps/manacore/apps/web/src/lib/modules/times/index.ts b/apps/manacore/apps/web/src/lib/modules/times/index.ts index 31f6c9608..d4621db45 100644 --- a/apps/manacore/apps/web/src/lib/modules/times/index.ts +++ b/apps/manacore/apps/web/src/lib/modules/times/index.ts @@ -25,7 +25,6 @@ export { toClient, toProject, toTimeEntry, - toTag, toTemplate, toSettings, formatDuration, @@ -67,7 +66,6 @@ export { clientTable, projectTable, timeEntryTable, - tagTable, templateTable, settingsTable, TIMES_GUEST_SEED, @@ -86,7 +84,6 @@ export type { LocalClient, LocalProject, LocalTimeEntry, - LocalTag, LocalTemplate, LocalSettings, BillingRate, diff --git a/apps/manacore/apps/web/src/lib/modules/times/queries.ts b/apps/manacore/apps/web/src/lib/modules/times/queries.ts index 359af6d1e..a89ac3e94 100644 --- a/apps/manacore/apps/web/src/lib/modules/times/queries.ts +++ b/apps/manacore/apps/web/src/lib/modules/times/queries.ts @@ -11,7 +11,6 @@ import type { LocalClient, LocalProject, LocalTimeEntry, - LocalTag, LocalTemplate, LocalSettings, LocalAlarm, @@ -88,17 +87,6 @@ export function toTimeEntry(local: LocalTimeEntry): TimeEntry { }; } -export function toTag(local: LocalTag): Tag { - return { - id: local.id, - name: local.name, - color: local.color, - order: local.order, - createdAt: local.createdAt ?? new Date().toISOString(), - updatedAt: local.updatedAt ?? new Date().toISOString(), - }; -} - export function toTemplate(local: LocalTemplate): EntryTemplate { return { id: local.id, @@ -200,12 +188,8 @@ export function useAllTimeEntries() { }); } -export function useAllTags() { - return liveQuery(async () => { - const locals = await db.table('timeTags').toArray(); - return locals.filter((t) => !t.deletedAt).map(toTag); - }); -} +// Tags: use shared global tags from @manacore/shared-stores +export { useAllTags } from '@manacore/shared-stores'; export function useAllTemplates() { return liveQuery(async () => { diff --git a/apps/manacore/apps/web/src/lib/modules/times/types.ts b/apps/manacore/apps/web/src/lib/modules/times/types.ts index 14c1315f6..e40953f9d 100644 --- a/apps/manacore/apps/web/src/lib/modules/times/types.ts +++ b/apps/manacore/apps/web/src/lib/modules/times/types.ts @@ -33,8 +33,8 @@ export interface ProjectBudget { } export interface SortOption { - field: SortField; - direction: SortDirection; + field: string; + direction: 'asc' | 'desc'; } export interface FilterCriteria { @@ -195,12 +195,6 @@ export interface LocalTimeEntry extends BaseRecord { source?: EntrySourceRef | null; } -export interface LocalTag extends BaseRecord { - name: string; - color: string; - order: number; -} - export interface LocalTemplate extends BaseRecord { name: string; projectId?: string | null; diff --git a/apps/manacore/apps/web/src/lib/modules/todo/collections.ts b/apps/manacore/apps/web/src/lib/modules/todo/collections.ts index 6d4237770..02f2353ec 100644 --- a/apps/manacore/apps/web/src/lib/modules/todo/collections.ts +++ b/apps/manacore/apps/web/src/lib/modules/todo/collections.ts @@ -7,8 +7,7 @@ import { db } from '$lib/data/database'; import type { LocalTask, - LocalLabel, - LocalTaskLabel, + LocalTaskTag, LocalReminder, LocalBoardView, LocalTodoProject, @@ -18,8 +17,7 @@ import type { export const taskTable = db.table('tasks'); export const todoProjectTable = db.table('todoProjects'); -export const labelTable = db.table('labels'); -export const taskLabelTable = db.table('taskLabels'); +export const taskTagTable = db.table('taskLabels'); // DB table still 'taskLabels' until schema migration export const reminderTable = db.table('reminders'); export const boardViewTable = db.table('boardViews'); @@ -32,19 +30,6 @@ const nextWeek = new Date(now); nextWeek.setDate(nextWeek.getDate() + 7); export const TODO_GUEST_SEED = { - labels: [ - { - id: 'label-important', - name: 'Wichtig', - color: '#ef4444', - }, - { - id: 'label-idea', - name: 'Idee', - color: '#f59e0b', - }, - ] satisfies LocalLabel[], - boardViews: [ { id: 'view-kanban', diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/form/TagSelector.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/form/TagSelector.svelte index 6b3e378eb..01ced9c21 100644 --- a/apps/manacore/apps/web/src/lib/modules/todo/components/form/TagSelector.svelte +++ b/apps/manacore/apps/web/src/lib/modules/todo/components/form/TagSelector.svelte @@ -1,7 +1,6 @@ @@ -123,17 +119,7 @@ style="background-color: {tag.color || '#888'}" > {tag.name} - {#if tag.isPinned} - - {/if}
-