mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:41:09 +02:00
feat: add QuickInputBar to 6 more apps (mukke, matrix, manadeck, planta, photos, presi)
- Mukke: search songs by title/artist/album via libraryStore - Matrix: search rooms/contacts, select navigates to chat - ManaDeck: search decks by title/description - Planta: search plants by name/species via plantsApi - Photos: search albums and tags - Presi: search presentation decks All with locale-aware syntax highlighting. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
49457c354a
commit
ff419f069a
6 changed files with 200 additions and 13 deletions
|
|
@ -7,8 +7,8 @@
|
||||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||||
import { theme } from '$lib/stores/theme';
|
import { theme } from '$lib/stores/theme';
|
||||||
import { isNavCollapsed as collapsedStore } from '$lib/stores/navigation';
|
import { isNavCollapsed as collapsedStore } from '$lib/stores/navigation';
|
||||||
import { PillNavigation } from '@manacore/shared-ui';
|
import { PillNavigation, QuickInputBar } from '@manacore/shared-ui';
|
||||||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
import type { PillNavItem, PillDropdownItem, QuickInputItem } from '@manacore/shared-ui';
|
||||||
import {
|
import {
|
||||||
THEME_DEFINITIONS,
|
THEME_DEFINITIONS,
|
||||||
DEFAULT_THEME_VARIANTS,
|
DEFAULT_THEME_VARIANTS,
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n';
|
import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n';
|
||||||
import { getPillAppItems } from '@manacore/shared-branding';
|
import { getPillAppItems } from '@manacore/shared-branding';
|
||||||
import { setLocale, supportedLocales } from '$lib/i18n';
|
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||||
|
import { deckStore } from '$lib/stores/deckStore.svelte';
|
||||||
import { manadeckOnboarding } from '$lib/stores/app-onboarding.svelte';
|
import { manadeckOnboarding } from '$lib/stores/app-onboarding.svelte';
|
||||||
import { MiniOnboardingModal } from '@manacore/shared-app-onboarding';
|
import { MiniOnboardingModal } from '@manacore/shared-app-onboarding';
|
||||||
|
|
||||||
|
|
@ -139,6 +140,23 @@
|
||||||
goto('/login');
|
goto('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuickInputBar handlers
|
||||||
|
async function handleInputSearch(query: string): Promise<QuickInputItem[]> {
|
||||||
|
const q = query.toLowerCase();
|
||||||
|
return deckStore.decks
|
||||||
|
.filter((d) => d.title.toLowerCase().includes(q) || d.description?.toLowerCase().includes(q))
|
||||||
|
.slice(0, 10)
|
||||||
|
.map((deck) => ({
|
||||||
|
id: deck.id,
|
||||||
|
title: deck.title,
|
||||||
|
subtitle: deck.description || undefined,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInputSelect(item: QuickInputItem) {
|
||||||
|
goto(`/decks/${item.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await authStore.initialize();
|
await authStore.initialize();
|
||||||
|
|
||||||
|
|
@ -209,6 +227,18 @@
|
||||||
allAppsHref="/apps"
|
allAppsHref="/apps"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Quick Input Bar -->
|
||||||
|
<QuickInputBar
|
||||||
|
onSearch={handleInputSearch}
|
||||||
|
onSelect={handleInputSelect}
|
||||||
|
placeholder="Deck suchen..."
|
||||||
|
emptyText="Keine Decks gefunden"
|
||||||
|
searchingText="Suche..."
|
||||||
|
locale={$locale || 'de'}
|
||||||
|
appIcon="search"
|
||||||
|
bottomOffset="70px"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Main content -->
|
<!-- Main content -->
|
||||||
<main class="pb-24">
|
<main class="pb-24">
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@
|
||||||
} from '@manacore/shared-theme';
|
} from '@manacore/shared-theme';
|
||||||
import type { ThemeVariant } from '@manacore/shared-theme';
|
import type { ThemeVariant } from '@manacore/shared-theme';
|
||||||
import { isNavCollapsed as collapsedStore } from '$lib/stores/navigation.svelte';
|
import { isNavCollapsed as collapsedStore } from '$lib/stores/navigation.svelte';
|
||||||
import { PillNavigation } from '@manacore/shared-ui';
|
import { PillNavigation, QuickInputBar } from '@manacore/shared-ui';
|
||||||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
import type { PillNavItem, PillDropdownItem, QuickInputItem } from '@manacore/shared-ui';
|
||||||
import { getPillAppItems } from '@manacore/shared-branding';
|
import { getPillAppItems } from '@manacore/shared-branding';
|
||||||
import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n';
|
import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n';
|
||||||
import { setLocale, supportedLocales } from '$lib/i18n';
|
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||||
|
|
@ -164,6 +164,22 @@
|
||||||
goto('/login');
|
goto('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuickInputBar handlers
|
||||||
|
async function handleInputSearch(query: string): Promise<QuickInputItem[]> {
|
||||||
|
const q = query.toLowerCase();
|
||||||
|
const rooms = matrixStore.rooms.filter((r) => r.name?.toLowerCase().includes(q));
|
||||||
|
return rooms.slice(0, 10).map((room) => ({
|
||||||
|
id: room.roomId,
|
||||||
|
title: room.name || room.roomId,
|
||||||
|
subtitle: room.isDirect ? 'Direktnachricht' : 'Gruppe',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInputSelect(item: QuickInputItem) {
|
||||||
|
matrixStore.selectRoom(item.id);
|
||||||
|
goto('/chat');
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
// Initialize collapsed state from localStorage
|
// Initialize collapsed state from localStorage
|
||||||
const savedCollapsed = localStorage.getItem('matrix-nav-collapsed');
|
const savedCollapsed = localStorage.getItem('matrix-nav-collapsed');
|
||||||
|
|
@ -332,6 +348,18 @@
|
||||||
allAppsHref="https://mana.how"
|
allAppsHref="https://mana.how"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Quick Input Bar -->
|
||||||
|
<QuickInputBar
|
||||||
|
onSearch={handleInputSearch}
|
||||||
|
onSelect={handleInputSelect}
|
||||||
|
placeholder="Raum oder Kontakt suchen..."
|
||||||
|
emptyText="Keine Räume gefunden"
|
||||||
|
searchingText="Suche..."
|
||||||
|
locale={$locale || 'de'}
|
||||||
|
appIcon="search"
|
||||||
|
bottomOffset="70px"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<main class="main-content bg-background">
|
<main class="main-content bg-background">
|
||||||
{@render children()}
|
{@render children()}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { PillNavigation, DevBuildBadge } from '@manacore/shared-ui';
|
import { PillNavigation, QuickInputBar, DevBuildBadge } from '@manacore/shared-ui';
|
||||||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
import type { PillNavItem, PillDropdownItem, QuickInputItem } from '@manacore/shared-ui';
|
||||||
import {
|
import {
|
||||||
SplitPaneContainer,
|
SplitPaneContainer,
|
||||||
setSplitPanelContext,
|
setSplitPanelContext,
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
import type { ThemeVariant } from '@manacore/shared-theme';
|
import type { ThemeVariant } from '@manacore/shared-theme';
|
||||||
import { theme } from '$lib/stores/theme.svelte';
|
import { theme } from '$lib/stores/theme.svelte';
|
||||||
import { authStore } from '$lib/stores/auth.svelte';
|
import { authStore } from '$lib/stores/auth.svelte';
|
||||||
|
import { libraryStore } from '$lib/stores/library.svelte';
|
||||||
import MiniPlayer from '$lib/components/MiniPlayer.svelte';
|
import MiniPlayer from '$lib/components/MiniPlayer.svelte';
|
||||||
import FullPlayer from '$lib/components/FullPlayer.svelte';
|
import FullPlayer from '$lib/components/FullPlayer.svelte';
|
||||||
import QueuePanel from '$lib/components/QueuePanel.svelte';
|
import QueuePanel from '$lib/components/QueuePanel.svelte';
|
||||||
|
|
@ -102,6 +103,21 @@
|
||||||
goto('/login');
|
goto('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuickInputBar handlers
|
||||||
|
async function handleInputSearch(query: string): Promise<QuickInputItem[]> {
|
||||||
|
const songs = await libraryStore.searchSongs(query);
|
||||||
|
return songs.slice(0, 10).map((song) => ({
|
||||||
|
id: song.id,
|
||||||
|
title: song.title || 'Untitled',
|
||||||
|
subtitle: [song.artist, song.album].filter(Boolean).join(' — '),
|
||||||
|
isFavorite: song.favorite,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInputSelect(item: QuickInputItem) {
|
||||||
|
goto(`/library?song=${item.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await authStore.initialize();
|
await authStore.initialize();
|
||||||
if (!authStore.isAuthenticated) {
|
if (!authStore.isAuthenticated) {
|
||||||
|
|
@ -155,6 +171,18 @@
|
||||||
ariaLabel="Main navigation"
|
ariaLabel="Main navigation"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Quick Input Bar -->
|
||||||
|
<QuickInputBar
|
||||||
|
onSearch={handleInputSearch}
|
||||||
|
onSelect={handleInputSelect}
|
||||||
|
placeholder="Song suchen..."
|
||||||
|
emptyText="Keine Songs gefunden"
|
||||||
|
searchingText="Suche..."
|
||||||
|
locale="de"
|
||||||
|
appIcon="search"
|
||||||
|
bottomOffset="140px"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<main id="main-content" class="main-content bg-background">
|
<main id="main-content" class="main-content bg-background">
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { _ } from 'svelte-i18n';
|
import { _, locale } from 'svelte-i18n';
|
||||||
import { PillNavigation } from '@manacore/shared-ui';
|
import { PillNavigation, QuickInputBar } from '@manacore/shared-ui';
|
||||||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
import type { PillNavItem, PillDropdownItem, QuickInputItem } from '@manacore/shared-ui';
|
||||||
import { theme } from '$lib/stores/theme';
|
import { theme } from '$lib/stores/theme';
|
||||||
import { authStore } from '$lib/stores/auth.svelte';
|
import { authStore } from '$lib/stores/auth.svelte';
|
||||||
import { photoStore } from '$lib/stores/photos.svelte';
|
import { photoStore } from '$lib/stores/photos.svelte';
|
||||||
|
|
@ -56,6 +56,29 @@
|
||||||
goto('/login');
|
goto('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuickInputBar handlers
|
||||||
|
async function handleInputSearch(query: string): Promise<QuickInputItem[]> {
|
||||||
|
const q = query.toLowerCase();
|
||||||
|
const albums = albumStore.albums.filter((a) => a.name?.toLowerCase().includes(q));
|
||||||
|
const tags = tagStore.tags.filter((t) => t.name?.toLowerCase().includes(q));
|
||||||
|
const results: QuickInputItem[] = [];
|
||||||
|
for (const album of albums.slice(0, 5)) {
|
||||||
|
results.push({ id: `album-${album.id}`, title: album.name, subtitle: 'Album' });
|
||||||
|
}
|
||||||
|
for (const tag of tags.slice(0, 5)) {
|
||||||
|
results.push({ id: `tag-${tag.id}`, title: tag.name, subtitle: 'Tag' });
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInputSelect(item: QuickInputItem) {
|
||||||
|
if (item.id.startsWith('album-')) {
|
||||||
|
goto(`/albums/${item.id.replace('album-', '')}`);
|
||||||
|
} else if (item.id.startsWith('tag-')) {
|
||||||
|
goto(`/tags/${item.id.replace('tag-', '')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await authStore.initialize();
|
await authStore.initialize();
|
||||||
if (!authStore.isAuthenticated) {
|
if (!authStore.isAuthenticated) {
|
||||||
|
|
@ -91,6 +114,18 @@
|
||||||
settingsHref="/settings"
|
settingsHref="/settings"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Quick Input Bar -->
|
||||||
|
<QuickInputBar
|
||||||
|
onSearch={handleInputSearch}
|
||||||
|
onSelect={handleInputSelect}
|
||||||
|
placeholder="Album oder Tag suchen..."
|
||||||
|
emptyText="Nichts gefunden"
|
||||||
|
searchingText="Suche..."
|
||||||
|
locale={$locale || 'de'}
|
||||||
|
appIcon="search"
|
||||||
|
bottomOffset="70px"
|
||||||
|
/>
|
||||||
|
|
||||||
<main class="main-content bg-background">
|
<main class="main-content bg-background">
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
{@render children()}
|
{@render children()}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { PillNavigation } from '@manacore/shared-ui';
|
import { PillNavigation, QuickInputBar } from '@manacore/shared-ui';
|
||||||
import type { PillNavItem } from '@manacore/shared-ui';
|
import type { PillNavItem, QuickInputItem } from '@manacore/shared-ui';
|
||||||
import { theme } from '$lib/stores/theme';
|
import { theme } from '$lib/stores/theme';
|
||||||
import { authStore } from '$lib/stores/auth.svelte';
|
import { authStore } from '$lib/stores/auth.svelte';
|
||||||
|
import { plantsApi } from '$lib/api/plants';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
|
|
@ -27,6 +28,29 @@
|
||||||
goto('/login');
|
goto('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuickInputBar handlers
|
||||||
|
async function handleInputSearch(query: string): Promise<QuickInputItem[]> {
|
||||||
|
const plants = await plantsApi.getAll();
|
||||||
|
const q = query.toLowerCase();
|
||||||
|
return plants
|
||||||
|
.filter(
|
||||||
|
(p) =>
|
||||||
|
p.name?.toLowerCase().includes(q) ||
|
||||||
|
p.commonName?.toLowerCase().includes(q) ||
|
||||||
|
p.scientificName?.toLowerCase().includes(q)
|
||||||
|
)
|
||||||
|
.slice(0, 10)
|
||||||
|
.map((plant) => ({
|
||||||
|
id: plant.id,
|
||||||
|
title: plant.name || plant.commonName || 'Unbenannt',
|
||||||
|
subtitle: plant.scientificName || undefined,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInputSelect(item: QuickInputItem) {
|
||||||
|
goto(`/plant/${item.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (!authStore.isAuthenticated) {
|
if (!authStore.isAuthenticated) {
|
||||||
goto('/login');
|
goto('/login');
|
||||||
|
|
@ -49,6 +73,18 @@
|
||||||
primaryColor="#10b981"
|
primaryColor="#10b981"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Quick Input Bar -->
|
||||||
|
<QuickInputBar
|
||||||
|
onSearch={handleInputSearch}
|
||||||
|
onSelect={handleInputSelect}
|
||||||
|
placeholder="Pflanze suchen..."
|
||||||
|
emptyText="Keine Pflanzen gefunden"
|
||||||
|
searchingText="Suche..."
|
||||||
|
locale="de"
|
||||||
|
appIcon="search"
|
||||||
|
bottomOffset="70px"
|
||||||
|
/>
|
||||||
|
|
||||||
<main class="main-content pt-24">
|
<main class="main-content pt-24">
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
{@render children()}
|
{@render children()}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { locale } from 'svelte-i18n';
|
import { locale } from 'svelte-i18n';
|
||||||
import { PillNavigation } from '@manacore/shared-ui';
|
import { PillNavigation, QuickInputBar } from '@manacore/shared-ui';
|
||||||
import type { PillNavItem, PillDropdownItem } from '@manacore/shared-ui';
|
import type { PillNavItem, PillDropdownItem, QuickInputItem } from '@manacore/shared-ui';
|
||||||
import { auth } from '$lib/stores/auth.svelte';
|
import { auth } from '$lib/stores/auth.svelte';
|
||||||
import { userSettings } from '$lib/stores/user-settings.svelte';
|
import { userSettings } from '$lib/stores/user-settings.svelte';
|
||||||
import { theme } from '$lib/stores/theme';
|
import { theme } from '$lib/stores/theme';
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n';
|
import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n';
|
||||||
import { getPillAppItems } from '@manacore/shared-branding';
|
import { getPillAppItems } from '@manacore/shared-branding';
|
||||||
import { setLocale, supportedLocales } from '$lib/i18n';
|
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||||
|
import { decksStore } from '$lib/stores/decks.svelte';
|
||||||
import { presiOnboarding } from '$lib/stores/app-onboarding.svelte';
|
import { presiOnboarding } from '$lib/stores/app-onboarding.svelte';
|
||||||
import { MiniOnboardingModal } from '@manacore/shared-app-onboarding';
|
import { MiniOnboardingModal } from '@manacore/shared-app-onboarding';
|
||||||
|
|
||||||
|
|
@ -103,6 +104,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuickInputBar handlers
|
||||||
|
async function handleInputSearch(query: string): Promise<QuickInputItem[]> {
|
||||||
|
const q = query.toLowerCase();
|
||||||
|
return decksStore.decks
|
||||||
|
.filter((d) => d.title.toLowerCase().includes(q) || d.description?.toLowerCase().includes(q))
|
||||||
|
.slice(0, 10)
|
||||||
|
.map((deck) => ({
|
||||||
|
id: deck.id,
|
||||||
|
title: deck.title,
|
||||||
|
subtitle: deck.description || undefined,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInputSelect(item: QuickInputItem) {
|
||||||
|
goto(`/deck/${item.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
// Redirect to login if not authenticated
|
// Redirect to login if not authenticated
|
||||||
if (!auth.isAuthenticated) {
|
if (!auth.isAuthenticated) {
|
||||||
|
|
@ -169,6 +187,18 @@
|
||||||
allAppsHref="/apps"
|
allAppsHref="/apps"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- Quick Input Bar -->
|
||||||
|
<QuickInputBar
|
||||||
|
onSearch={handleInputSearch}
|
||||||
|
onSelect={handleInputSelect}
|
||||||
|
placeholder="Präsentation suchen..."
|
||||||
|
emptyText="Keine Decks gefunden"
|
||||||
|
searchingText="Suche..."
|
||||||
|
locale={$locale || 'de'}
|
||||||
|
appIcon="search"
|
||||||
|
bottomOffset="70px"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<main class="main-content">
|
<main class="main-content">
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue