fix(web): code review round 1 remaining UI fixes
- EmojiPanel: add missing 手势/物品 categories, 12-column grid per README §3.3
- DetailColumn: add 投诉举报 row, real ID/region/签名 via new getUserProfile
API, chevron_right icons now use --color-icon-arrow token (were tertiary
text color), regroup rows so dividers only sit between sections not every
row (matches design-code reference exactly)
- MessageBubble/ConversationView: right-clicked message bubble now gets the
spec's outline while its context menu is open
- ChatListColumn/AppShell: pinned 系统消息/文件助手 rows using confirmed
bootstrap entries/entry_badges topic names ("sys"/"slf"); route to the
existing SectionPlaceholder pattern since their own dedicated layouts are
Phase 8, not built yet
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a7da4dc079
commit
93d4077d1e
@@ -11,6 +11,7 @@ import {
|
||||
getBlocks,
|
||||
getConversationSettings,
|
||||
getFriends,
|
||||
getUserProfile,
|
||||
unblockUser,
|
||||
updateConversationSettings,
|
||||
updateFriendRemark,
|
||||
@@ -53,6 +54,11 @@ export function DetailColumn({ topicId, peerName, onClose }: DetailColumnProps)
|
||||
const friendsQuery = useQuery({ queryKey: ['friends'], queryFn: () => getFriends() });
|
||||
const friend = friendsQuery.data?.items.find((f) => f.user_id === topicId);
|
||||
|
||||
const profileQuery = useQuery({ queryKey: ['user-profile', topicId], queryFn: () => getUserProfile(topicId) });
|
||||
const idLine = [profileQuery.data?.public_account && `ID:${profileQuery.data.public_account}`, profileQuery.data?.region]
|
||||
.filter(Boolean)
|
||||
.join(' · ');
|
||||
|
||||
const settingsQuery = useQuery({
|
||||
queryKey: ['conversation-settings', topicId],
|
||||
queryFn: () => getConversationSettings(topicId),
|
||||
@@ -98,6 +104,10 @@ export function DetailColumn({ topicId, peerName, onClose }: DetailColumnProps)
|
||||
deleteFriendMutation.mutate();
|
||||
};
|
||||
|
||||
const reportAbuse = () => {
|
||||
window.alert('该功能暂未开放,如需投诉举报请联系客服。');
|
||||
};
|
||||
|
||||
return (
|
||||
<aside className="flex h-full w-full flex-none flex-col overflow-y-auto border-l border-border-panel bg-white md:w-[300px]">
|
||||
<header className="flex h-15 flex-none items-center justify-between border-b border-list-item px-5">
|
||||
@@ -109,11 +119,15 @@ export function DetailColumn({ topicId, peerName, onClose }: DetailColumnProps)
|
||||
) : null}
|
||||
</header>
|
||||
|
||||
<div className="flex flex-col items-center gap-1 px-5 pb-4 pt-6">
|
||||
<div className="flex flex-col items-center gap-1 border-b border-list-item px-5 pb-4 pt-6">
|
||||
<span className={`grid h-18 w-18 place-items-center rounded-2xl text-2xl font-medium text-white ${avatarBgClass(topicId)}`}>
|
||||
{avatarLetter(peerName)}
|
||||
</span>
|
||||
<strong className="mt-2 text-[17px] font-semibold text-text-heading">{peerName}</strong>
|
||||
{idLine ? <span className="text-xs text-text-tertiary-2">{idLine}</span> : null}
|
||||
{profileQuery.data?.signature ? (
|
||||
<p className="m-0 text-center text-[13px] text-text-secondary">{profileQuery.data.signature}</p>
|
||||
) : null}
|
||||
<div className="mt-3 flex gap-3">
|
||||
<button
|
||||
type="button"
|
||||
@@ -134,10 +148,10 @@ export function DetailColumn({ topicId, peerName, onClose }: DetailColumnProps)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="px-5 pb-3 text-sm">
|
||||
<div className="border-b border-list-item px-5 pb-3 pt-2 text-sm">
|
||||
<button type="button" onClick={() => setHistoryTab('text')} className="flex w-full items-center justify-between py-2">
|
||||
<span className="text-text-body">查找聊天记录</span>
|
||||
<Icon name="chevron_right" className="text-[18px] text-text-tertiary-2" />
|
||||
<Icon name="chevron_right" className="text-[20px] text-icon-arrow" />
|
||||
</button>
|
||||
<div className="mt-1 grid grid-cols-4 gap-2">
|
||||
{(
|
||||
@@ -156,7 +170,7 @@ export function DetailColumn({ topicId, peerName, onClose }: DetailColumnProps)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col border-t border-list-item px-5 pb-2 text-sm">
|
||||
<div className="flex flex-col border-b border-list-item px-5 text-sm">
|
||||
{remarkEditing ? (
|
||||
<div className="flex items-center gap-2 py-3">
|
||||
<span className="flex-none text-text-body">备注</span>
|
||||
@@ -181,13 +195,13 @@ export function DetailColumn({ topicId, peerName, onClose }: DetailColumnProps)
|
||||
className="flex items-center justify-between py-3 text-left"
|
||||
>
|
||||
<span className="text-text-body">备注</span>
|
||||
<span className="flex items-center gap-1 text-text-tertiary-2">
|
||||
<span className="flex items-center gap-0.5 text-[13px] text-text-tertiary-2">
|
||||
{friend?.remark || '未设置'}
|
||||
<Icon name="chevron_right" className="text-[18px]" />
|
||||
<Icon name="chevron_right" className="text-[20px] text-icon-arrow" />
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
<div className="flex items-center justify-between border-t border-list-item py-3">
|
||||
<div className="flex items-center justify-between py-3">
|
||||
<span className="text-text-body">置顶聊天</span>
|
||||
<Toggle
|
||||
checked={!!settingsQuery.data?.pinned}
|
||||
@@ -195,7 +209,7 @@ export function DetailColumn({ topicId, peerName, onClose }: DetailColumnProps)
|
||||
onChange={() => updateSettings.mutate({ pinned: !settingsQuery.data?.pinned })}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between border-t border-list-item py-3">
|
||||
<div className="flex items-center justify-between py-3">
|
||||
<span className="text-text-body">消息免打扰</span>
|
||||
<Toggle
|
||||
checked={!!settingsQuery.data?.mute_notifications}
|
||||
@@ -203,13 +217,20 @@ export function DetailColumn({ topicId, peerName, onClose }: DetailColumnProps)
|
||||
onChange={() => updateSettings.mutate({ mute_notifications: !settingsQuery.data?.mute_notifications })}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between border-t border-list-item py-3">
|
||||
<div className="flex items-center justify-between py-3">
|
||||
<span className="text-text-body">加入黑名单</span>
|
||||
<Toggle checked={isBlocked} disabled={blockMutation.isPending} onChange={() => blockMutation.mutate(!isBlocked)} />
|
||||
</div>
|
||||
<button type="button" onClick={clearHistory} className="flex items-center justify-between border-t border-list-item py-3 text-left">
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col px-5 pb-2 text-sm">
|
||||
<button type="button" onClick={clearHistory} className="flex items-center justify-between py-3 text-left">
|
||||
<span className="text-text-body">清空聊天记录</span>
|
||||
<Icon name="chevron_right" className="text-[18px] text-text-tertiary-2" />
|
||||
<Icon name="chevron_right" className="text-[20px] text-icon-arrow" />
|
||||
</button>
|
||||
<button type="button" onClick={reportAbuse} className="flex items-center justify-between py-3 text-left">
|
||||
<span className="text-text-body">投诉举报</span>
|
||||
<Icon name="chevron_right" className="text-[20px] text-icon-arrow" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user