mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
fix(desktop): remove hidden chat action hover strip #642
The previous fix moved the hover group onto the message shell, but the action row still occupied layout space while invisible. That invisible row kept expanding the shell hit area, so moving the pointer into the empty metadata strip could still reveal copy and timestamp controls. Collapse the action row to zero height by default and expand it only while the message shell is hovered or focused. Keep message content spacing separate from the action row so hidden controls do not create a hover target. Constraint: Copy/fork controls must remain reachable after the bubble reveals them. Rejected: Use display:none for the action row | would remove the keyboard focus path entirely. Confidence: high Scope-risk: narrow Directive: Keep hidden message metadata rows out of normal hover hit-testing; do not reintroduce invisible layout space around chat bubbles. Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx --run -t "keeps user actions anchored" Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx --run Tested: cd desktop && bun run test src/components/chat/UserMessage.test.tsx --run Tested: bun run check:desktop Tested: git diff --check Not-tested: Live Tauri native hover smoke Related: #642
This commit is contained in:
parent
9b3e58b60b
commit
0ab624bff4
@ -68,7 +68,7 @@ export const AssistantMessage = memo(function AssistantMessage({ content, isStre
|
||||
<div
|
||||
data-message-shell="assistant"
|
||||
data-layout={documentLayout ? 'document' : 'bubble'}
|
||||
className={`group flex min-w-0 flex-col items-start gap-2 ${
|
||||
className={`group flex min-w-0 flex-col items-start ${
|
||||
documentLayout
|
||||
? 'w-full max-w-full'
|
||||
: 'max-w-[88%] sm:max-w-[80%] lg:max-w-[72%]'
|
||||
|
||||
@ -41,7 +41,7 @@ export function MessageActionBar({
|
||||
<div
|
||||
data-message-actions
|
||||
data-align={align}
|
||||
className={`invisible flex w-full opacity-0 transition-opacity duration-150 group-hover:visible group-hover:opacity-100 group-focus-within:visible group-focus-within:opacity-100 ${
|
||||
className={`pointer-events-none mt-0 flex h-0 w-full overflow-hidden opacity-0 transition-[height,margin-top,opacity] duration-150 group-hover:pointer-events-auto group-hover:mt-2 group-hover:h-7 group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:mt-2 group-focus-within:h-7 group-focus-within:opacity-100 ${
|
||||
align === 'end' ? 'justify-end' : 'justify-start'
|
||||
}`}
|
||||
>
|
||||
|
||||
@ -2743,8 +2743,9 @@ describe('MessageList nested tool calls', () => {
|
||||
expect(assistantShell?.className).not.toContain('ml-10')
|
||||
expect(userActions?.getAttribute('data-align')).toBe('end')
|
||||
expect(assistantActions?.getAttribute('data-align')).toBe('start')
|
||||
expect(userActions?.className).toContain('invisible')
|
||||
expect(userActions?.className).toContain('group-hover:visible')
|
||||
expect(userActions?.className).toContain('h-0')
|
||||
expect(userActions?.className).toContain('group-hover:h-7')
|
||||
expect(userActions?.className).not.toContain('invisible')
|
||||
expect(within(userActions as HTMLElement).getByText('5m ago')).toBeTruthy()
|
||||
expect(within(assistantActions as HTMLElement).getByText('2h ago')).toBeTruthy()
|
||||
})
|
||||
|
||||
@ -17,24 +17,26 @@ export const UserMessage = memo(function UserMessage({ content, attachments, bra
|
||||
<div className="mb-5 flex justify-end">
|
||||
<div
|
||||
data-message-shell="user"
|
||||
className="group flex min-w-0 max-w-[82%] flex-col items-end gap-2 sm:max-w-[78%] lg:max-w-[72%]"
|
||||
className="group flex min-w-0 max-w-[82%] flex-col items-end sm:max-w-[78%] lg:max-w-[72%]"
|
||||
>
|
||||
{attachments && attachments.length > 0 && (
|
||||
<AttachmentGallery attachments={attachments} variant="message" />
|
||||
)}
|
||||
<div className="flex max-w-full flex-col items-end gap-2">
|
||||
{attachments && attachments.length > 0 && (
|
||||
<AttachmentGallery attachments={attachments} variant="message" />
|
||||
)}
|
||||
|
||||
{hasText && (
|
||||
<div
|
||||
className="min-w-0 max-w-full bg-[var(--color-surface-user-msg)] px-4 py-3 text-sm leading-relaxed text-[var(--color-text-primary)] whitespace-pre-wrap break-words"
|
||||
style={{
|
||||
borderRadius: '18px 4px 18px 18px',
|
||||
overflowWrap: 'anywhere',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
)}
|
||||
{hasText && (
|
||||
<div
|
||||
className="min-w-0 max-w-full bg-[var(--color-surface-user-msg)] px-4 py-3 text-sm leading-relaxed text-[var(--color-text-primary)] whitespace-pre-wrap break-words"
|
||||
style={{
|
||||
borderRadius: '18px 4px 18px 18px',
|
||||
overflowWrap: 'anywhere',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasText && (
|
||||
<MessageActionBar
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user