Initial public release

This commit is contained in:
Bohdan Triapitsyn
2025-12-07 19:32:53 +02:00
commit 4b2edf7318
319 changed files with 81600 additions and 0 deletions
@@ -0,0 +1,95 @@
import React from 'react';
import type { Message, Part } from '@opencode-ai/sdk';
import ChatMessage from './ChatMessage';
import { PermissionCard } from './PermissionCard';
import type { Permission } from '@/types/permission';
import type { AnimationHandlers, ContentChangeReason } from '@/hooks/useChatScrollManager';
import { isFullySyntheticMessage } from '@/lib/messages/synthetic';
import { useTurnGrouping } from './hooks/useTurnGrouping';
interface MessageListProps {
messages: { info: Message; parts: Part[] }[];
permissions: Permission[];
onMessageContentChange: (reason?: ContentChangeReason) => void;
getAnimationHandlers: (messageId: string) => AnimationHandlers;
hasMoreAbove: boolean;
isLoadingOlder: boolean;
onLoadOlder: () => void;
scrollToBottom?: (options?: { instant?: boolean }) => void;
pendingAnchorId?: string | null;
}
const MessageList: React.FC<MessageListProps> = ({
messages,
permissions,
onMessageContentChange,
getAnimationHandlers,
hasMoreAbove,
isLoadingOlder,
onLoadOlder,
scrollToBottom,
pendingAnchorId,
}) => {
React.useEffect(() => {
if (permissions.length === 0) {
return;
}
onMessageContentChange('permission');
}, [permissions, onMessageContentChange]);
const displayMessages = React.useMemo(() => {
return messages.filter((message) => !isFullySyntheticMessage(message.parts));
}, [messages]);
const { getContextForMessage } = useTurnGrouping(displayMessages);
return (
<div>
{hasMoreAbove && (
<div className="flex justify-center py-3">
{isLoadingOlder ? (
<span className="text-xs uppercase tracking-wide text-muted-foreground/80">
Loading
</span>
) : (
<button
type="button"
onClick={onLoadOlder}
className="text-xs uppercase tracking-wide text-muted-foreground/80 hover:text-foreground"
>
Load older messages
</button>
)}
</div>
)}
<div className="flex flex-col">
{displayMessages.map((message, index) => (
<ChatMessage
key={message.info.id}
message={message}
previousMessage={index > 0 ? displayMessages[index - 1] : undefined}
nextMessage={index < displayMessages.length - 1 ? displayMessages[index + 1] : undefined}
onContentChange={onMessageContentChange}
animationHandlers={getAnimationHandlers(message.info.id)}
scrollToBottom={scrollToBottom}
isPendingAnchor={pendingAnchorId === message.info.id}
turnGroupingContext={getContextForMessage(message.info.id)}
/>
))}
</div>
{permissions.length > 0 && (
<div>
{permissions.map((permission) => (
<PermissionCard key={permission.id} permission={permission} />
))}
</div>
)}
</div>
);
};
export default React.memo(MessageList);