From 650dea5e1dd44d68826cdb7d8d92c8e420681cc8 Mon Sep 17 00:00:00 2001 From: Till JS Date: Thu, 2 Apr 2026 22:57:09 +0200 Subject: [PATCH] feat(manacore/web): add overlay detail views for 8 more modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add inline-editable DetailViews with auto-save for: planta, inventar, skilltree, memoro, questions, uload, mukke, citycorners Wire AppView list items to open overlay via navigate() with sibling navigation support. Fix citycorners table names (cityLocations→ccLocations). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../lib/components/workbench/app-registry.ts | 32 ++ .../lib/modules/citycorners/AppView.svelte | 19 +- .../citycorners/views/DetailView.svelte | 404 ++++++++++++++ .../src/lib/modules/inventar/AppView.svelte | 15 +- .../modules/inventar/views/DetailView.svelte | 351 ++++++++++++ .../web/src/lib/modules/memoro/AppView.svelte | 15 +- .../modules/memoro/views/DetailView.svelte | 400 ++++++++++++++ .../web/src/lib/modules/mukke/AppView.svelte | 15 +- .../lib/modules/mukke/views/DetailView.svelte | 365 +++++++++++++ .../web/src/lib/modules/planta/AppView.svelte | 15 +- .../modules/planta/views/DetailView.svelte | 406 ++++++++++++++ .../src/lib/modules/questions/AppView.svelte | 15 +- .../modules/questions/views/DetailView.svelte | 398 ++++++++++++++ .../src/lib/modules/skilltree/AppView.svelte | 15 +- .../modules/skilltree/views/DetailView.svelte | 508 ++++++++++++++++++ .../web/src/lib/modules/uload/AppView.svelte | 15 +- .../lib/modules/uload/views/DetailView.svelte | 397 ++++++++++++++ 17 files changed, 3361 insertions(+), 24 deletions(-) create mode 100644 apps/manacore/apps/web/src/lib/modules/citycorners/views/DetailView.svelte create mode 100644 apps/manacore/apps/web/src/lib/modules/inventar/views/DetailView.svelte create mode 100644 apps/manacore/apps/web/src/lib/modules/memoro/views/DetailView.svelte create mode 100644 apps/manacore/apps/web/src/lib/modules/mukke/views/DetailView.svelte create mode 100644 apps/manacore/apps/web/src/lib/modules/planta/views/DetailView.svelte create mode 100644 apps/manacore/apps/web/src/lib/modules/questions/views/DetailView.svelte create mode 100644 apps/manacore/apps/web/src/lib/modules/skilltree/views/DetailView.svelte create mode 100644 apps/manacore/apps/web/src/lib/modules/uload/views/DetailView.svelte diff --git a/apps/manacore/apps/web/src/lib/components/workbench/app-registry.ts b/apps/manacore/apps/web/src/lib/components/workbench/app-registry.ts index 97e328fe7..c2faeb3c3 100644 --- a/apps/manacore/apps/web/src/lib/components/workbench/app-registry.ts +++ b/apps/manacore/apps/web/src/lib/components/workbench/app-registry.ts @@ -87,6 +87,10 @@ export const APP_REGISTRY: AppEntry[] = [ name: 'Mukke', color: '#F97316', load: () => import('$lib/modules/mukke/AppView.svelte'), + views: { + list: { load: () => import('$lib/modules/mukke/AppView.svelte') }, + detail: { load: () => import('$lib/modules/mukke/views/DetailView.svelte') }, + }, }, { id: 'photos', @@ -111,6 +115,10 @@ export const APP_REGISTRY: AppEntry[] = [ name: 'Planta', color: '#16A34A', load: () => import('$lib/modules/planta/AppView.svelte'), + views: { + list: { load: () => import('$lib/modules/planta/AppView.svelte') }, + detail: { load: () => import('$lib/modules/planta/views/DetailView.svelte') }, + }, }, { id: 'presi', @@ -123,24 +131,40 @@ export const APP_REGISTRY: AppEntry[] = [ name: 'Inventar', color: '#78716C', load: () => import('$lib/modules/inventar/AppView.svelte'), + views: { + list: { load: () => import('$lib/modules/inventar/AppView.svelte') }, + detail: { load: () => import('$lib/modules/inventar/views/DetailView.svelte') }, + }, }, { id: 'memoro', name: 'Memoro', color: '#F59E0B', load: () => import('$lib/modules/memoro/AppView.svelte'), + views: { + list: { load: () => import('$lib/modules/memoro/AppView.svelte') }, + detail: { load: () => import('$lib/modules/memoro/views/DetailView.svelte') }, + }, }, { id: 'questions', name: 'Questions', color: '#2563EB', load: () => import('$lib/modules/questions/AppView.svelte'), + views: { + list: { load: () => import('$lib/modules/questions/AppView.svelte') }, + detail: { load: () => import('$lib/modules/questions/views/DetailView.svelte') }, + }, }, { id: 'skilltree', name: 'SkillTree', color: '#D946EF', load: () => import('$lib/modules/skilltree/AppView.svelte'), + views: { + list: { load: () => import('$lib/modules/skilltree/AppView.svelte') }, + detail: { load: () => import('$lib/modules/skilltree/views/DetailView.svelte') }, + }, }, { id: 'moodlit', @@ -153,12 +177,20 @@ export const APP_REGISTRY: AppEntry[] = [ name: 'CityCorners', color: '#14B8A6', load: () => import('$lib/modules/citycorners/AppView.svelte'), + views: { + list: { load: () => import('$lib/modules/citycorners/AppView.svelte') }, + detail: { load: () => import('$lib/modules/citycorners/views/DetailView.svelte') }, + }, }, { id: 'uload', name: 'uLoad', color: '#0EA5E9', load: () => import('$lib/modules/uload/AppView.svelte'), + views: { + list: { load: () => import('$lib/modules/uload/AppView.svelte') }, + detail: { load: () => import('$lib/modules/uload/views/DetailView.svelte') }, + }, }, { id: 'calc', diff --git a/apps/manacore/apps/web/src/lib/modules/citycorners/AppView.svelte b/apps/manacore/apps/web/src/lib/modules/citycorners/AppView.svelte index 39c741d99..ac2c34140 100644 --- a/apps/manacore/apps/web/src/lib/modules/citycorners/AppView.svelte +++ b/apps/manacore/apps/web/src/lib/modules/citycorners/AppView.svelte @@ -7,6 +7,9 @@ import { db } from '$lib/data/database'; import type { LocalLocation, LocalFavorite } from './types'; import { CATEGORY_COLORS } from './types'; + import type { ViewProps } from '$lib/components/workbench/nav-stack'; + + let { navigate, goBack, params }: ViewProps = $props(); let locations = $state([]); let favorites = $state([]); @@ -14,7 +17,7 @@ $effect(() => { const sub = liveQuery(async () => { return db - .table('cityLocations') + .table('ccLocations') .toArray() .then((all) => all.filter((l) => !l.deletedAt)); }).subscribe((val) => { @@ -26,7 +29,7 @@ $effect(() => { const sub = liveQuery(async () => { return db - .table('cityFavorites') + .table('ccFavorites') .toArray() .then((all) => all.filter((f) => !f.deletedAt)); }).subscribe((val) => { @@ -60,7 +63,15 @@
{#each locations as location (location.id)} -
+
+ {/each} {#if locations.length === 0} diff --git a/apps/manacore/apps/web/src/lib/modules/citycorners/views/DetailView.svelte b/apps/manacore/apps/web/src/lib/modules/citycorners/views/DetailView.svelte new file mode 100644 index 000000000..47da85fd7 --- /dev/null +++ b/apps/manacore/apps/web/src/lib/modules/citycorners/views/DetailView.svelte @@ -0,0 +1,404 @@ + + + +
+ {#if !location} +

Ort nicht gefunden

+ {:else} + +
+ (focused = true)} + onblur={saveField} + placeholder="Name..." + /> + +
+ + +
+
+ +
+ + +
+
+ Adresse + (focused = true)} + onblur={saveField} + placeholder="Adresse..." + /> +
+
+ + +
+ + +
+ + +
+ Erstellt: {new Date(location.createdAt ?? '').toLocaleDateString('de')} + {#if location.updatedAt} + Bearbeitet: {new Date(location.updatedAt).toLocaleDateString('de')} + {/if} +
+ + +
+ {#if confirmDelete} +

Ort wirklich löschen?

+
+ + +
+ {:else} + + {/if} +
+ {/if} +
+ + diff --git a/apps/manacore/apps/web/src/lib/modules/inventar/AppView.svelte b/apps/manacore/apps/web/src/lib/modules/inventar/AppView.svelte index 39bf5321e..8ed18d650 100644 --- a/apps/manacore/apps/web/src/lib/modules/inventar/AppView.svelte +++ b/apps/manacore/apps/web/src/lib/modules/inventar/AppView.svelte @@ -5,8 +5,11 @@ + +
+ {#if !collection} +

Sammlung nicht gefunden

+ {:else} + +
+ {#if collection.icon} + {collection.icon} + {/if} + (focused = true)} + onblur={saveField} + placeholder="Name..." + /> +
+ + +
+
+ Icon + (focused = true)} + onblur={saveField} + placeholder="z.B. 📦" + /> +
+ +
+ Farbe + (focused = true)} + onblur={saveField} + placeholder="z.B. #78716C" + /> +
+ +
+ Gegenstaende + {itemCount} +
+
+ + +
+ + +
+ + +
+ Erstellt: {new Date(collection.createdAt ?? '').toLocaleDateString('de')} + {#if collection.updatedAt} + Bearbeitet: {new Date(collection.updatedAt).toLocaleDateString('de')} + {/if} +
+ + +
+ {#if confirmDelete} +

Sammlung wirklich loeschen?

+
+ + +
+ {:else} + + {/if} +
+ {/if} +
+ + diff --git a/apps/manacore/apps/web/src/lib/modules/memoro/AppView.svelte b/apps/manacore/apps/web/src/lib/modules/memoro/AppView.svelte index a8a30d091..e9f6873f6 100644 --- a/apps/manacore/apps/web/src/lib/modules/memoro/AppView.svelte +++ b/apps/manacore/apps/web/src/lib/modules/memoro/AppView.svelte @@ -5,8 +5,11 @@ + +
+ {#if !memo} +

Memo nicht gefunden

+ {:else} + +
+ (focused = true)} + onblur={saveField} + placeholder="Titel..." + /> + +
+ + +
+
+ Status + + {statusLabels[memo.processingStatus]} + +
+ +
+ Dauer + {formatDuration(memo.audioDurationMs)} +
+ +
+ Sprache + (focused = true)} + onblur={saveField} + placeholder="z.B. de" + /> +
+
+ + +
+ + +
+ + + {#if memo.transcript} +
+ +
{memo.transcript}
+
+ {/if} + + +
+ Erstellt: {new Date(memo.createdAt ?? '').toLocaleDateString('de')} + {#if memo.updatedAt} + Bearbeitet: {new Date(memo.updatedAt).toLocaleDateString('de')} + {/if} +
+ + +
+ {#if confirmDelete} +

Memo wirklich loeschen?

+
+ + +
+ {:else} + + {/if} +
+ {/if} +
+ + diff --git a/apps/manacore/apps/web/src/lib/modules/mukke/AppView.svelte b/apps/manacore/apps/web/src/lib/modules/mukke/AppView.svelte index fd64b790f..7a13c5609 100644 --- a/apps/manacore/apps/web/src/lib/modules/mukke/AppView.svelte +++ b/apps/manacore/apps/web/src/lib/modules/mukke/AppView.svelte @@ -6,6 +6,9 @@ import { liveQuery } from 'dexie'; import { db } from '$lib/data/database'; import type { LocalSong, LocalPlaylist } from './types'; + import type { ViewProps } from '$lib/components/workbench/nav-stack'; + + let { navigate, goBack, params }: ViewProps = $props(); let songs = $state([]); let playlists = $state([]); @@ -61,8 +64,14 @@

Zuletzt gehört

{#each recentlyPlayed as song (song.id)} -
+ navigate('detail', { + songId: song.id, + _siblingIds: recentlyPlayed.map((s) => s.id), + _siblingKey: 'songId', + })} + class="flex w-full items-center gap-3 rounded-md px-2 py-1.5 transition-colors hover:bg-white/5 cursor-pointer text-left" >
{song.artist ?? 'Unbekannt'}

{formatDuration(song.duration)} -
+ {/each} {#if recentlyPlayed.length === 0} diff --git a/apps/manacore/apps/web/src/lib/modules/mukke/views/DetailView.svelte b/apps/manacore/apps/web/src/lib/modules/mukke/views/DetailView.svelte new file mode 100644 index 000000000..3a48bf730 --- /dev/null +++ b/apps/manacore/apps/web/src/lib/modules/mukke/views/DetailView.svelte @@ -0,0 +1,365 @@ + + + +
+ {#if !song} +

Song nicht gefunden

+ {:else} + +
+ (focused = true)} + onblur={saveField} + placeholder="Titel..." + /> + +
+ + +
+
+ Künstler + (focused = true)} + onblur={saveField} + placeholder="Unbekannt" + /> +
+ +
+ Album + (focused = true)} + onblur={saveField} + placeholder="--" + /> +
+ +
+ Genre + (focused = true)} + onblur={saveField} + placeholder="--" + /> +
+ +
+ Jahr + (focused = true)} + onblur={saveField} + placeholder="--" + /> +
+ +
+ BPM + (focused = true)} + onblur={saveField} + placeholder="--" + /> +
+ +
+ Dauer + {formatDuration(song.duration)} +
+ +
+ Wiedergaben + {song.playCount} +
+
+ + +
+ Erstellt: {new Date(song.createdAt ?? '').toLocaleDateString('de')} + {#if song.updatedAt} + Bearbeitet: {new Date(song.updatedAt).toLocaleDateString('de')} + {/if} + {#if song.lastPlayedAt} + Zuletzt gehört: {new Date(song.lastPlayedAt).toLocaleDateString('de')} + {/if} +
+ + +
+ {#if confirmDelete} +

Song wirklich löschen?

+
+ + +
+ {:else} + + {/if} +
+ {/if} +
+ + diff --git a/apps/manacore/apps/web/src/lib/modules/planta/AppView.svelte b/apps/manacore/apps/web/src/lib/modules/planta/AppView.svelte index b1db32674..e2c179a06 100644 --- a/apps/manacore/apps/web/src/lib/modules/planta/AppView.svelte +++ b/apps/manacore/apps/web/src/lib/modules/planta/AppView.svelte @@ -5,8 +5,11 @@ + +
+ {#if !plant} +

Pflanze nicht gefunden

+ {:else} + + (focused = true)} + onblur={saveField} + placeholder="Name..." + /> + + +
+
+ Wissenschaftlicher Name + (focused = true)} + onblur={saveField} + placeholder="—" + /> +
+ +
+ Art + (focused = true)} + onblur={saveField} + placeholder="—" + /> +
+ +
+ Zustand + +
+ +
+ Licht + +
+ +
+ Giessen (Tage) + (focused = true)} + onblur={saveField} + placeholder="—" + min="1" + /> +
+ +
+ Erworben + (focused = true)} + onblur={saveField} + /> +
+
+ + +
+ + +
+ + +
+ Erstellt: {new Date(plant.createdAt ?? '').toLocaleDateString('de')} + {#if plant.updatedAt} + Bearbeitet: {new Date(plant.updatedAt).toLocaleDateString('de')} + {/if} +
+ + +
+ {#if confirmDelete} +

Pflanze wirklich loeschen?

+
+ + +
+ {:else} + + {/if} +
+ {/if} +
+ + diff --git a/apps/manacore/apps/web/src/lib/modules/questions/AppView.svelte b/apps/manacore/apps/web/src/lib/modules/questions/AppView.svelte index ad87ff28f..203c682b3 100644 --- a/apps/manacore/apps/web/src/lib/modules/questions/AppView.svelte +++ b/apps/manacore/apps/web/src/lib/modules/questions/AppView.svelte @@ -6,6 +6,9 @@ import { liveQuery } from 'dexie'; import { db } from '$lib/data/database'; import type { LocalQuestion, LocalCollection } from './types'; + import type { ViewProps } from '$lib/components/workbench/nav-stack'; + + let { navigate, goBack, params }: ViewProps = $props(); let questions = $state([]); let collections = $state([]); @@ -63,8 +66,14 @@
{#each sorted as question (question.id)} -
+ navigate('detail', { + questionId: question.id, + _siblingIds: sorted.map((q) => q.id), + _siblingKey: 'questionId', + })} + class="mb-2 w-full text-left rounded-md border border-white/10 px-3 py-2.5 transition-colors hover:bg-white/5 cursor-pointer" >

{question.title}

@@ -84,7 +93,7 @@ {/each}
{/if} -
+ {/each} {#if sorted.length === 0} diff --git a/apps/manacore/apps/web/src/lib/modules/questions/views/DetailView.svelte b/apps/manacore/apps/web/src/lib/modules/questions/views/DetailView.svelte new file mode 100644 index 000000000..9d26501c2 --- /dev/null +++ b/apps/manacore/apps/web/src/lib/modules/questions/views/DetailView.svelte @@ -0,0 +1,398 @@ + + + +
+ {#if !question} +

Frage nicht gefunden

+ {:else} + + (focused = true)} + onblur={saveField} + placeholder="Titel..." + /> + + +
+
+ Status + +
+ +
+ Priorität + +
+ +
+ Recherchetiefe + +
+
+ + +
+ + +
+ + + {#if question.tags.length > 0} +
+ +
+ {#each question.tags as tag} + {tag} + {/each} +
+
+ {/if} + + +
+ Erstellt: {new Date(question.createdAt ?? '').toLocaleDateString('de')} + {#if question.updatedAt} + Bearbeitet: {new Date(question.updatedAt).toLocaleDateString('de')} + {/if} +
+ + +
+ {#if confirmDelete} +

Frage wirklich löschen?

+
+ + +
+ {:else} + + {/if} +
+ {/if} +
+ + diff --git a/apps/manacore/apps/web/src/lib/modules/skilltree/AppView.svelte b/apps/manacore/apps/web/src/lib/modules/skilltree/AppView.svelte index 282cb9326..1d92bed63 100644 --- a/apps/manacore/apps/web/src/lib/modules/skilltree/AppView.svelte +++ b/apps/manacore/apps/web/src/lib/modules/skilltree/AppView.svelte @@ -5,9 +5,12 @@ + +
+ {#if !skill} +

Skill nicht gefunden

+ {:else} + +
+ {skill.icon} + (focused = true)} + onblur={saveField} + placeholder="Name..." + /> +
+ + +
+
+ Level {skill.level} — {LEVEL_NAMES[skill.level] ?? 'Unbekannt'} + {skill.currentXp} / {xpForNextLevel(skill.level) === Infinity + ? '∞' + : xpForNextLevel(skill.level)} XP +
+
+
+
+ {skill.totalXp} XP gesamt +
+ + {#if levelUpMessage} +
{levelUpMessage}
+ {/if} + + +
+ +
+ + + +
+
+ + +
+
+ Branch + +
+ +
+ Icon + (focused = true)} + onblur={saveField} + placeholder="z.B. ⭐" + /> +
+ +
+ Farbe + (focused = true)} + onblur={saveField} + placeholder="z.B. #D946EF" + /> +
+
+ + +
+ + +
+ + +
+ Erstellt: {new Date(skill.createdAt ?? '').toLocaleDateString('de')} + {#if skill.updatedAt} + Bearbeitet: {new Date(skill.updatedAt).toLocaleDateString('de')} + {/if} +
+ + +
+ {#if confirmDelete} +

Skill wirklich loeschen?

+
+ + +
+ {:else} + + {/if} +
+ {/if} +
+ + diff --git a/apps/manacore/apps/web/src/lib/modules/uload/AppView.svelte b/apps/manacore/apps/web/src/lib/modules/uload/AppView.svelte index d94c3b6af..9f8bd1f01 100644 --- a/apps/manacore/apps/web/src/lib/modules/uload/AppView.svelte +++ b/apps/manacore/apps/web/src/lib/modules/uload/AppView.svelte @@ -6,6 +6,9 @@ import { liveQuery } from 'dexie'; import { db } from '$lib/data/database'; import type { LocalLink, LocalFolder } from './types'; + import type { ViewProps } from '$lib/components/workbench/nav-stack'; + + let { navigate, goBack, params }: ViewProps = $props(); let links = $state([]); let folders = $state([]); @@ -58,7 +61,15 @@
{#each sorted as link (link.id)} -
+ {/each} {#if sorted.length === 0} diff --git a/apps/manacore/apps/web/src/lib/modules/uload/views/DetailView.svelte b/apps/manacore/apps/web/src/lib/modules/uload/views/DetailView.svelte new file mode 100644 index 000000000..523840828 --- /dev/null +++ b/apps/manacore/apps/web/src/lib/modules/uload/views/DetailView.svelte @@ -0,0 +1,397 @@ + + + +
+ {#if !link} +

Link nicht gefunden

+ {:else} + + (focused = true)} + onblur={saveField} + placeholder="Titel..." + /> + + +
+
+ URL + (focused = true)} + onblur={saveField} + placeholder="https://..." + /> +
+ +
+ Kurzcode + (focused = true)} + onblur={saveField} + placeholder="custom-code" + /> +
+ + {#if link.shortCode} +
+ Short Code + {link.shortCode} +
+ {/if} + +
+ Aktiv + +
+ +
+ Klicks + {link.clickCount} +
+ +
+ Ablaufdatum + (focused = true)} + onblur={saveField} + /> +
+
+ + +
+ + +
+ + +
+ Erstellt: {new Date(link.createdAt ?? '').toLocaleDateString('de')} + {#if link.updatedAt} + Bearbeitet: {new Date(link.updatedAt).toLocaleDateString('de')} + {/if} +
+ + +
+ {#if confirmDelete} +

Link wirklich löschen?

+
+ + +
+ {:else} + + {/if} +
+ {/if} +
+ +