managarten/packages/shared-links/src/deep-links.ts
Till JS 4cee74e15d feat(shared-links): deep-link navigation to target app detail views
ManaLinkBadge now resolves the correct URL for the linked record's
detail view (e.g. /event/{id}, /contacts/{id}, /deck/{id}) instead
of just linking to the app's root page.

Uses an anchor tag by default for standard browser navigation, with
onclick prop override for custom behavior. Supports all 12 apps with
their specific routing patterns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:14:29 +02:00

80 lines
2 KiB
TypeScript

/**
* ManaLink — Deep-Link Resolution
*
* Maps app + collection + recordId to a full URL that opens
* the record's detail view in the target app.
*/
import { APP_URLS } from '@manacore/shared-branding';
import type { AppIconId } from '@manacore/shared-branding';
/** Route pattern per app and collection. Use {id} as placeholder. */
const DEEP_LINK_PATTERNS: Record<string, Record<string, string>> = {
todo: {
// Todo uses inline editing, no detail route — link to app root
tasks: '/',
projects: '/',
},
calendar: {
events: '/event/{id}',
calendars: '/',
},
contacts: {
contacts: '/contacts/{id}',
},
chat: {
conversations: '/chat/{id}',
messages: '/chat/{id}', // Navigate to conversation, not individual message
},
picture: {
images: '/app/board/{id}',
boards: '/app/board/{id}',
},
storage: {
files: '/',
folders: '/files/{id}',
},
presi: {
decks: '/deck/{id}',
slides: '/deck/{id}', // Navigate to the deck containing the slide
},
context: {
documents: '/documents/{id}',
spaces: '/spaces/{id}',
},
manadeck: {
decks: '/decks/{id}',
cards: '/decks/{id}', // Navigate to deck containing the card
},
mukke: {
songs: '/',
playlists: '/playlists/{id}',
},
clock: {
alarms: '/',
timers: '/',
},
zitare: {
favorites: '/',
},
};
/**
* Resolve a deep link URL for a cross-app record.
*
* @param app - App ID (e.g. 'todo', 'calendar')
* @param collection - Collection name (e.g. 'tasks', 'events')
* @param recordId - Record UUID
* @returns Full URL to the record's detail view, or app root as fallback
*/
export function resolveDeepLink(app: string, collection: string, recordId: string): string {
const isDev = typeof window !== 'undefined' && window.location.hostname === 'localhost';
const urls = APP_URLS[app as AppIconId];
if (!urls) return '#';
const baseUrl = isDev ? urls.dev : urls.prod;
const pattern = DEEP_LINK_PATTERNS[app]?.[collection] ?? '/';
const path = pattern.replace('{id}', recordId);
return `${baseUrl}${path}`;
}