style(chat): restyle message image thumbnails and their expired placeholder

Square the attached-image thumbnail at 100x100 (was 160x120) and give it a
fixed light-gray backdrop so a transparent PNG still shows its artwork —
fixed rather than a neutral token, since the artwork inside the file does
not invert with the theme.

The expired placeholder follows the thumbnail it stands in for: same size,
same tint, no border, lighter icon and label, and the Chinese copy breaks
where it reads best instead of wherever 100px happens to fall.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kinyoo
2026-07-29 16:11:22 +08:00
parent 1584a79365
commit ffc79496f5
3 changed files with 19 additions and 7 deletions
@@ -18,13 +18,20 @@ export function InvalidImagePlaceholder({
<div
{...rest}
className={cn(
'flex h-[120px] w-[160px] flex-col items-center justify-center gap-2 rounded-lg',
'border border-border-light bg-surface-secondary text-text-secondary',
// pt against a centered stack nudges it down by half the padding — 6px
// here, enough to sit off dead-center without looking misaligned.
'flex size-[100px] flex-col items-center justify-center gap-2 rounded-lg pt-3',
// Same tint as the thumbnail it stands in for, and no border: in a row
// of pictures the missing one should hold the place quietly rather than
// draw a frame around itself.
'bg-[#F8F8F8] text-text-3/60',
className,
)}
>
<Outlined.FileImage className="size-7 opacity-60" />
<span className="px-2 text-center text-xs leading-tight">
<Outlined.FileImage className="size-5" />
{/* pre-line so a translation can place its own break; zh splits the two
clauses onto their own lines rather than letting 100px decide. */}
<span className="whitespace-pre-line px-2 text-center text-caption leading-tight">
{localize('com_chat_image_expired')}
</span>
</div>
@@ -67,7 +67,7 @@ export function MessageImage({
return (
<div
{...debugAttrs}
className="h-[120px] w-[160px] animate-pulse rounded-lg bg-fill-2"
className="h-[100px] w-[100px] animate-pulse rounded-lg bg-[#F8F8F8]"
/>
);
}
@@ -80,7 +80,12 @@ export function MessageImage({
src={url}
alt={altText ?? ''}
onError={() => setFailed(true)}
className="h-[120px] w-[160px] cursor-pointer rounded-lg object-cover"
// A transparent PNG would otherwise sit on the page's white and lose
// its own black artwork; the tint gives it something to show against.
// Deliberately a fixed light gray rather than a neutral token: the
// artwork inside the file doesn't invert with the theme, so a backdrop
// that darkened alongside it would hide the very thing it's here for.
className="h-[100px] w-[100px] cursor-pointer rounded-lg bg-[#F8F8F8] object-cover"
/>
</Dialog.Trigger>
<DialogImage src={url} />
@@ -183,7 +183,7 @@
"com_bschoose_confirm": "确认",
"com_bschoose_confirmed": "已确认",
"com_case_featured": "$t(linsight)精选案例",
"com_chat_image_expired": "图片已失效无法查看",
"com_chat_image_expired": "图片已失效\n无法查看",
"com_chat_knowledge_empty_no_org_kbs": "暂无组织知识库",
"com_chat_knowledge_empty_no_spaces": "暂无知识空间",
"com_chat_knowledge_placeholder_search_space": "搜索知识空间名称",