mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
refactor(web): use standard sizes for icon actions (#42684)
This commit is contained in:
20 files changed
+55
-33
No files matched your search
@@ -131,7 +131,7 @@ const SnippetInfoDropdown = ({ snippet }: SnippetInfoDropdownProps) => {
|
||||
render={
|
||||
<IconButton
|
||||
aria-label={t(($) => $['operation.more'], { ns: 'common' })}
|
||||
className="rounded-md data-popup-open:bg-state-base-hover data-popup-open:text-text-secondary"
|
||||
className="data-popup-open:bg-state-base-hover data-popup-open:text-text-secondary"
|
||||
>
|
||||
<span aria-hidden className="i-ri-more-fill size-4" />
|
||||
</IconButton>
|
||||
|
||||
@@ -60,7 +60,7 @@ const ConfigSelect: FC<IConfigSelectProps> = ({ options, onChange, errorMessage,
|
||||
>
|
||||
<IconButton
|
||||
{...getHandleProps(index)}
|
||||
className="handle size-6 shrink-0 cursor-grab aria-pressed:bg-state-accent-hover"
|
||||
className="handle shrink-0 cursor-grab aria-pressed:bg-state-accent-hover"
|
||||
>
|
||||
<RiDraggable aria-hidden="true" className="size-4 text-text-quaternary" />
|
||||
</IconButton>
|
||||
|
||||
@@ -59,7 +59,7 @@ const VarItem: FC<ItemProps> = ({
|
||||
<IconButton
|
||||
{...dragHandleProps}
|
||||
aria-label={dragHandleProps?.['aria-label'] ?? name}
|
||||
className="handle pointer-events-none absolute left-1.5 size-6 cursor-grab opacity-0 group-focus-within:pointer-events-auto group-focus-within:opacity-100 group-hover:pointer-events-auto group-hover:opacity-100 focus-visible:pointer-events-auto focus-visible:opacity-100 aria-pressed:bg-state-accent-hover"
|
||||
className="handle pointer-events-none absolute left-1.5 cursor-grab opacity-0 group-focus-within:pointer-events-auto group-focus-within:opacity-100 group-hover:pointer-events-auto group-hover:opacity-100 focus-visible:pointer-events-auto focus-visible:opacity-100 aria-pressed:bg-state-accent-hover"
|
||||
>
|
||||
<RiDraggable aria-hidden="true" className="size-4 text-text-tertiary" />
|
||||
</IconButton>
|
||||
|
||||
@@ -160,7 +160,7 @@ const CreatorsFilter = ({ value, onChange }: CreatorsFilterProps) => {
|
||||
<IconButton
|
||||
size="sm"
|
||||
aria-label={resetLabel}
|
||||
className="absolute top-1/2 right-1 size-5 -translate-y-1/2 text-text-tertiary peer-data-popup-open/creators-trigger:text-text-secondary"
|
||||
className="absolute top-1/2 right-1 -translate-y-1/2 peer-data-popup-open/creators-trigger:text-text-secondary"
|
||||
onClick={handleSelectionClear}
|
||||
>
|
||||
<span aria-hidden className="i-ri-close-circle-fill h-3.5 w-3.5" />
|
||||
|
||||
@@ -119,7 +119,6 @@ export function AccessPointUrl({
|
||||
) : (
|
||||
<CopyFeedback
|
||||
content={value}
|
||||
className="size-6"
|
||||
copyLabel={copyLabel}
|
||||
copiedLabel={copiedLabel}
|
||||
onCopyError={onCopyError}
|
||||
|
||||
@@ -199,7 +199,7 @@ const OpeningSettingModal = ({
|
||||
>
|
||||
<IconButton
|
||||
{...getHandleProps(index)}
|
||||
className="handle size-6 shrink-0 cursor-grab aria-pressed:bg-state-accent-hover"
|
||||
className="handle shrink-0 cursor-grab aria-pressed:bg-state-accent-hover"
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-draggable size-4 text-text-quaternary" />
|
||||
</IconButton>
|
||||
|
||||
@@ -7,6 +7,11 @@ import { FormItemValidateStatusEnum, FormTypeEnum } from '@/app/components/base/
|
||||
import BaseField from '../base-field'
|
||||
|
||||
const mockDynamicOptions = vi.fn()
|
||||
const mockCopy = vi.fn()
|
||||
|
||||
vi.mock('foxact/use-clipboard', () => ({
|
||||
useClipboard: () => ({ copy: mockCopy, copied: false }),
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks/use-i18n', () => ({
|
||||
useRenderI18nObject: () => (content: Record<string, string>) =>
|
||||
@@ -74,6 +79,30 @@ describe('BaseField', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ type: FormTypeEnum.textInput, value: 'server-value', copied: 'server-value' },
|
||||
{ type: FormTypeEnum.textNumber, value: 0, copied: '0' },
|
||||
])(
|
||||
'copies the $type field value through its keyboard-accessible action',
|
||||
async ({ type, value, copied }) => {
|
||||
const user = userEvent.setup()
|
||||
renderBaseField({
|
||||
formSchema: { type, name: 'value', label: 'Value', required: false, showCopy: true },
|
||||
defaultValues: { value },
|
||||
})
|
||||
|
||||
await user.click(screen.getByLabelText('Value'))
|
||||
await user.tab()
|
||||
const copyButton = screen.getByRole('button', { name: 'common.operation.copy' })
|
||||
expect(copyButton).toHaveFocus()
|
||||
await user.keyboard('{Enter}')
|
||||
|
||||
expect(mockCopy).toHaveBeenCalledWith(copied)
|
||||
expect(copyButton).toHaveFocus()
|
||||
expect(screen.getByLabelText('Value')).toHaveValue(String(value))
|
||||
},
|
||||
)
|
||||
|
||||
it.each([FormTypeEnum.textInput, FormTypeEnum.secretInput, FormTypeEnum.textNumber])(
|
||||
'associates the visible label, description and required state for %s',
|
||||
async (type) => {
|
||||
|
||||
@@ -337,11 +337,8 @@ const BaseField = ({
|
||||
)}
|
||||
>
|
||||
<InputGroupInput {...textInputProps} />
|
||||
<InputGroupAddon align="inline-end" className="pe-0">
|
||||
<CopyFeedback
|
||||
content={stringValue ?? ''}
|
||||
className="size-7 hover:bg-transparent"
|
||||
/>
|
||||
<InputGroupAddon align="inline-end" className="pe-0.5">
|
||||
<CopyFeedback content={stringValue ?? ''} className="hover:bg-transparent" />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
) : (
|
||||
@@ -385,7 +382,7 @@ const BaseField = ({
|
||||
{showCopy && (
|
||||
<CopyFeedback
|
||||
content={value == null ? '' : String(value)}
|
||||
className="size-7 shrink-0 hover:bg-transparent"
|
||||
className="me-0.5 shrink-0 self-center hover:bg-transparent"
|
||||
/>
|
||||
)}
|
||||
</NumberFieldGroup>
|
||||
|
||||
@@ -21,10 +21,7 @@ const Card: FC<CardProps> = ({ log }) => {
|
||||
>
|
||||
<div className="flex h-8 items-center justify-between">
|
||||
<div className="font-semibold text-indigo-800">{item.role.toUpperCase()}</div>
|
||||
<CopyFeedback
|
||||
className="hidden size-6 group-hover/card:block"
|
||||
content={item.text}
|
||||
/>
|
||||
<CopyFeedback className="hidden group-hover/card:block" content={item.text} />
|
||||
</div>
|
||||
<div className="whitespace-pre-line text-text-secondary">{item.text}</div>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@ const PromptLogModal: FC<PromptLogModalProps> = ({ currentLogItem, width, onCanc
|
||||
<div className="flex items-center">
|
||||
{currentLogItem.log?.length === 1 && (
|
||||
<>
|
||||
<CopyFeedback className="size-6" content={currentLogItem.log[0]!.text} />
|
||||
<CopyFeedback content={currentLogItem.log[0]!.text} />
|
||||
<div className="mx-2.5 h-3.5 w-px bg-divider-regular" />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -142,8 +142,8 @@ export default function MarketplaceDetailDialogFrame({
|
||||
<IconButton
|
||||
ref={closeButtonRef}
|
||||
aria-label={t(($) => $['operation.close'], { ns: 'common' })}
|
||||
size="sm"
|
||||
className="absolute top-5 right-5 z-10 size-8 rounded-lg"
|
||||
size="lg"
|
||||
className="absolute top-5 right-5 z-10"
|
||||
>
|
||||
<span aria-hidden className="i-ri-close-line size-4" />
|
||||
</IconButton>
|
||||
|
||||
@@ -30,8 +30,8 @@ export function ReadmeDialog({ detail, open, onOpenChange, triggerId }: ReadmeDi
|
||||
render={
|
||||
<IconButton
|
||||
aria-label={t(($) => $['operation.close'], { ns: 'common' })}
|
||||
size="sm"
|
||||
className="static size-8 rounded-lg"
|
||||
size="lg"
|
||||
className="static"
|
||||
>
|
||||
<span aria-hidden className="i-ri-close-line size-4" />
|
||||
</IconButton>
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ const FieldItem = ({
|
||||
{!readonly && dragHandleProps && (
|
||||
<IconButton
|
||||
{...dragHandleProps}
|
||||
className="handle pointer-events-none absolute -top-1 -left-1 size-6 cursor-grab opacity-0 group-focus-within:pointer-events-auto group-focus-within:opacity-100 group-hover:pointer-events-auto group-hover:opacity-100 focus-visible:pointer-events-auto focus-visible:opacity-100 aria-pressed:bg-state-accent-hover"
|
||||
className="handle pointer-events-none absolute -top-1 -left-1 cursor-grab opacity-0 group-focus-within:pointer-events-auto group-focus-within:opacity-100 group-hover:pointer-events-auto group-hover:opacity-100 focus-visible:pointer-events-auto focus-visible:opacity-100 aria-pressed:bg-state-accent-hover"
|
||||
>
|
||||
<RiDraggable aria-hidden="true" className="size-4 text-text-quaternary" />
|
||||
</IconButton>
|
||||
|
||||
@@ -177,7 +177,7 @@ const VarList: FC<Props> = ({
|
||||
{canDrag && (
|
||||
<IconButton
|
||||
{...keyboardSort.getHandleProps(index)}
|
||||
className="handle pointer-events-none absolute top-1 -left-6 size-6 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
className="handle pointer-events-none absolute top-1 -left-6 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-draggable size-3" />
|
||||
</IconButton>
|
||||
|
||||
@@ -140,7 +140,7 @@ const ConditionWrap: FC<Props> = ({
|
||||
{!readOnly && casesLength > 1 && (
|
||||
<IconButton
|
||||
{...keyboardSort.getHandleProps(index)}
|
||||
className="handle pointer-events-none absolute top-1 -left-2 z-10 size-6 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
className="handle pointer-events-none absolute top-1 -left-2 z-10 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-draggable size-3" />
|
||||
</IconButton>
|
||||
|
||||
@@ -221,7 +221,7 @@ const ConfigPrompt: FC<Props> = ({
|
||||
{canDrag && (
|
||||
<IconButton
|
||||
{...keyboardSort.getHandleProps(index)}
|
||||
className="handle pointer-events-none absolute top-1 -left-6 size-6 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
className="handle pointer-events-none absolute top-1 -left-6 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
|
||||
@@ -180,7 +180,7 @@ const ClassList: FC<Props> = ({
|
||||
{canDrag && (
|
||||
<IconButton
|
||||
{...keyboardSort.getHandleProps(index)}
|
||||
className="handle pointer-events-none absolute top-1.5 left-0.5 z-10 size-6 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
className="handle pointer-events-none absolute top-1.5 left-0.5 z-10 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-draggable size-3" />
|
||||
</IconButton>
|
||||
|
||||
@@ -127,7 +127,7 @@ const VarList: FC<Props> = ({ readonly, list, onChange }) => {
|
||||
{canDrag && (
|
||||
<IconButton
|
||||
{...keyboardSort.getHandleProps(index)}
|
||||
className="handle pointer-events-none absolute top-1 left-1.5 size-6 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
className="handle pointer-events-none absolute top-1 left-1.5 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 focus:pointer-events-auto focus:opacity-100 aria-pressed:pointer-events-auto aria-pressed:opacity-100"
|
||||
>
|
||||
<span aria-hidden="true" className="i-ri-draggable size-3" />
|
||||
</IconButton>
|
||||
|
||||
+2
-2
@@ -458,8 +458,8 @@ function AgentKnowledgeRetrievalDialogContent({
|
||||
render={
|
||||
<IconButton
|
||||
aria-label={t(($) => $['operation.close'], { ns: 'common' })}
|
||||
size="sm"
|
||||
className="static size-7 shrink-0 rounded-md"
|
||||
size="lg"
|
||||
className="-my-0.5 shrink-0"
|
||||
>
|
||||
<span aria-hidden className="i-ri-close-line size-4" />
|
||||
</IconButton>
|
||||
|
||||
+4
-4
@@ -392,14 +392,14 @@ export function AgentSkillDetailDialog({
|
||||
</h2>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
<div className="-my-0.5 flex shrink-0 items-center gap-1">
|
||||
{detail.onDownloadFile && previewTitle && (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`${isHeaderDownloadLoading ? tCommon(($) => $['operation.downloading']) : tCommon(($) => $['operation.download'])} ${previewTitle}`}
|
||||
onClick={() => detail.onDownloadFile?.('header')}
|
||||
disabled={isHeaderDownloadLoading}
|
||||
className="flex size-7 shrink-0 items-center justify-center rounded-md text-text-tertiary outline-hidden hover:bg-state-base-hover hover:text-text-secondary focus-visible:bg-state-base-hover focus-visible:text-text-secondary focus-visible:ring-2 focus-visible:ring-state-accent-solid"
|
||||
className="flex size-8 shrink-0 items-center justify-center rounded-lg text-text-tertiary outline-hidden hover:bg-state-base-hover hover:text-text-secondary focus-visible:bg-state-base-hover focus-visible:text-text-secondary focus-visible:ring-2 focus-visible:ring-state-accent-solid"
|
||||
>
|
||||
<span
|
||||
aria-hidden
|
||||
@@ -416,8 +416,8 @@ export function AgentSkillDetailDialog({
|
||||
render={
|
||||
<IconButton
|
||||
aria-label={tCommon(($) => $['operation.close'])}
|
||||
size="sm"
|
||||
className="static size-7 shrink-0 rounded-md"
|
||||
size="lg"
|
||||
className="shrink-0"
|
||||
>
|
||||
<span aria-hidden className="i-ri-close-line size-4" />
|
||||
</IconButton>
|
||||
|
||||
Reference in new issue
Block a user