diff --git a/apps/mana/apps/web/src/lib/app-registry/apps.ts b/apps/mana/apps/web/src/lib/app-registry/apps.ts index b2ff7d44b..60762806f 100644 --- a/apps/mana/apps/web/src/lib/app-registry/apps.ts +++ b/apps/mana/apps/web/src/lib/app-registry/apps.ts @@ -71,6 +71,8 @@ import { Scroll, Spiral, Crown, + ShootingStar, + CloudSun, } from '@mana/shared-icons'; // ── Apps with entity capabilities ─────────────────────────── @@ -1169,6 +1171,45 @@ registerApp({ }, }); +registerApp({ + id: 'wishes', + name: 'Wünsche', + color: '#F59E0B', + icon: ShootingStar, + views: { + list: { load: () => import('$lib/modules/wishes/ListView.svelte') }, + detail: { load: () => import('$lib/modules/wishes/views/DetailView.svelte') }, + }, + contextMenuActions: [ + { + id: 'new-wish', + label: 'Neuer Wunsch', + icon: Plus, + action: () => + window.dispatchEvent( + new CustomEvent('mana:quick-action', { detail: { app: 'wishes', action: 'new' } }) + ), + }, + ], + collection: 'wishesItems', + paramKey: 'wishId', + dragType: 'wish', + getDisplayData: (item) => ({ + title: (item.title as string) || 'Wunsch', + subtitle: item.targetPrice + ? `${(item.targetPrice as number).toLocaleString('de-DE')} €` + : undefined, + }), + createItem: async (data) => { + const { wishesStore } = await import('$lib/modules/wishes/stores/wishes.svelte'); + const wish = await wishesStore.create({ + title: data.title as string, + description: data.description as string | undefined, + }); + return wish.id; + }, +}); + registerApp({ id: 'help', name: 'Hilfe', @@ -1179,6 +1220,16 @@ registerApp({ }, }); +registerApp({ + id: 'wetter', + name: 'Wetter', + color: '#38bdf8', + icon: CloudSun, + views: { + list: { load: () => import('$lib/modules/wetter/ListView.svelte') }, + }, +}); + registerApp({ id: 'feedback', name: 'Feedback', diff --git a/apps/mana/apps/web/src/lib/app-registry/categories.ts b/apps/mana/apps/web/src/lib/app-registry/categories.ts index f1db37043..1ea0ee07f 100644 --- a/apps/mana/apps/web/src/lib/app-registry/categories.ts +++ b/apps/mana/apps/web/src/lib/app-registry/categories.ts @@ -76,6 +76,7 @@ export const APP_CATEGORY_MAP: Record = { places: 'life', citycorners: 'life', news: 'life', + wetter: 'life', inventory: 'life', storage: 'life', who: 'life', diff --git a/apps/mana/apps/web/src/lib/modules/wetter/ListView.svelte b/apps/mana/apps/web/src/lib/modules/wetter/ListView.svelte new file mode 100644 index 000000000..e24ae893f --- /dev/null +++ b/apps/mana/apps/web/src/lib/modules/wetter/ListView.svelte @@ -0,0 +1,289 @@ + + + +{#if weatherStore.loading && !weatherStore.weatherData} +
+ 🌤 + Laden... +
+{:else if weatherStore.weatherData} + {@const data = weatherStore.weatherData} + {@const c = data.current} + + +
+
+ {getWeatherIcon(c.weatherCode, c.isDay)} + {Math.round(c.temperature)}° +
+ {getWeatherLabel(c.weatherCode)} + {data.location.name} +
+
+
+ Gefuehlt {Math.round(c.feelsLike)}° + 💨 {Math.round(c.windSpeed)} km/h {windDirectionLabel(c.windDirection)} + 💧 {c.humidity}% +
+
+ + + {#if data.alerts.length > 0} +
+ {#each data.alerts.slice(0, 2) as alert (alert.id)} +
+ ⚠ {alert.event} +
+ {/each} +
+ {/if} + + + {#if data.hourly.length > 0} +
+ {#each data.hourly.slice(0, 8) as hour (hour.time)} + {@const time = new Date(hour.time).toLocaleTimeString('de-DE', { hour: '2-digit' })} +
+ {time} + {getWeatherIcon(hour.weatherCode, hour.isDay)} + {Math.round(hour.temperature)}° +
+ {/each} +
+ {/if} + + + {#if data.daily.length > 0} +
+ {#each data.daily.slice(0, 5) as day, idx (day.date)} + {@const label = + idx === 0 + ? 'Heute' + : new Date(day.date).toLocaleDateString('de-DE', { weekday: 'short' })} +
+ {label} + {getWeatherIcon(day.weatherCode)} + {Math.round(day.temperatureMin)}° / {Math.round(day.temperatureMax)}° +
+ {/each} +
+ {/if} + + + {#if weatherStore.nowcast} +
+ {weatherStore.nowcast.summary} +
+ {/if} +{:else if weatherStore.error} +
{weatherStore.error}
+{/if} + +