@adminide-stack/yantra-mobile 12.0.28-alpha.7 → 12.0.28-alpha.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/stt.js +54 -0
- package/lib/api/stt.js.map +1 -0
- package/lib/assets/icon.png +0 -0
- package/lib/components/CustomDrawer.js +479 -0
- package/lib/components/CustomDrawer.js.map +1 -0
- package/lib/components/GatewayConnector/GatewayConnector.js +18 -0
- package/lib/components/GatewayConnector/GatewayConnector.js.map +1 -0
- package/lib/components/GatewayToolbarButtonMobile.js +84 -0
- package/lib/components/GatewayToolbarButtonMobile.js.map +1 -0
- package/lib/components/NavigationHeader/NavigationHeader.js +214 -0
- package/lib/components/NavigationHeader/NavigationHeader.js.map +1 -0
- package/lib/components/ThinkingIndicator.js +55 -0
- package/lib/components/ThinkingIndicator.js.map +1 -0
- package/lib/components/YantraBrandLoader.js +94 -0
- package/lib/components/YantraBrandLoader.js.map +1 -0
- package/lib/compute.js +114 -5
- package/lib/compute.js.map +1 -1
- package/lib/config/constants.js +16 -0
- package/lib/config/constants.js.map +1 -0
- package/lib/config/env-config.js +74 -19
- package/lib/config/env-config.js.map +1 -1
- package/lib/contexts/CdecliConnectionContext.js +47 -0
- package/lib/contexts/CdecliConnectionContext.js.map +1 -0
- package/lib/contexts/GatewayContext.js +77 -0
- package/lib/contexts/GatewayContext.js.map +1 -0
- package/lib/features/audio-input/AudioRecorderPanel.js +231 -0
- package/lib/features/audio-input/AudioRecorderPanel.js.map +1 -0
- package/lib/features/audio-input/MicErrorBoundary.js +34 -0
- package/lib/features/audio-input/MicErrorBoundary.js.map +1 -0
- package/lib/graphql/agentGatewayDocuments.js +53 -0
- package/lib/graphql/agentGatewayDocuments.js.map +1 -0
- package/lib/hooks/useCdecliAutoConnect.js +242 -0
- package/lib/hooks/useCdecliAutoConnect.js.map +1 -0
- package/lib/hooks/useCdecliChannel.js +226 -0
- package/lib/hooks/useCdecliChannel.js.map +1 -0
- package/lib/hooks/useChatApi.js +338 -171
- package/lib/hooks/useChatApi.js.map +1 -1
- package/lib/hooks/useChatStream.js +281 -64
- package/lib/hooks/useChatStream.js.map +1 -1
- package/lib/hooks/useGatewayConnection.js +123 -0
- package/lib/hooks/useGatewayConnection.js.map +1 -0
- package/lib/hooks/useGatewayRegistry.js +28 -0
- package/lib/hooks/useGatewayRegistry.js.map +1 -0
- package/lib/hooks/usePrerequisiteIds.js +181 -0
- package/lib/hooks/usePrerequisiteIds.js.map +1 -0
- package/lib/hooks/useWorkspaceProvisioner.js +236 -0
- package/lib/hooks/useWorkspaceProvisioner.js.map +1 -0
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/routes.json +120 -5
- package/lib/screens/Chat/index.js +423 -0
- package/lib/screens/Chat/index.js.map +1 -0
- package/lib/screens/ChatHistory/index.js +56 -0
- package/lib/screens/ChatHistory/index.js.map +1 -0
- package/lib/screens/Home/HomeScreen.js +413 -140
- package/lib/screens/Home/HomeScreen.js.map +1 -1
- package/lib/screens/Home/components/ChatHistoryLanding.js +487 -0
- package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -0
- package/lib/screens/Home/components/DeepSearchModal.js +349 -0
- package/lib/screens/Home/components/DeepSearchModal.js.map +1 -0
- package/lib/screens/Home/deepSearchUtils.js +41 -0
- package/lib/screens/Home/deepSearchUtils.js.map +1 -0
- package/lib/screens/NewChat/index.js +79 -0
- package/lib/screens/NewChat/index.js.map +1 -0
- package/lib/services/agentSessionManager.js +451 -0
- package/lib/services/agentSessionManager.js.map +1 -0
- package/lib/services/gatewayApiKeyBridge.js +4 -0
- package/lib/services/gatewayApiKeyBridge.js.map +1 -0
- package/lib/services/gatewayClient.js +470 -0
- package/lib/services/gatewayClient.js.map +1 -0
- package/lib/theme/mobileTokens.js +18 -0
- package/lib/theme/mobileTokens.js.map +1 -0
- package/lib/utils/gatewaySelectionStorage.js +21 -0
- package/lib/utils/gatewaySelectionStorage.js.map +1 -0
- package/package.json +7 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatHistoryLanding.js","sources":["../../../../src/screens/Home/components/ChatHistoryLanding.tsx"],"sourcesContent":["import React from 'react';\nimport {\n ActivityIndicator,\n Pressable,\n RefreshControl,\n SectionList,\n StyleSheet,\n View,\n useColorScheme,\n useWindowDimensions,\n} from 'react-native';\nimport { Feather, MaterialCommunityIcons } from '@expo/vector-icons';\nimport { Text } from '@admin-layout/gluestack-ui-mobile';\nimport { useFocusEffect } from '@react-navigation/native';\nimport {\n HISTORY_PAGE_SIZE,\n chatHistorySessionsFromChannels,\n getHistoryChannelsQueryVariables,\n useChatHistorySessionsFromChannels,\n type ChatHistoryMode,\n type ChatHistorySession,\n} from '../../../hooks/useChatApi';\nimport { useApolloClient } from '@apollo/client';\nimport { GetChannelsByUserWithLastMessageDocument } from 'common/graphql';\nimport { usePrerequisiteIds } from '../../../hooks/usePrerequisiteIds';\nimport ThinkingIndicator from '../../../components/ThinkingIndicator';\nimport { mobileTokens } from '../../../theme/mobileTokens';\n\n/**\n * Chat history list for mobile.\n *\n * Data: `useGetChannelsByUserWithLastMessageQuery` returning one row per channel\n * with `lastMessage` carrying the parent user prompt and the assistant reply.\n *\n * Layout: Manus-style two-line row — 40×40 leading mode tile, **line 1** =\n * `lastMessage.propsConfiguration.contents.parent.message` (user prompt),\n * **line 2** = `lastMessage.message` (latest post body, including agent errors\n * such as lines starting with ⚠), right-aligned short date. Indigo-tinted\n * neutrals so the surface stays in the Yantra brand register.\n *\n * Mode tile carries real information (chat vs deep-search), not decoration —\n * different modes get different glyphs and tints.\n */\ninterface ChatHistoryLandingProps {\n /**\n * `mode` is derived per-row via `detectMode(channel)` so the Chat screen can\n * render its composer in the correct mode (deep-search vs chat) without\n * needing to re-fetch the channel after navigation. Plain chat threads get\n * `'chat'` here even though it's the default — being explicit at the\n * boundary keeps the consumer's switch statement total.\n */\n onSelectSession: (channelId: string, mode: ChatHistoryMode) => void;\n /** Kept in the contract; not surfaced here — new-chat lives in the screen header. */\n onCompose: () => void;\n}\n\ninterface SessionRow extends ChatHistorySession {\n id: string;\n /** Pre-truncated title for one-line render. */\n titleForRender: string;\n /** Pre-truncated preview for one-line render (empty if suppressed upstream). */\n previewForRender: string;\n /** Cached unix-ms for bucketing / sorting. */\n sortAt: number;\n}\n\ninterface SessionSection {\n key: 'today' | 'yesterday' | 'week' | 'earlier';\n title: string;\n data: SessionRow[];\n}\n\nfunction truncate(text: string, max = 96): string {\n const cleaned = text.replace(/\\s+/g, ' ').trim();\n if (cleaned.length <= max) return cleaned;\n return `${cleaned.slice(0, max).trim()}...`;\n}\n\nconst WEEKDAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n\nfunction relativeTime(ts: number, now: number): string {\n const deltaMs = now - ts;\n if (deltaMs < 60_000) return 'now';\n const minutes = Math.floor(deltaMs / 60_000);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h`;\n const days = Math.floor(hours / 24);\n if (days < 7) {\n const d = new Date(ts);\n return WEEKDAYS[d.getDay()] ?? `${days}d`;\n }\n /**\n * 7d+: numeric short date (e.g. \"2/18\" matching the Manus reference). Year only\n * appears when crossing into a previous year, to keep the right column compact.\n */\n const d = new Date(ts);\n const sameYear = d.getFullYear() === new Date(now).getFullYear();\n const m = d.getMonth() + 1;\n const day = d.getDate();\n return sameYear ? `${m}/${day}` : `${m}/${day}/${String(d.getFullYear()).slice(2)}`;\n}\n\nfunction bucketFor(ts: number, now: number): SessionSection['key'] {\n const a = new Date(ts);\n const b = new Date(now);\n const startOf = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n const today = startOf(b);\n const yesterday = today - 24 * 60 * 60 * 1000;\n const weekAgo = today - 7 * 24 * 60 * 60 * 1000;\n const tsDay = startOf(a);\n if (tsDay >= today) return 'today';\n if (tsDay >= yesterday) return 'yesterday';\n if (tsDay >= weekAgo) return 'week';\n return 'earlier';\n}\n\nfunction buildSections(rows: SessionRow[], now: number): SessionSection[] {\n const buckets: Record<SessionSection['key'], SessionRow[]> = {\n today: [],\n yesterday: [],\n week: [],\n earlier: [],\n };\n for (const row of rows) {\n buckets[bucketFor(row.sortAt, now)].push(row);\n }\n const out: SessionSection[] = [];\n if (buckets.today.length) out.push({ key: 'today', title: 'Today', data: buckets.today });\n if (buckets.yesterday.length) out.push({ key: 'yesterday', title: 'Yesterday', data: buckets.yesterday });\n if (buckets.week.length) out.push({ key: 'week', title: 'This week', data: buckets.week });\n if (buckets.earlier.length) out.push({ key: 'earlier', title: 'Earlier', data: buckets.earlier });\n return out;\n}\n\n/**\n * Theme tokens.\n *\n * Color strategy: Monochrome ink. Chrome (section labels, chat tile, load-more\n * pill, end-of-list dot, press wash, refresh spinner) is rendered in tinted\n * neutrals so the only real color on the screen is the deep-search amber —\n * which then reliably signals a mode, not decoration. Neutrals carry chroma\n * 0.005–0.01 toward the brand hue (no pure `#fff` / `#000`).\n */\ninterface ThemeTokens {\n bg: string;\n surface: string;\n title: string;\n preview: string;\n meta: string;\n muted: string;\n divider: string;\n sectionLabel: string;\n /** Mode tile (chat) — neutral ink on neutral fill. */\n tileChatBg: string;\n tileChatIcon: string;\n /** Mode tile (deep-search) — amber kept as the one real mode color. */\n tileSearchBg: string;\n tileSearchIcon: string;\n pressed: string;\n loadMoreText: string;\n loadMoreBorder: string;\n loadMoreBg: string;\n refreshTint: string;\n endDot: string;\n /**\n * Empty-state mark — circular soft-neutral disk holding a chat glyph.\n * Matches the web reference (gray-on-gray circle), not the row mode tile.\n */\n emptyMarkBg: string;\n emptyMarkIcon: string;\n}\n\nfunction buildTheme(isDark: boolean): ThemeTokens {\n if (isDark) {\n return {\n bg: '#0b1220',\n surface: mobileTokens.color.surface,\n title: '#f1f5f9',\n preview: '#94a3b8',\n meta: '#9aa0b8',\n muted: '#7a809a',\n divider: 'rgba(148, 163, 184, 0.12)',\n sectionLabel: '#cbd5e1',\n tileChatBg: 'rgba(148, 163, 184, 0.16)',\n tileChatIcon: '#e2e8f0',\n tileSearchBg: 'rgba(251, 191, 36, 0.16)',\n tileSearchIcon: '#fde68a',\n pressed: 'rgba(148, 163, 184, 0.10)',\n loadMoreText: '#e2e8f0',\n loadMoreBorder: 'rgba(148, 163, 184, 0.28)',\n loadMoreBg: 'rgba(148, 163, 184, 0.10)',\n refreshTint: '#cbd5e1',\n endDot: '#94a3b8',\n emptyMarkBg: 'rgba(148, 163, 184, 0.18)',\n emptyMarkIcon: '#b4bccc',\n };\n }\n return {\n bg: mobileTokens.color.bg,\n surface: mobileTokens.color.surface,\n title: '#0b1424',\n preview: '#525a73',\n meta: '#7b8197',\n muted: '#94a3b8',\n divider: 'rgba(15, 23, 42, 0.06)',\n sectionLabel: '#374151',\n tileChatBg: 'rgba(15, 23, 42, 0.06)',\n tileChatIcon: '#1f2937',\n tileSearchBg: 'rgba(217, 119, 6, 0.10)',\n tileSearchIcon: '#b45309',\n pressed: 'rgba(15, 23, 42, 0.05)',\n loadMoreText: '#1f2937',\n loadMoreBorder: 'rgba(15, 23, 42, 0.15)',\n loadMoreBg: 'rgba(15, 23, 42, 0.04)',\n refreshTint: '#374151',\n endDot: '#9ca3af',\n emptyMarkBg: 'rgba(15, 23, 42, 0.07)',\n emptyMarkIcon: '#6b7280',\n };\n}\n\n/**\n * Leading 40×40 mode tile. Background and glyph reflect the conversation mode:\n * - chat → Lucide-style message bubble on indigo-tinted neutral\n * - deep-search → lightning glyph on amber-tinted neutral\n *\n * Chat uses Feather (a Lucide port) so the row tile, the empty-state mark, and\n * the web header all share one bubble silhouette. Deep-search stays on MCI —\n * Feather has no acceptable lightning glyph and the amber/indigo split is\n * already the primary mode signal.\n *\n * Real information per row, not decoration.\n */\nfunction ModeTile({ mode, theme }: { mode: ChatHistoryMode; theme: ThemeTokens }) {\n const isSearch = mode === 'deep-search';\n return (\n <View style={[styles.tile, { backgroundColor: isSearch ? theme.tileSearchBg : theme.tileChatBg }]}>\n {isSearch ? (\n <MaterialCommunityIcons name=\"lightning-bolt-outline\" size={18} color={theme.tileSearchIcon} />\n ) : (\n <Feather name=\"message-circle\" size={18} color={theme.tileChatIcon} />\n )}\n </View>\n );\n}\n\nfunction ChatHistoryRow({\n session,\n onSelectSession,\n theme,\n timeLabel,\n}: {\n session: SessionRow;\n onSelectSession: (channelId: string, mode: ChatHistoryMode) => void;\n theme: ThemeTokens;\n timeLabel: string;\n}) {\n const titleColor = session.isPlaceholder ? theme.preview : theme.title;\n const titleStyle = [\n styles.rowTitle,\n { color: titleColor },\n session.isPlaceholder ? styles.rowTitlePlaceholder : null,\n ];\n return (\n <Pressable\n onPress={() => onSelectSession(session.channelId, session.mode)}\n style={({ pressed }) => [styles.row, pressed && { backgroundColor: theme.pressed }]}\n accessibilityRole=\"button\"\n accessibilityLabel={\n session.previewForRender\n ? `Open conversation: ${session.titleForRender}. ${session.previewForRender}. ${timeLabel}`\n : `Open conversation: ${session.titleForRender}, ${timeLabel}`\n }\n >\n <ModeTile mode={session.mode} theme={theme} />\n <View style={styles.rowBody}>\n <View style={styles.rowHeader}>\n <Text style={titleStyle} numberOfLines={1} ellipsizeMode=\"tail\">\n {session.titleForRender}\n </Text>\n <Text style={[styles.rowDate, { color: theme.meta }]} numberOfLines={1}>\n {timeLabel}\n </Text>\n </View>\n {session.previewForRender ? (\n <Text style={[styles.rowPreview, { color: theme.preview }]} numberOfLines={1} ellipsizeMode=\"tail\">\n {session.previewForRender}\n </Text>\n ) : null}\n </View>\n </Pressable>\n );\n}\n\nexport default function ChatHistoryLanding({ onSelectSession }: ChatHistoryLandingProps) {\n const { width: screenWidth } = useWindowDimensions();\n const colorScheme = useColorScheme();\n const isDark = colorScheme === 'dark';\n const theme = React.useMemo(() => buildTheme(isDark), [isDark]);\n\n const apollo = useApolloClient();\n const { orgName, loading: idsLoading } = usePrerequisiteIds();\n\n const {\n sessions: liveSessions,\n sessionsLoaded,\n refetch,\n sourceChannelCount,\n } = useChatHistorySessionsFromChannels(orgName, { skip: !orgName });\n\n /** \"Now\" reference recomputed on refresh so relative timestamps re-evaluate cleanly. */\n const [nowTs, setNowTs] = React.useState(() => Date.now());\n const [refreshing, setRefreshing] = React.useState(false);\n /** Manually fetched older pages (channel-paginated, appended). */\n const [olderSessions, setOlderSessions] = React.useState<ChatHistorySession[]>([]);\n /** True only when the last fetch returned a full page of channels (there may be more). */\n const [hasMore, setHasMore] = React.useState(false);\n const [loadingMore, setLoadingMore] = React.useState(false);\n\n /**\n * \"Load older\" eligibility tracks the live first page's raw channel count.\n * When older pages are appended, `onLoadMore` updates `hasMore` from its\n * own response. When older pages are reset (refresh), this effect realigns.\n */\n React.useEffect(() => {\n if (olderSessions.length > 0) return;\n setHasMore(sourceChannelCount >= HISTORY_PAGE_SIZE);\n }, [sourceChannelCount, olderSessions.length]);\n\n /** Re-fetch first page on focus (e.g. returning from a chat). */\n useFocusEffect(\n React.useCallback(() => {\n if (!orgName) return;\n void refetch(getHistoryChannelsQueryVariables(orgName)).catch(() => {\n /* network errors surface in the watched query state. */\n });\n }, [orgName, refetch]),\n );\n\n const onRefresh = React.useCallback(async () => {\n if (!orgName) return;\n setRefreshing(true);\n try {\n await refetch(getHistoryChannelsQueryVariables(orgName));\n setOlderSessions([]);\n setNowTs(Date.now());\n } catch {\n /* refetch errors surface via loading state. */\n } finally {\n setRefreshing(false);\n }\n }, [orgName, refetch]);\n\n /**\n * \"Load older\": one-off `client.query` against `channelsByUser` with the next\n * `skip`. We don't bump the watched query's variables (that would re-key the\n * cache slot and shrink `liveSessions`).\n */\n const onLoadMore = React.useCallback(async () => {\n if (!orgName || loadingMore || !hasMore) return;\n setLoadingMore(true);\n try {\n const nextSkip = liveSessions.length + olderSessions.length;\n const result = await apollo.query({\n query: GetChannelsByUserWithLastMessageDocument,\n variables: getHistoryChannelsQueryVariables(orgName, {\n skip: nextSkip,\n limit: HISTORY_PAGE_SIZE,\n }),\n fetchPolicy: 'network-only',\n });\n const rawCount = (result.data?.channelsByUser ?? []).length;\n const nextBatch = chatHistorySessionsFromChannels(result.data as any);\n if (nextBatch.length === 0) {\n setHasMore(false);\n } else {\n setOlderSessions((prev) => {\n const map = new Map<string, ChatHistorySession>();\n for (const s of prev) map.set(s.channelId, s);\n for (const s of nextBatch) map.set(s.channelId, s);\n return Array.from(map.values());\n });\n setHasMore(rawCount >= HISTORY_PAGE_SIZE);\n }\n } catch {\n /* next \"Load older\" tap retries the same skip. */\n } finally {\n setLoadingMore(false);\n }\n }, [apollo, hasMore, liveSessions.length, loadingMore, olderSessions, orgName]);\n\n /**\n * Merge live + older, dedupe on channelId (live wins so streaming title /\n * lastMessage updates are reflected), sort descending by activity, then\n * pre-truncate strings for one-line render.\n */\n const sessions: SessionRow[] = React.useMemo(() => {\n const map = new Map<string, ChatHistorySession>();\n for (const s of olderSessions) map.set(s.channelId, s);\n for (const s of liveSessions) map.set(s.channelId, s);\n return Array.from(map.values())\n .sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())\n .map((s) => ({\n ...s,\n id: s.channelId,\n titleForRender: truncate(s.title, 64),\n previewForRender: s.preview ? truncate(s.preview, 96) : '',\n sortAt: s.updatedAt.getTime(),\n }));\n }, [liveSessions, olderSessions]);\n\n const sections = React.useMemo(() => buildSections(sessions, nowTs), [sessions, nowTs]);\n /**\n * Initial-load window: the loader shows ONLY before we have data we can\n * render — i.e. before prerequisite ids resolve or before Apollo has served\n * a result (cache or network) for this org.\n *\n * Critically, `sessionsLoaded` (`data !== undefined`) flips true synchronously\n * on a cache hit, so revisiting the screen does not re-flash the loader while\n * Apollo revalidates in the background. We also do NOT gate on\n * `sessions.length === 0` here — a cached-but-empty list should drop straight\n * into the dedicated empty state, not the spinner.\n */\n const initialLoading = !sessionsLoaded || idsLoading || !orgName;\n const contentMaxWidth = Math.min(720, Math.max(360, screenWidth - 24));\n const containerStyle = { maxWidth: contentMaxWidth, alignSelf: 'center' as const, width: '100%' as const };\n\n const listFooter = hasMore ? (\n <View style={[styles.footer, containerStyle]}>\n <Pressable\n onPress={() => void onLoadMore()}\n disabled={loadingMore}\n style={({ pressed }) => [\n styles.loadMore,\n {\n backgroundColor: theme.loadMoreBg,\n borderColor: theme.loadMoreBorder,\n },\n loadingMore && { opacity: 0.7 },\n pressed && !loadingMore && { opacity: 0.8 },\n ]}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Load older conversations\"\n >\n {loadingMore ? (\n <ActivityIndicator size=\"small\" color={theme.loadMoreText} />\n ) : (\n <Text style={[styles.loadMoreText, { color: theme.loadMoreText }]}>Load older</Text>\n )}\n </Pressable>\n </View>\n ) : !hasMore && sessions.length > 0 ? (\n <View style={[styles.endHint, containerStyle]}>\n <View style={[styles.endHintDot, { backgroundColor: theme.endDot, opacity: 0.5 }]} />\n <Text style={[styles.endHintText, { color: theme.muted }]}>{\"You're all caught up\"}</Text>\n </View>\n ) : (\n <View style={{ height: 24 }} />\n );\n\n /**\n * Hairline divider between rows, inset to start where the title column does\n * (past the 40px tile + 14px gap = 54px). Quieter than full-bleed; confirms\n * the column the eye is scanning.\n */\n const renderItemSeparator = React.useCallback(\n () => <View style={[styles.divider, { backgroundColor: theme.divider }]} />,\n [theme.divider],\n );\n\n return (\n <View style={[styles.container, { backgroundColor: theme.bg }]}>\n {initialLoading ? (\n /**\n * Initial-fetch state mirrors the web composer's \"Thinking…\" pill\n * (see `packages-modules/account/browser/src/pages/chat/ChatSessionPage.tsx`):\n * a thin spinning arc + 12px muted caption, both tinted with\n * `theme.muted` so the indicator reads as a quiet status row\n * rather than a brand-stamped loading screen.\n */\n <View style={styles.emptyStateWrap}>\n <ThinkingIndicator color={theme.muted} />\n </View>\n ) : sessions.length === 0 ? (\n <View style={styles.emptyStateWrap}>\n {/**\n * Empty-state mark: circular neutral disk with a Lucide-style chat\n * bubble. Uses Feather (same glyph family as the web's lucide-react\n * `MessageCircle`) instead of MCI so the rounded body + tail proportions\n * match the web reference 1:1. Glyph fills ~55% of the disk so it\n * reads as a real focal point, not decoration.\n */}\n <View style={[styles.emptyMark, { backgroundColor: theme.emptyMarkBg }]}>\n <Feather name=\"message-circle\" size={40} color={theme.emptyMarkIcon} />\n </View>\n <Text style={[styles.emptyTitle, { color: theme.title }]}>No conversations yet</Text>\n <Text style={[styles.emptySubtitle, { color: theme.muted }]}>\n Start your first chat to see your conversation history here.\n </Text>\n </View>\n ) : (\n <SectionList\n sections={sections}\n keyExtractor={(item) => item.channelId}\n stickySectionHeadersEnabled={false}\n contentContainerStyle={[styles.listContent, containerStyle, { paddingBottom: 32 }]}\n ListFooterComponent={listFooter}\n ItemSeparatorComponent={renderItemSeparator}\n refreshControl={\n <RefreshControl\n refreshing={refreshing}\n onRefresh={() => void onRefresh()}\n tintColor={theme.refreshTint}\n colors={[theme.refreshTint]}\n />\n }\n renderSectionHeader={({ section }) => (\n <View style={styles.sectionHeader}>\n <Text style={[styles.sectionLabel, { color: theme.sectionLabel }]}>{section.title}</Text>\n </View>\n )}\n renderItem={({ item }) => (\n <ChatHistoryRow\n session={item}\n onSelectSession={onSelectSession}\n theme={theme}\n timeLabel={relativeTime(item.sortAt, nowTs)}\n />\n )}\n showsVerticalScrollIndicator={false}\n />\n )}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n },\n listContent: {\n paddingHorizontal: 20,\n paddingTop: 4,\n },\n /**\n * Section header: sentence case, indigo-tinted, modest size. 28px top padding\n * establishes rhythm between groups without dead air below the label.\n */\n sectionHeader: {\n paddingTop: 28,\n paddingBottom: 10,\n paddingHorizontal: 2,\n },\n sectionLabel: {\n fontSize: 12,\n fontWeight: '600',\n letterSpacing: 0.2,\n textTransform: 'none',\n },\n /**\n * Row: leading 40×40 mode tile, two-line body (title + preview), right-aligned\n * date aligned to the title's baseline. 14px gap matches the tile-to-text\n * rhythm in Manus / iOS Mail.\n */\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n paddingVertical: 12,\n paddingHorizontal: 2,\n gap: 14,\n },\n tile: {\n width: 40,\n height: 40,\n borderRadius: 12,\n alignItems: 'center',\n justifyContent: 'center',\n },\n rowBody: {\n flex: 1,\n minWidth: 0,\n },\n rowHeader: {\n flexDirection: 'row',\n alignItems: 'baseline',\n gap: 10,\n },\n rowTitle: {\n flex: 1,\n fontSize: 16,\n fontWeight: '600',\n letterSpacing: -0.1,\n lineHeight: 22,\n },\n rowTitlePlaceholder: {\n fontWeight: '500',\n fontStyle: 'italic',\n },\n rowDate: {\n fontSize: 12.5,\n fontWeight: '500',\n fontVariant: ['tabular-nums'],\n },\n rowPreview: {\n marginTop: 2,\n fontSize: 13.5,\n lineHeight: 19,\n fontWeight: '400',\n letterSpacing: -0.05,\n },\n /**\n * Indented hairline: starts past the tile column (40 + 14 = 54) so the rule\n * aligns with the title's leading edge. Mail-style.\n */\n divider: {\n height: StyleSheet.hairlineWidth,\n marginLeft: 56,\n },\n footer: {\n paddingTop: 28,\n paddingBottom: 8,\n alignItems: 'center',\n },\n /** Bordered ink-neutral pill. Label is the affordance, no leading icon, no chevron. */\n loadMore: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n paddingVertical: 10,\n paddingHorizontal: 18,\n borderRadius: 999,\n borderWidth: 1,\n minWidth: 132,\n },\n loadMoreText: {\n fontSize: 13.5,\n fontWeight: '600',\n letterSpacing: -0.05,\n },\n endHint: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n paddingTop: 32,\n paddingBottom: 12,\n },\n endHintDot: {\n width: 4,\n height: 4,\n borderRadius: 2,\n },\n endHintText: {\n fontSize: 12.5,\n fontWeight: '500',\n letterSpacing: 0.1,\n },\n /**\n * Empty state: stack a 64×64 indigo-tinted mark over title + subtitle.\n * Generous vertical gap (16) between mark and title; tighter gap (6)\n * between title and subtitle so the pair reads as one unit hanging off\n * the mark, not three independent items.\n */\n emptyStateWrap: {\n flex: 1,\n minHeight: 420,\n alignItems: 'center',\n justifyContent: 'center',\n paddingHorizontal: 32,\n },\n emptyMark: {\n width: 72,\n height: 72,\n borderRadius: 36,\n alignItems: 'center',\n justifyContent: 'center',\n marginBottom: 18,\n },\n emptyTitle: {\n fontSize: 20,\n fontWeight: '700',\n letterSpacing: -0.3,\n textAlign: 'center',\n marginBottom: 6,\n },\n emptySubtitle: {\n fontSize: 14,\n lineHeight: 20,\n textAlign: 'center',\n maxWidth: 340,\n },\n});\n"],"names":["d"],"mappings":"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"}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import {jsx,jsxs}from'react/jsx-runtime';import {useRef,useMemo,useEffect}from'react';import {useWindowDimensions,Modal,View,StyleSheet,Pressable,ScrollView,Linking,Share}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {Text}from'@admin-layout/gluestack-ui-mobile';import Markdown from'react-native-markdown-display';import {mobileTokens}from'../../../theme/mobileTokens.js';function DeepSearchModal({
|
|
2
|
+
visible,
|
|
3
|
+
query,
|
|
4
|
+
summaryText,
|
|
5
|
+
sources,
|
|
6
|
+
isStreaming,
|
|
7
|
+
researchProcessOpen,
|
|
8
|
+
sourcesAccordionOpen,
|
|
9
|
+
onToggleResearchProcess,
|
|
10
|
+
onToggleSourcesAccordion,
|
|
11
|
+
onRetry,
|
|
12
|
+
onStop,
|
|
13
|
+
onClose
|
|
14
|
+
}) {
|
|
15
|
+
const {
|
|
16
|
+
width: screenWidth
|
|
17
|
+
} = useWindowDimensions();
|
|
18
|
+
const modalScrollRef = useRef(null);
|
|
19
|
+
const displayMarkdown = useMemo(() => {
|
|
20
|
+
if (!summaryText) return "";
|
|
21
|
+
const hasResearchHeading = /research summary\s*:/i.test(summaryText);
|
|
22
|
+
if (hasResearchHeading) return summaryText;
|
|
23
|
+
const heading = query ? `## Research Summary: ${query}` : "## Research Summary";
|
|
24
|
+
return `${heading}
|
|
25
|
+
|
|
26
|
+
${summaryText}`;
|
|
27
|
+
}, [summaryText, query]);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!visible) return;
|
|
30
|
+
requestAnimationFrame(() => {
|
|
31
|
+
var _a;
|
|
32
|
+
(_a = modalScrollRef.current) == null ? void 0 : _a.scrollToEnd({
|
|
33
|
+
animated: true
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}, [visible, displayMarkdown, sources.length, isStreaming]);
|
|
37
|
+
const handleShare = async () => {
|
|
38
|
+
if (!summaryText) return;
|
|
39
|
+
try {
|
|
40
|
+
await Share.share({
|
|
41
|
+
message: `${summaryText}
|
|
42
|
+
|
|
43
|
+
Query: ${query != null ? query : ""}`
|
|
44
|
+
});
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error("[DeepSearchModal] Failed to share summary:", error);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
return /* @__PURE__ */ jsx(Modal, { visible, transparent: true, animationType: "fade", onRequestClose: onClose, children: /* @__PURE__ */ jsx(View, { style: styles.modalBackdrop, children: /* @__PURE__ */ jsxs(View, { style: [styles.modalCard, {
|
|
50
|
+
width: Math.min(760, screenWidth - 24)
|
|
51
|
+
}], children: [
|
|
52
|
+
/* @__PURE__ */ jsxs(View, { style: styles.modalHeaderRow, children: [
|
|
53
|
+
/* @__PURE__ */ jsxs(View, { style: styles.modalHeaderLeft, children: [
|
|
54
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "$md", fontWeight: "$semibold", color: "$gray900", children: "Deep Search" }),
|
|
55
|
+
isStreaming ? /* @__PURE__ */ jsx(Text, { fontSize: "$xs", color: "$gray600", children: "Running..." }) : null
|
|
56
|
+
] }),
|
|
57
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: onClose, style: styles.iconButton, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close", size: 18, color: "#6b7280" }) })
|
|
58
|
+
] }),
|
|
59
|
+
/* @__PURE__ */ jsxs(ScrollView, { ref: modalScrollRef, style: styles.modalBody, contentContainerStyle: styles.modalBodyContent, nestedScrollEnabled: true, keyboardShouldPersistTaps: "handled", showsVerticalScrollIndicator: true, onContentSizeChange: () => {
|
|
60
|
+
var _a;
|
|
61
|
+
(_a = modalScrollRef.current) == null ? void 0 : _a.scrollToEnd({
|
|
62
|
+
animated: true
|
|
63
|
+
});
|
|
64
|
+
}, children: [
|
|
65
|
+
/* @__PURE__ */ jsxs(View, { style: styles.summaryCard, children: [
|
|
66
|
+
(displayMarkdown || (isStreaming ? "Researching..." : "")).length > 0 ? /* @__PURE__ */ jsx(Markdown, { style: markdownStyles, onLinkPress: (url) => {
|
|
67
|
+
void Linking.openURL(url);
|
|
68
|
+
return true;
|
|
69
|
+
}, children: displayMarkdown }) : /* @__PURE__ */ jsx(Text, { fontSize: "$sm", color: "$gray700", children: "No summary yet." }),
|
|
70
|
+
/* @__PURE__ */ jsxs(View, { style: styles.summaryActionRow, children: [
|
|
71
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: handleShare, style: styles.summaryActionButton, children: /* @__PURE__ */ jsx(Text, { fontSize: "$xs", color: "$gray900", children: "Share" }) }),
|
|
72
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: onRetry, disabled: isStreaming || !query, style: ({
|
|
73
|
+
pressed
|
|
74
|
+
}) => [styles.summaryActionButton, (isStreaming || !query) && styles.summaryActionDisabled, pressed && styles.sourceRowPressed], children: /* @__PURE__ */ jsx(Text, { fontSize: "$xs", color: "$gray900", children: "Retry" }) })
|
|
75
|
+
] })
|
|
76
|
+
] }),
|
|
77
|
+
/* @__PURE__ */ jsxs(View, { style: styles.accordionCard, children: [
|
|
78
|
+
/* @__PURE__ */ jsxs(Pressable, { onPress: onToggleResearchProcess, style: styles.accordionHeader, children: [
|
|
79
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "$sm", color: "$gray900", fontWeight: "$semibold", children: "Research Process" }),
|
|
80
|
+
/* @__PURE__ */ jsxs(View, { style: styles.accordionHeaderRight, children: [
|
|
81
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "$xs", color: "$gray600", children: query ? "1 query" : "0 query" }),
|
|
82
|
+
/* @__PURE__ */ jsx(MaterialCommunityIcons, { name: researchProcessOpen ? "chevron-up" : "chevron-down", size: 16, color: "#6b7280" })
|
|
83
|
+
] })
|
|
84
|
+
] }),
|
|
85
|
+
researchProcessOpen && /* @__PURE__ */ jsx(View, { style: styles.accordionBody, children: query ? /* @__PURE__ */ jsxs(View, { style: styles.processItem, children: [
|
|
86
|
+
/* @__PURE__ */ jsx(View, { style: [styles.processDot, {
|
|
87
|
+
backgroundColor: isStreaming ? "#f59e0b" : "#22c55e"
|
|
88
|
+
}] }),
|
|
89
|
+
/* @__PURE__ */ jsxs(View, { style: {
|
|
90
|
+
flex: 1
|
|
91
|
+
}, children: [
|
|
92
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "$sm", color: "$gray900", numberOfLines: 2, children: query }),
|
|
93
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "$xs", color: "$gray600", children: isStreaming ? "Running deep-search..." : `Completed with ${sources.length} sources` })
|
|
94
|
+
] })
|
|
95
|
+
] }) : /* @__PURE__ */ jsx(Text, { fontSize: "$sm", color: "$gray600", children: "No query started yet." }) })
|
|
96
|
+
] }),
|
|
97
|
+
/* @__PURE__ */ jsxs(View, { style: styles.accordionCard, children: [
|
|
98
|
+
/* @__PURE__ */ jsxs(Pressable, { onPress: onToggleSourcesAccordion, style: styles.accordionHeader, children: [
|
|
99
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "$sm", color: "$gray900", fontWeight: "$semibold", children: "Sources" }),
|
|
100
|
+
/* @__PURE__ */ jsxs(View, { style: styles.accordionHeaderRight, children: [
|
|
101
|
+
/* @__PURE__ */ jsxs(Text, { fontSize: "$xs", color: "$gray600", children: [
|
|
102
|
+
sources.length,
|
|
103
|
+
" sources"
|
|
104
|
+
] }),
|
|
105
|
+
/* @__PURE__ */ jsx(MaterialCommunityIcons, { name: sourcesAccordionOpen ? "chevron-up" : "chevron-down", size: 16, color: "#6b7280" })
|
|
106
|
+
] })
|
|
107
|
+
] }),
|
|
108
|
+
sourcesAccordionOpen && /* @__PURE__ */ jsx(View, { style: styles.accordionBody, children: sources.length > 0 ? sources.map((item, index) => {
|
|
109
|
+
var _a;
|
|
110
|
+
return /* @__PURE__ */ jsxs(Pressable, { onPress: () => {
|
|
111
|
+
if (item.url) {
|
|
112
|
+
void Linking.openURL(item.url);
|
|
113
|
+
}
|
|
114
|
+
}, disabled: !item.url, style: ({
|
|
115
|
+
pressed
|
|
116
|
+
}) => [styles.sourceRow, !item.url && styles.sourceRowNoLink, pressed && item.url ? styles.sourceRowPressed : void 0], children: [
|
|
117
|
+
/* @__PURE__ */ jsxs(Text, { fontSize: "$xs", color: "$green800", mb: "$1", fontWeight: "$semibold", children: [
|
|
118
|
+
index + 1,
|
|
119
|
+
". ",
|
|
120
|
+
item.title || "Source"
|
|
121
|
+
] }),
|
|
122
|
+
item.url ? /* @__PURE__ */ jsx(Text, { fontSize: "$xs", color: "$gray700", numberOfLines: 1, children: item.url }) : /* @__PURE__ */ jsx(Text, { fontSize: "$xs", color: "$gray500", numberOfLines: 1, children: "Source title detected from summary" })
|
|
123
|
+
] }, `${(_a = item.url) != null ? _a : item.title}-${index}`);
|
|
124
|
+
}) : /* @__PURE__ */ jsx(Text, { fontSize: "$sm", color: "$gray700", children: isStreaming ? "Collecting sources..." : "No source links detected in the response." }) })
|
|
125
|
+
] })
|
|
126
|
+
] }),
|
|
127
|
+
/* @__PURE__ */ jsxs(View, { style: styles.modalActionsRow, children: [
|
|
128
|
+
isStreaming ? /* @__PURE__ */ jsx(Pressable, { onPress: onStop, style: styles.modalActionButton, children: /* @__PURE__ */ jsx(Text, { fontSize: "$sm", color: "$gray900", children: "Stop" }) }) : null,
|
|
129
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: onClose, style: styles.modalActionButton, children: /* @__PURE__ */ jsx(Text, { fontSize: "$sm", color: "$gray900", children: "Close" }) })
|
|
130
|
+
] })
|
|
131
|
+
] }) }) });
|
|
132
|
+
}
|
|
133
|
+
const styles = StyleSheet.create({
|
|
134
|
+
modalBackdrop: {
|
|
135
|
+
flex: 1,
|
|
136
|
+
backgroundColor: "rgba(15, 23, 42, 0.45)",
|
|
137
|
+
justifyContent: "center",
|
|
138
|
+
padding: 16
|
|
139
|
+
},
|
|
140
|
+
modalCard: {
|
|
141
|
+
maxHeight: "88%",
|
|
142
|
+
backgroundColor: mobileTokens.color.surface,
|
|
143
|
+
borderRadius: 18,
|
|
144
|
+
padding: 16,
|
|
145
|
+
width: "100%",
|
|
146
|
+
borderWidth: 1,
|
|
147
|
+
borderColor: mobileTokens.color.border
|
|
148
|
+
},
|
|
149
|
+
modalHeaderRow: {
|
|
150
|
+
flexDirection: "row",
|
|
151
|
+
justifyContent: "space-between",
|
|
152
|
+
alignItems: "center",
|
|
153
|
+
marginBottom: 10,
|
|
154
|
+
paddingBottom: 10,
|
|
155
|
+
borderBottomWidth: 1,
|
|
156
|
+
borderBottomColor: mobileTokens.color.border
|
|
157
|
+
},
|
|
158
|
+
modalHeaderLeft: {
|
|
159
|
+
flexDirection: "column"
|
|
160
|
+
},
|
|
161
|
+
iconButton: {
|
|
162
|
+
width: 32,
|
|
163
|
+
height: 32,
|
|
164
|
+
borderRadius: 16,
|
|
165
|
+
alignItems: "center",
|
|
166
|
+
justifyContent: "center",
|
|
167
|
+
backgroundColor: mobileTokens.color.surfaceMuted
|
|
168
|
+
},
|
|
169
|
+
modalBody: {
|
|
170
|
+
flexGrow: 1,
|
|
171
|
+
minHeight: 140,
|
|
172
|
+
marginBottom: 10
|
|
173
|
+
},
|
|
174
|
+
modalBodyContent: {
|
|
175
|
+
paddingBottom: 8
|
|
176
|
+
},
|
|
177
|
+
summaryCard: {
|
|
178
|
+
backgroundColor: mobileTokens.color.surfaceMuted,
|
|
179
|
+
borderWidth: 1,
|
|
180
|
+
borderColor: mobileTokens.color.border,
|
|
181
|
+
borderRadius: 14,
|
|
182
|
+
padding: 12,
|
|
183
|
+
marginBottom: 10
|
|
184
|
+
},
|
|
185
|
+
summaryActionRow: {
|
|
186
|
+
marginTop: 8,
|
|
187
|
+
borderTopWidth: 1,
|
|
188
|
+
borderTopColor: "#e5e7eb",
|
|
189
|
+
paddingTop: 8,
|
|
190
|
+
flexDirection: "row",
|
|
191
|
+
justifyContent: "flex-start",
|
|
192
|
+
gap: 8
|
|
193
|
+
},
|
|
194
|
+
summaryActionButton: {
|
|
195
|
+
paddingVertical: 6,
|
|
196
|
+
paddingHorizontal: 12,
|
|
197
|
+
borderRadius: 10,
|
|
198
|
+
backgroundColor: mobileTokens.color.surface,
|
|
199
|
+
borderWidth: 1,
|
|
200
|
+
borderColor: mobileTokens.color.border
|
|
201
|
+
},
|
|
202
|
+
summaryActionDisabled: {
|
|
203
|
+
opacity: 0.5
|
|
204
|
+
},
|
|
205
|
+
accordionCard: {
|
|
206
|
+
backgroundColor: mobileTokens.color.surface,
|
|
207
|
+
borderWidth: 1,
|
|
208
|
+
borderColor: mobileTokens.color.border,
|
|
209
|
+
borderRadius: 12,
|
|
210
|
+
marginBottom: 10,
|
|
211
|
+
overflow: "hidden"
|
|
212
|
+
},
|
|
213
|
+
accordionHeader: {
|
|
214
|
+
paddingHorizontal: 10,
|
|
215
|
+
paddingVertical: 10,
|
|
216
|
+
flexDirection: "row",
|
|
217
|
+
justifyContent: "space-between",
|
|
218
|
+
alignItems: "center"
|
|
219
|
+
},
|
|
220
|
+
accordionHeaderRight: {
|
|
221
|
+
flexDirection: "row",
|
|
222
|
+
alignItems: "center",
|
|
223
|
+
gap: 6
|
|
224
|
+
},
|
|
225
|
+
accordionBody: {
|
|
226
|
+
borderTopWidth: 1,
|
|
227
|
+
borderTopColor: "#e5e7eb",
|
|
228
|
+
padding: 10
|
|
229
|
+
},
|
|
230
|
+
processItem: {
|
|
231
|
+
flexDirection: "row",
|
|
232
|
+
alignItems: "flex-start",
|
|
233
|
+
gap: 8
|
|
234
|
+
},
|
|
235
|
+
processDot: {
|
|
236
|
+
marginTop: 6,
|
|
237
|
+
width: 8,
|
|
238
|
+
height: 8,
|
|
239
|
+
borderRadius: 4
|
|
240
|
+
},
|
|
241
|
+
markdownBody: {
|
|
242
|
+
color: "#111827",
|
|
243
|
+
fontSize: 14,
|
|
244
|
+
lineHeight: 20
|
|
245
|
+
},
|
|
246
|
+
markdownHeading1: {
|
|
247
|
+
color: "#111827",
|
|
248
|
+
fontSize: 18,
|
|
249
|
+
marginTop: 6,
|
|
250
|
+
marginBottom: 6,
|
|
251
|
+
fontWeight: "700"
|
|
252
|
+
},
|
|
253
|
+
markdownHeading2: {
|
|
254
|
+
color: "#111827",
|
|
255
|
+
fontSize: 16,
|
|
256
|
+
marginTop: 6,
|
|
257
|
+
marginBottom: 6,
|
|
258
|
+
fontWeight: "700"
|
|
259
|
+
},
|
|
260
|
+
markdownHeading3: {
|
|
261
|
+
color: "#111827",
|
|
262
|
+
fontSize: 15,
|
|
263
|
+
marginTop: 6,
|
|
264
|
+
marginBottom: 6,
|
|
265
|
+
fontWeight: "700"
|
|
266
|
+
},
|
|
267
|
+
markdownParagraph: {
|
|
268
|
+
color: "#111827",
|
|
269
|
+
fontSize: 14,
|
|
270
|
+
lineHeight: 20,
|
|
271
|
+
marginTop: 2,
|
|
272
|
+
marginBottom: 8
|
|
273
|
+
},
|
|
274
|
+
markdownList: {
|
|
275
|
+
marginTop: 2,
|
|
276
|
+
marginBottom: 8
|
|
277
|
+
},
|
|
278
|
+
markdownListItem: {
|
|
279
|
+
color: "#111827",
|
|
280
|
+
fontSize: 14,
|
|
281
|
+
lineHeight: 20
|
|
282
|
+
},
|
|
283
|
+
markdownLink: {
|
|
284
|
+
color: "#166534",
|
|
285
|
+
textDecorationLine: "underline"
|
|
286
|
+
},
|
|
287
|
+
markdownBlockquote: {
|
|
288
|
+
borderLeftColor: "#d1d5db",
|
|
289
|
+
borderLeftWidth: 3,
|
|
290
|
+
paddingLeft: 8,
|
|
291
|
+
color: "#4b5563"
|
|
292
|
+
},
|
|
293
|
+
markdownInlineCode: {
|
|
294
|
+
backgroundColor: "#f3f4f6",
|
|
295
|
+
color: "#111827",
|
|
296
|
+
paddingHorizontal: 4,
|
|
297
|
+
borderRadius: 4
|
|
298
|
+
},
|
|
299
|
+
markdownCodeBlock: {
|
|
300
|
+
backgroundColor: "#f3f4f6",
|
|
301
|
+
color: "#111827",
|
|
302
|
+
padding: 8,
|
|
303
|
+
borderRadius: 6
|
|
304
|
+
},
|
|
305
|
+
sourceRow: {
|
|
306
|
+
backgroundColor: mobileTokens.color.surface,
|
|
307
|
+
borderWidth: 1,
|
|
308
|
+
borderColor: mobileTokens.color.border,
|
|
309
|
+
borderRadius: 10,
|
|
310
|
+
padding: 10,
|
|
311
|
+
marginBottom: 6
|
|
312
|
+
},
|
|
313
|
+
sourceRowPressed: {
|
|
314
|
+
opacity: 0.7
|
|
315
|
+
},
|
|
316
|
+
sourceRowNoLink: {
|
|
317
|
+
backgroundColor: "#f3f4f6"
|
|
318
|
+
},
|
|
319
|
+
modalActionsRow: {
|
|
320
|
+
marginTop: 12,
|
|
321
|
+
flexDirection: "row",
|
|
322
|
+
justifyContent: "flex-end",
|
|
323
|
+
gap: 10
|
|
324
|
+
},
|
|
325
|
+
modalActionButton: {
|
|
326
|
+
minHeight: 38,
|
|
327
|
+
paddingVertical: 8,
|
|
328
|
+
paddingHorizontal: 16,
|
|
329
|
+
borderRadius: 11,
|
|
330
|
+
backgroundColor: mobileTokens.color.surfaceMuted,
|
|
331
|
+
borderWidth: 1,
|
|
332
|
+
borderColor: mobileTokens.color.border,
|
|
333
|
+
justifyContent: "center"
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
const markdownStyles = {
|
|
337
|
+
body: styles.markdownBody,
|
|
338
|
+
heading1: styles.markdownHeading1,
|
|
339
|
+
heading2: styles.markdownHeading2,
|
|
340
|
+
heading3: styles.markdownHeading3,
|
|
341
|
+
bullet_list: styles.markdownList,
|
|
342
|
+
ordered_list: styles.markdownList,
|
|
343
|
+
list_item: styles.markdownListItem,
|
|
344
|
+
link: styles.markdownLink,
|
|
345
|
+
paragraph: styles.markdownParagraph,
|
|
346
|
+
blockquote: styles.markdownBlockquote,
|
|
347
|
+
code_inline: styles.markdownInlineCode,
|
|
348
|
+
code_block: styles.markdownCodeBlock
|
|
349
|
+
};export{DeepSearchModal as default};//# sourceMappingURL=DeepSearchModal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeepSearchModal.js","sources":["../../../../src/screens/Home/components/DeepSearchModal.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef } from 'react';\nimport {\n ActivityIndicator,\n Modal,\n Pressable,\n ScrollView,\n Share,\n StyleSheet,\n View,\n useWindowDimensions,\n} from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { Text } from '@admin-layout/gluestack-ui-mobile';\nimport Markdown from 'react-native-markdown-display';\nimport { Linking } from 'react-native';\nimport type { DeepSearchSourceItem } from '../deepSearchUtils';\nimport { mobileTokens } from '../../../theme/mobileTokens';\n\ninterface DeepSearchModalProps {\n visible: boolean;\n query: string | null;\n summaryText: string;\n sources: DeepSearchSourceItem[];\n isStreaming: boolean;\n researchProcessOpen: boolean;\n sourcesAccordionOpen: boolean;\n onToggleResearchProcess: () => void;\n onToggleSourcesAccordion: () => void;\n onRetry: () => void;\n onStop: () => void;\n onClose: () => void;\n}\n\nexport default function DeepSearchModal({\n visible,\n query,\n summaryText,\n sources,\n isStreaming,\n researchProcessOpen,\n sourcesAccordionOpen,\n onToggleResearchProcess,\n onToggleSourcesAccordion,\n onRetry,\n onStop,\n onClose,\n}: DeepSearchModalProps) {\n const { width: screenWidth } = useWindowDimensions();\n const modalScrollRef = useRef<ScrollView | null>(null);\n\n const displayMarkdown = useMemo(() => {\n if (!summaryText) return '';\n const hasResearchHeading = /research summary\\s*:/i.test(summaryText);\n if (hasResearchHeading) return summaryText;\n const heading = query ? `## Research Summary: ${query}` : '## Research Summary';\n return `${heading}\\n\\n${summaryText}`;\n }, [summaryText, query]);\n\n useEffect(() => {\n if (!visible) return;\n requestAnimationFrame(() => {\n modalScrollRef.current?.scrollToEnd({ animated: true });\n });\n }, [visible, displayMarkdown, sources.length, isStreaming]);\n\n const handleShare = async () => {\n if (!summaryText) return;\n try {\n await Share.share({\n message: `${summaryText}\\n\\nQuery: ${query ?? ''}`,\n });\n } catch (error) {\n console.error('[DeepSearchModal] Failed to share summary:', error);\n }\n };\n\n return (\n <Modal visible={visible} transparent animationType=\"fade\" onRequestClose={onClose}>\n <View style={styles.modalBackdrop}>\n <View style={[styles.modalCard, { width: Math.min(760, screenWidth - 24) }]}>\n <View style={styles.modalHeaderRow}>\n <View style={styles.modalHeaderLeft}>\n <Text fontSize=\"$md\" fontWeight=\"$semibold\" color=\"$gray900\">\n Deep Search\n </Text>\n {isStreaming ? (\n <Text fontSize=\"$xs\" color=\"$gray600\">\n Running...\n </Text>\n ) : null}\n </View>\n <Pressable onPress={onClose} style={styles.iconButton}>\n <MaterialCommunityIcons name=\"close\" size={18} color=\"#6b7280\" />\n </Pressable>\n </View>\n <ScrollView\n ref={modalScrollRef}\n style={styles.modalBody}\n contentContainerStyle={styles.modalBodyContent}\n nestedScrollEnabled\n keyboardShouldPersistTaps=\"handled\"\n showsVerticalScrollIndicator\n onContentSizeChange={() => {\n modalScrollRef.current?.scrollToEnd({ animated: true });\n }}\n >\n <View style={styles.summaryCard}>\n {(displayMarkdown || (isStreaming ? 'Researching...' : '')).length > 0 ? (\n <Markdown\n style={markdownStyles}\n onLinkPress={(url) => {\n void Linking.openURL(url);\n return true;\n }}\n >\n {displayMarkdown}\n </Markdown>\n ) : (\n <Text fontSize=\"$sm\" color=\"$gray700\">\n No summary yet.\n </Text>\n )}\n <View style={styles.summaryActionRow}>\n <Pressable onPress={handleShare} style={styles.summaryActionButton}>\n <Text fontSize=\"$xs\" color=\"$gray900\">\n Share\n </Text>\n </Pressable>\n <Pressable\n onPress={onRetry}\n disabled={isStreaming || !query}\n style={({ pressed }) => [\n styles.summaryActionButton,\n (isStreaming || !query) && styles.summaryActionDisabled,\n pressed && styles.sourceRowPressed,\n ]}\n >\n <Text fontSize=\"$xs\" color=\"$gray900\">\n Retry\n </Text>\n </Pressable>\n </View>\n </View>\n\n <View style={styles.accordionCard}>\n <Pressable onPress={onToggleResearchProcess} style={styles.accordionHeader}>\n <Text fontSize=\"$sm\" color=\"$gray900\" fontWeight=\"$semibold\">\n Research Process\n </Text>\n <View style={styles.accordionHeaderRight}>\n <Text fontSize=\"$xs\" color=\"$gray600\">\n {query ? '1 query' : '0 query'}\n </Text>\n <MaterialCommunityIcons\n name={researchProcessOpen ? 'chevron-up' : 'chevron-down'}\n size={16}\n color=\"#6b7280\"\n />\n </View>\n </Pressable>\n {researchProcessOpen && (\n <View style={styles.accordionBody}>\n {query ? (\n <View style={styles.processItem}>\n <View\n style={[\n styles.processDot,\n { backgroundColor: isStreaming ? '#f59e0b' : '#22c55e' },\n ]}\n />\n <View style={{ flex: 1 }}>\n <Text fontSize=\"$sm\" color=\"$gray900\" numberOfLines={2}>\n {query}\n </Text>\n <Text fontSize=\"$xs\" color=\"$gray600\">\n {isStreaming\n ? 'Running deep-search...'\n : `Completed with ${sources.length} sources`}\n </Text>\n </View>\n </View>\n ) : (\n <Text fontSize=\"$sm\" color=\"$gray600\">\n No query started yet.\n </Text>\n )}\n </View>\n )}\n </View>\n\n <View style={styles.accordionCard}>\n <Pressable onPress={onToggleSourcesAccordion} style={styles.accordionHeader}>\n <Text fontSize=\"$sm\" color=\"$gray900\" fontWeight=\"$semibold\">\n Sources\n </Text>\n <View style={styles.accordionHeaderRight}>\n <Text fontSize=\"$xs\" color=\"$gray600\">\n {sources.length} sources\n </Text>\n <MaterialCommunityIcons\n name={sourcesAccordionOpen ? 'chevron-up' : 'chevron-down'}\n size={16}\n color=\"#6b7280\"\n />\n </View>\n </Pressable>\n {sourcesAccordionOpen && (\n <View style={styles.accordionBody}>\n {sources.length > 0 ? (\n sources.map((item, index) => (\n <Pressable\n key={`${item.url ?? item.title}-${index}`}\n onPress={() => {\n if (item.url) {\n void Linking.openURL(item.url);\n }\n }}\n disabled={!item.url}\n style={({ pressed }) => [\n styles.sourceRow,\n !item.url && styles.sourceRowNoLink,\n pressed && item.url ? styles.sourceRowPressed : undefined,\n ]}\n >\n <Text fontSize=\"$xs\" color=\"$green800\" mb=\"$1\" fontWeight=\"$semibold\">\n {index + 1}. {item.title || 'Source'}\n </Text>\n {item.url ? (\n <Text fontSize=\"$xs\" color=\"$gray700\" numberOfLines={1}>\n {item.url}\n </Text>\n ) : (\n <Text fontSize=\"$xs\" color=\"$gray500\" numberOfLines={1}>\n Source title detected from summary\n </Text>\n )}\n </Pressable>\n ))\n ) : (\n <Text fontSize=\"$sm\" color=\"$gray700\">\n {isStreaming\n ? 'Collecting sources...'\n : 'No source links detected in the response.'}\n </Text>\n )}\n </View>\n )}\n </View>\n </ScrollView>\n <View style={styles.modalActionsRow}>\n {isStreaming ? (\n <Pressable onPress={onStop} style={styles.modalActionButton}>\n <Text fontSize=\"$sm\" color=\"$gray900\">\n Stop\n </Text>\n </Pressable>\n ) : null}\n <Pressable onPress={onClose} style={styles.modalActionButton}>\n <Text fontSize=\"$sm\" color=\"$gray900\">\n Close\n </Text>\n </Pressable>\n </View>\n </View>\n </View>\n </Modal>\n );\n}\n\nconst styles = StyleSheet.create({\n modalBackdrop: {\n flex: 1,\n backgroundColor: 'rgba(15, 23, 42, 0.45)',\n justifyContent: 'center',\n padding: 16,\n },\n modalCard: {\n maxHeight: '88%',\n backgroundColor: mobileTokens.color.surface,\n borderRadius: 18,\n padding: 16,\n width: '100%',\n borderWidth: 1,\n borderColor: mobileTokens.color.border,\n },\n modalHeaderRow: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: 10,\n paddingBottom: 10,\n borderBottomWidth: 1,\n borderBottomColor: mobileTokens.color.border,\n },\n modalHeaderLeft: {\n flexDirection: 'column',\n },\n iconButton: {\n width: 32,\n height: 32,\n borderRadius: 16,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: mobileTokens.color.surfaceMuted,\n },\n modalBody: {\n flexGrow: 1,\n minHeight: 140,\n marginBottom: 10,\n },\n modalBodyContent: {\n paddingBottom: 8,\n },\n summaryCard: {\n backgroundColor: mobileTokens.color.surfaceMuted,\n borderWidth: 1,\n borderColor: mobileTokens.color.border,\n borderRadius: 14,\n padding: 12,\n marginBottom: 10,\n },\n summaryActionRow: {\n marginTop: 8,\n borderTopWidth: 1,\n borderTopColor: '#e5e7eb',\n paddingTop: 8,\n flexDirection: 'row',\n justifyContent: 'flex-start',\n gap: 8,\n },\n summaryActionButton: {\n paddingVertical: 6,\n paddingHorizontal: 12,\n borderRadius: 10,\n backgroundColor: mobileTokens.color.surface,\n borderWidth: 1,\n borderColor: mobileTokens.color.border,\n },\n summaryActionDisabled: {\n opacity: 0.5,\n },\n accordionCard: {\n backgroundColor: mobileTokens.color.surface,\n borderWidth: 1,\n borderColor: mobileTokens.color.border,\n borderRadius: 12,\n marginBottom: 10,\n overflow: 'hidden',\n },\n accordionHeader: {\n paddingHorizontal: 10,\n paddingVertical: 10,\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n },\n accordionHeaderRight: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 6,\n },\n accordionBody: {\n borderTopWidth: 1,\n borderTopColor: '#e5e7eb',\n padding: 10,\n },\n processItem: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: 8,\n },\n processDot: {\n marginTop: 6,\n width: 8,\n height: 8,\n borderRadius: 4,\n },\n markdownBody: {\n color: '#111827',\n fontSize: 14,\n lineHeight: 20,\n },\n markdownHeading1: {\n color: '#111827',\n fontSize: 18,\n marginTop: 6,\n marginBottom: 6,\n fontWeight: '700',\n },\n markdownHeading2: {\n color: '#111827',\n fontSize: 16,\n marginTop: 6,\n marginBottom: 6,\n fontWeight: '700',\n },\n markdownHeading3: {\n color: '#111827',\n fontSize: 15,\n marginTop: 6,\n marginBottom: 6,\n fontWeight: '700',\n },\n markdownParagraph: {\n color: '#111827',\n fontSize: 14,\n lineHeight: 20,\n marginTop: 2,\n marginBottom: 8,\n },\n markdownList: {\n marginTop: 2,\n marginBottom: 8,\n },\n markdownListItem: {\n color: '#111827',\n fontSize: 14,\n lineHeight: 20,\n },\n markdownLink: {\n color: '#166534',\n textDecorationLine: 'underline',\n },\n markdownBlockquote: {\n borderLeftColor: '#d1d5db',\n borderLeftWidth: 3,\n paddingLeft: 8,\n color: '#4b5563',\n },\n markdownInlineCode: {\n backgroundColor: '#f3f4f6',\n color: '#111827',\n paddingHorizontal: 4,\n borderRadius: 4,\n },\n markdownCodeBlock: {\n backgroundColor: '#f3f4f6',\n color: '#111827',\n padding: 8,\n borderRadius: 6,\n },\n sourceRow: {\n backgroundColor: mobileTokens.color.surface,\n borderWidth: 1,\n borderColor: mobileTokens.color.border,\n borderRadius: 10,\n padding: 10,\n marginBottom: 6,\n },\n sourceRowPressed: {\n opacity: 0.7,\n },\n sourceRowNoLink: {\n backgroundColor: '#f3f4f6',\n },\n modalActionsRow: {\n marginTop: 12,\n flexDirection: 'row',\n justifyContent: 'flex-end',\n gap: 10,\n },\n modalActionButton: {\n minHeight: 38,\n paddingVertical: 8,\n paddingHorizontal: 16,\n borderRadius: 11,\n backgroundColor: mobileTokens.color.surfaceMuted,\n borderWidth: 1,\n borderColor: mobileTokens.color.border,\n justifyContent: 'center',\n },\n});\n\nconst markdownStyles = {\n body: styles.markdownBody,\n heading1: styles.markdownHeading1,\n heading2: styles.markdownHeading2,\n heading3: styles.markdownHeading3,\n bullet_list: styles.markdownList,\n ordered_list: styles.markdownList,\n list_item: styles.markdownListItem,\n link: styles.markdownLink,\n paragraph: styles.markdownParagraph,\n blockquote: styles.markdownBlockquote,\n code_inline: styles.markdownInlineCode,\n code_block: styles.markdownCodeBlock,\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
function normalizeSummaryText(content) {
|
|
2
|
+
return content.replace(/\r\n/g, "\n").trim();
|
|
3
|
+
}
|
|
4
|
+
function extractDeepSearchSources(content) {
|
|
5
|
+
const markdownLinks = Array.from(content.matchAll(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g)).map((m) => ({
|
|
6
|
+
title: m[1].trim(),
|
|
7
|
+
url: m[2].trim()
|
|
8
|
+
}));
|
|
9
|
+
const plainUrls = Array.from(content.matchAll(/https?:\/\/[^\s)]+/g)).map((m) => ({
|
|
10
|
+
title: "Source",
|
|
11
|
+
url: m[0].trim()
|
|
12
|
+
}));
|
|
13
|
+
const numberedTitleLines = content.split("\n").map((line) => line.trim()).filter((line) => /^\d+\.\s+/.test(line)).map((line) => ({
|
|
14
|
+
title: line.replace(/^\d+\.\s+/, "").trim(),
|
|
15
|
+
url: void 0
|
|
16
|
+
}));
|
|
17
|
+
const merged = [...markdownLinks, ...plainUrls, ...numberedTitleLines];
|
|
18
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19
|
+
const seenTitleOnly = /* @__PURE__ */ new Set();
|
|
20
|
+
const unique = [];
|
|
21
|
+
for (const item of merged) {
|
|
22
|
+
let isUnique = false;
|
|
23
|
+
if (item.url) {
|
|
24
|
+
if (!seen.has(item.url)) {
|
|
25
|
+
seen.add(item.url);
|
|
26
|
+
isUnique = true;
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
const normalizedTitle = item.title.toLowerCase();
|
|
30
|
+
if (normalizedTitle && !seenTitleOnly.has(normalizedTitle)) {
|
|
31
|
+
seenTitleOnly.add(normalizedTitle);
|
|
32
|
+
isUnique = true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (isUnique) {
|
|
36
|
+
unique.push(item);
|
|
37
|
+
if (unique.length >= 30) break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return unique;
|
|
41
|
+
}export{extractDeepSearchSources,normalizeSummaryText};//# sourceMappingURL=deepSearchUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepSearchUtils.js","sources":["../../../src/screens/Home/deepSearchUtils.ts"],"sourcesContent":["export interface DeepSearchSourceItem {\n title: string;\n url?: string;\n}\n\nexport function normalizeSummaryText(content: string): string {\n return content.replace(/\\r\\n/g, '\\n').trim();\n}\n\nexport function extractDeepSearchSources(content: string): DeepSearchSourceItem[] {\n const markdownLinks = Array.from(content.matchAll(/\\[([^\\]]+)\\]\\((https?:\\/\\/[^\\s)]+)\\)/g)).map((m) => ({\n title: m[1].trim(),\n url: m[2].trim(),\n }));\n const plainUrls = Array.from(content.matchAll(/https?:\\/\\/[^\\s)]+/g)).map((m) => ({\n title: 'Source',\n url: m[0].trim(),\n }));\n const numberedTitleLines = content\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => /^\\d+\\.\\s+/.test(line))\n .map((line) => ({\n title: line.replace(/^\\d+\\.\\s+/, '').trim(),\n url: undefined as string | undefined,\n }));\n\n const merged = [...markdownLinks, ...plainUrls, ...numberedTitleLines];\n const seen = new Set<string>();\n const seenTitleOnly = new Set<string>();\n const unique: DeepSearchSourceItem[] = [];\n\n for (const item of merged) {\n let isUnique = false;\n if (item.url) {\n if (!seen.has(item.url)) {\n seen.add(item.url);\n isUnique = true;\n }\n } else {\n const normalizedTitle = item.title.toLowerCase();\n if (normalizedTitle && !seenTitleOnly.has(normalizedTitle)) {\n seenTitleOnly.add(normalizedTitle);\n isUnique = true;\n }\n }\n if (isUnique) {\n unique.push(item);\n if (unique.length >= 30) break;\n }\n }\n return unique;\n}\n"],"names":[],"mappings":"AAIO,SAAS,qBAAqB,OAAyB,EAAA;AAC5D,EAAA,OAAO,OAAQ,CAAA,OAAA,CAAQ,OAAS,EAAA,IAAI,EAAE,IAAK,EAAA;AAC7C;AACO,SAAS,yBAAyB,OAAyC,EAAA;AAChF,EAAM,MAAA,aAAA,GAAgB,MAAM,IAAK,CAAA,OAAA,CAAQ,SAAS,uCAAuC,CAAC,CAAE,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,IACpG,KAAO,EAAA,CAAA,CAAE,CAAC,CAAA,CAAE,IAAK,EAAA;AAAA,IACjB,GAAK,EAAA,CAAA,CAAE,CAAC,CAAA,CAAE,IAAK;AAAA,GACf,CAAA,CAAA;AACF,EAAM,MAAA,SAAA,GAAY,MAAM,IAAK,CAAA,OAAA,CAAQ,SAAS,qBAAqB,CAAC,CAAE,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,IAC9E,KAAO,EAAA,QAAA;AAAA,IACP,GAAK,EAAA,CAAA,CAAE,CAAC,CAAA,CAAE,IAAK;AAAA,GACf,CAAA,CAAA;AACF,EAAA,MAAM,qBAAqB,OAAQ,CAAA,KAAA,CAAM,IAAI,CAAE,CAAA,GAAA,CAAI,UAAQ,IAAK,CAAA,IAAA,EAAM,CAAE,CAAA,MAAA,CAAO,UAAQ,WAAY,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,IAAI,CAAS,IAAA,MAAA;AAAA,IAC1H,OAAO,IAAK,CAAA,OAAA,CAAQ,WAAa,EAAA,EAAE,EAAE,IAAK,EAAA;AAAA,IAC1C,GAAK,EAAA;AAAA,GACL,CAAA,CAAA;AACF,EAAA,MAAM,SAAS,CAAC,GAAG,eAAe,GAAG,SAAA,EAAW,GAAG,kBAAkB,CAAA;AACrE,EAAM,MAAA,IAAA,uBAAW,GAAY,EAAA;AAC7B,EAAM,MAAA,aAAA,uBAAoB,GAAY,EAAA;AACtC,EAAA,MAAM,SAAiC,EAAC;AACxC,EAAA,KAAA,MAAW,QAAQ,MAAQ,EAAA;AACzB,IAAA,IAAI,QAAW,GAAA,KAAA;AACf,IAAA,IAAI,KAAK,GAAK,EAAA;AACZ,MAAA,IAAI,CAAC,IAAA,CAAK,GAAI,CAAA,IAAA,CAAK,GAAG,CAAG,EAAA;AACvB,QAAK,IAAA,CAAA,GAAA,CAAI,KAAK,GAAG,CAAA;AACjB,QAAW,QAAA,GAAA,IAAA;AAAA;AACb,KACK,MAAA;AACL,MAAM,MAAA,eAAA,GAAkB,IAAK,CAAA,KAAA,CAAM,WAAY,EAAA;AAC/C,MAAA,IAAI,eAAmB,IAAA,CAAC,aAAc,CAAA,GAAA,CAAI,eAAe,CAAG,EAAA;AAC1D,QAAA,aAAA,CAAc,IAAI,eAAe,CAAA;AACjC,QAAW,QAAA,GAAA,IAAA;AAAA;AACb;AAEF,IAAA,IAAI,QAAU,EAAA;AACZ,MAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAChB,MAAI,IAAA,MAAA,CAAO,UAAU,EAAI,EAAA;AAAA;AAC3B;AAEF,EAAO,OAAA,MAAA;AACT"}
|