({ entry }: { entry: FeedEntry })
| 68 | } |
| 69 | |
| 70 | function MessageCard({ entry }: { entry: FeedEntry }) { |
| 71 | const isPending = entry.id.startsWith('pending-'); |
| 72 | if (entry.feedType === 'user') { |
| 73 | return ( |
| 74 | <div className="ml-auto flex max-w-[58%] justify-end"> |
| 75 | <div className={[ |
| 76 | 'rounded-[18px] border border-[#E4DACB] bg-[#EFE8DD] px-4 py-3 shadow-[0_10px_28px_rgba(74,57,28,0.06)]', |
| 77 | isPending ? 'opacity-70' : '', |
| 78 | ].join(' ')}> |
| 79 | <div className="mb-1 text-[11px] text-[#9A8F80]">你</div> |
| 80 | <div className="whitespace-pre-wrap break-words text-[15px] leading-7 text-[#332C24]"> |
| 81 | {trimText(entry.content)} |
| 82 | </div> |
| 83 | </div> |
| 84 | </div> |
| 85 | ); |
| 86 | } |
| 87 | |
| 88 | if (entry.feedType === 'assistant' && entry.isError) { |
| 89 | const issue = describeIssue(entry.content); |
| 90 | |
| 91 | return ( |
| 92 | <div className="max-w-[82%]"> |
| 93 | <div className="mb-2 text-[11px] text-[#9A8F80]"> |
| 94 | 助手 |
| 95 | {entry.timestamp ? ` - ${formatTimestamp(entry.timestamp)}` : ''} |
| 96 | </div> |
| 97 | <div className={['rounded-[20px] border px-4 py-4', issueToneClass(issue.tone)].join(' ')}> |
| 98 | <div className="text-[15px] font-semibold">{issue.title}</div> |
| 99 | <div className="mt-2 text-[14px] leading-7">{issue.detail}</div> |
| 100 | </div> |
| 101 | </div> |
| 102 | ); |
| 103 | } |
| 104 | |
| 105 | return ( |
| 106 | <div className="max-w-[82%]"> |
| 107 | <div className="mb-2 text-[11px] text-[#9A8F80]"> |
| 108 | {entry.feedType === 'assistant' ? '助手' : entry.title} |
| 109 | {entry.timestamp ? ` - ${formatTimestamp(entry.timestamp)}` : ''} |
| 110 | </div> |
| 111 | <div className="whitespace-pre-wrap break-words text-[15px] leading-8 text-[#2C241C]"> |
| 112 | {trimText(entry.content)} |
| 113 | </div> |
| 114 | {entry.feedType === 'assistant' && entry.streaming ? ( |
| 115 | <div className="mt-3 flex items-center gap-2 text-[14px] italic text-[#C06B47]"> |
| 116 | <span className="h-1 w-1 rounded-full bg-current" /> |
| 117 | 正在生成…… |
| 118 | </div> |
| 119 | ) : null} |
| 120 | </div> |
| 121 | ); |
| 122 | } |
| 123 | |
| 124 | function toolIcon(name?: string) { |
| 125 | const n = (name || '').toLowerCase(); |
nothing calls this directly
no test coverage detected