diff --git a/app/actions.tsx b/app/actions.tsx index 6617ab64..852bc9e3 100644 --- a/app/actions.tsx +++ b/app/actions.tsx @@ -32,6 +32,25 @@ type RelatedQueries = { }; // Removed mcp parameter from submit, as geospatialTool now handles its client. +async function hideMessage(messageId: string) { + 'use server' + + const aiState = getMutableAIState() + + aiState.update({ + ...aiState.get(), + messages: aiState.get().messages.map(msg => { + if (msg.id === messageId) { + return { + ...msg, + isHidden: true + } + } + return msg + }) + }) +} + async function submit(formData?: FormData, skip?: boolean) { 'use server'; @@ -272,6 +291,7 @@ const initialUIState: UIState = []; export const AI = createAI({ actions: { submit, + hideMessage, }, initialUIState, initialAIState, @@ -344,6 +364,7 @@ export const getUIStateFromAIState = (aiState: AIState): UIState => { const chatId = aiState.chatId; const isSharePage = aiState.isSharePage; return aiState.messages + .filter(message => !message.isHidden) .map((message, index) => { const { role, content, id, type, name } = message; diff --git a/bun.lockb b/bun.lockb index d24d91ca..f00171e2 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/components/chat-messages.tsx b/components/chat-messages.tsx index 6bfa3642..aeda64e5 100644 --- a/components/chat-messages.tsx +++ b/components/chat-messages.tsx @@ -3,6 +3,7 @@ import { StreamableValue, useUIState } from 'ai/rsc' import type { AI, UIState } from '@/app/actions' import { CollapsibleMessage } from './collapsible-message' +import { SwipeableMessage } from './swipeable-message' interface ChatMessagesProps { messages: UIState @@ -50,19 +51,24 @@ export function ChatMessages({ messages }: ChatMessagesProps) { }, index ) => ( - ( -
{component}
- )), - isCollapsed: groupedMessage.isCollapsed - }} - isLastMessage={ - groupedMessage.id === messages[messages.length - 1].id - } - /> + + ( +
{component}
+ )), + isCollapsed: groupedMessage.isCollapsed + }} + isLastMessage={ + groupedMessage.id === messages[messages.length - 1].id + } + /> +
) )} diff --git a/components/swipeable-message.tsx b/components/swipeable-message.tsx new file mode 100644 index 00000000..ea4b6660 --- /dev/null +++ b/components/swipeable-message.tsx @@ -0,0 +1,30 @@ +'use client' + +import { useSwipeable } from 'react-swipeable' +import { StreamableValue, useActions } from 'ai/rsc' + +interface SwipeableMessageProps { + message: { + id: string + components: React.ReactNode[] + isCollapsed?: StreamableValue + } + children: React.ReactNode +} + +export function SwipeableMessage({ + message, + children +}: SwipeableMessageProps) { + const { hideMessage } = useActions() + + const handlers = useSwipeable({ + onSwipedLeft: () => { + console.log(`Swiped left on message ${message.id}`) + hideMessage(message.id) + }, + trackMouse: true + }) + + return
{children}
+} diff --git a/lib/types/index.ts b/lib/types/index.ts index 0652e848..96023b71 100644 --- a/lib/types/index.ts +++ b/lib/types/index.ts @@ -71,4 +71,5 @@ export type AIMessage = { | 'followup' | 'end' | 'drawing_context' // Added custom type for drawing context messages + isHidden?: boolean } diff --git a/package.json b/package.json index 764140a4..39c98ec2 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "react-hook-form": "^7.56.2", "react-icons": "^5.5.0", "react-markdown": "^9.1.0", + "react-swipeable": "^7.0.2", "react-textarea-autosize": "^8.5.9", "react-toastify": "^10.0.6", "rehype-external-links": "^3.0.0",