Improve fork and rewind actions (#1336)

This commit is contained in:
SSU-WEI HUANG
2026-08-03 12:33:06 +08:00
committed by GitHub
parent cc39021abc
commit cd570adf66
3 changed files with 47 additions and 5 deletions
@@ -140,6 +140,23 @@ describe('MessageActions', () => {
expect(screen.queryByRole('button', { name: 'Rewind' })).toBeNull() expect(screen.queryByRole('button', { name: 'Rewind' })).toBeNull()
}) })
it('renders Fork and Rewind as compact icon actions', () => {
renderActions({
align: 'end',
copyText: 'body',
showFork: true,
showRewind: true,
onFork: async () => {},
onRewind: async () => {}
})
for (const name of ['Fork', 'Rewind']) {
const button = screen.getByRole('button', { name })
expect(button.className.split(' ')).toContain('w-5')
expect(button.querySelector('svg')).not.toBeNull()
}
})
it('shows Fork confirm dialog and calls onFork only after confirm', async () => { it('shows Fork confirm dialog and calls onFork only after confirm', async () => {
const onFork = vi.fn(async () => {}) const onFork = vi.fn(async () => {})
renderActions({ align: 'start', copyText: 'body', showFork: true, onFork }) renderActions({ align: 'start', copyText: 'body', showFork: true, onFork })
@@ -1,7 +1,7 @@
import * as Popover from '@radix-ui/react-popover' import * as Popover from '@radix-ui/react-popover'
import { useState } from 'react' import { useState } from 'react'
import { useAuiState } from '@assistant-ui/react' import { useAuiState } from '@assistant-ui/react'
import { CheckIcon, CopyIcon, InfoIcon } from '@/components/icons' import { CheckIcon, CopyIcon, ForkIcon, InfoIcon, RewindIcon } from '@/components/icons'
import { useCopyToClipboard } from '@/hooks/useCopyToClipboard' import { useCopyToClipboard } from '@/hooks/useCopyToClipboard'
import { useTranslation } from '@/lib/use-translation' import { useTranslation } from '@/lib/use-translation'
import { MessageMetadata, buildMessageMetadataLabels, type MessageMetadataProps } from './MessageMetadata' import { MessageMetadata, buildMessageMetadataLabels, type MessageMetadataProps } from './MessageMetadata'
@@ -65,10 +65,10 @@ export function MessageActions({
title={t('message.fork')} title={t('message.fork')}
aria-label={t('message.fork')} aria-label={t('message.fork')}
disabled={actionsLocked} disabled={actionsLocked}
className="flex h-5 items-center rounded px-1 text-[11px] text-[var(--app-hint)] transition-colors hover:bg-[var(--app-subtle-bg)] hover:text-[var(--app-fg)] disabled:opacity-40" className="flex h-5 w-5 items-center justify-center rounded text-[var(--app-hint)] transition-colors hover:bg-[var(--app-subtle-bg)] hover:text-[var(--app-fg)] disabled:opacity-40"
onClick={() => setForkOpen(true)} onClick={() => setForkOpen(true)}
> >
{t('message.fork')} <ForkIcon className="h-3.5 w-3.5" />
</button> </button>
) : null} ) : null}
{showRewind && onRewind ? ( {showRewind && onRewind ? (
@@ -77,10 +77,10 @@ export function MessageActions({
title={t('message.rewind')} title={t('message.rewind')}
aria-label={t('message.rewind')} aria-label={t('message.rewind')}
disabled={actionsLocked} disabled={actionsLocked}
className="flex h-5 items-center rounded px-1 text-[11px] text-[var(--app-hint)] transition-colors hover:bg-[var(--app-subtle-bg)] hover:text-[var(--app-fg)] disabled:opacity-40" className="flex h-5 w-5 items-center justify-center rounded text-[var(--app-hint)] transition-colors hover:bg-[var(--app-subtle-bg)] hover:text-[var(--app-fg)] disabled:opacity-40"
onClick={() => setRewindOpen(true)} onClick={() => setRewindOpen(true)}
> >
{t('message.rewind')} <RewindIcon className="h-3.5 w-3.5" />
</button> </button>
) : null} ) : null}
</> </>
+25
View File
@@ -73,6 +73,31 @@ export function InfoIcon(props: IconProps) {
) )
} }
export function ForkIcon(props: IconProps) {
return createIcon(
<>
<circle cx="6" cy="4" r="1.5" />
<circle cx="18" cy="4" r="1.5" />
<circle cx="18" cy="20" r="1.5" />
<path d="M6 5.5v4.75A5.75 5.75 0 0 0 11.75 16H16.5" />
<path d="M12 16a5.75 5.75 0 0 0 5.75-5.75V5.5" />
</>,
props,
2
)
}
export function RewindIcon(props: IconProps) {
return createIcon(
<>
<path d="M3 12a9 9 0 1 0 3-6.7" />
<polyline points="3 4 3 10 9 10" />
</>,
props,
2
)
}
/** Composer schedule-send clock — circle + hands (matches ComposerButtons). */ /** Composer schedule-send clock — circle + hands (matches ComposerButtons). */
export function ScheduleIcon(props: IconProps) { export function ScheduleIcon(props: IconProps) {
return createIcon( return createIcon(