fix: table i18n bug (#6129)

This commit is contained in:
Calum H.
2026-05-18 15:53:25 +01:00
committed by GitHub
parent 6479eca0e9
commit 3f2e76ae7e
4 changed files with 105 additions and 45 deletions
+12 -6
View File
@@ -7,6 +7,14 @@
<slot name="header" />
</div>
<table class="w-full table-fixed border-separate border-spacing-0 border-surface-5">
<colgroup>
<col v-if="showSelection" class="w-10" />
<col
v-for="column in columns"
:key="column.key"
:style="column.width ? { width: column.width } : undefined"
/>
</colgroup>
<thead class="">
<tr class="bg-surface-3">
<th v-if="showSelection" class="w-10 pl-4">
@@ -25,24 +33,23 @@
`text-${column.align ?? 'left'}`,
column.enableSorting ? 'cursor-pointer select-none' : '',
]"
:style="column.width ? { width: column.width } : undefined"
@click="column.enableSorting ? handleSort(column.key) : undefined"
>
<slot :name="`header-${column.key}`" :column="column">
<span
v-if="column.label || column.enableSorting"
class="inline-flex items-center gap-1 font-semibold"
class="inline-flex min-w-0 max-w-full items-center gap-1 font-semibold"
:class="`${sortColumn === column.key ? 'text-contrast' : ''}`"
>
{{ column.label ?? '' }}
<span class="min-w-0 truncate">{{ column.label ?? '' }}</span>
<template v-if="column.enableSorting">
<ChevronUpIcon
v-if="sortColumn === column.key && sortDirection === 'asc'"
class="size-4"
class="size-4 shrink-0"
/>
<ChevronDownIcon
v-else-if="sortColumn === column.key && sortDirection === 'desc'"
class="size-4"
class="size-4 shrink-0"
/>
</template>
</span>
@@ -85,7 +92,6 @@
:key="column.key"
class="text-secondary h-14 overflow-hidden first:pl-4 last:pr-4 border-solid border-0 border-t border-surface-5"
:class="`text-${column.align ?? 'left'}`"
:style="column.width ? { width: column.width } : undefined"
>
<slot
:name="`cell-${column.key}`"
@@ -38,7 +38,7 @@
:class="sortField === 'size' ? 'text-contrast' : 'text-secondary'"
@click="$emit('sort', 'size')"
>
<span class="ml-2">{{ formatMessage(messages.size) }}</span>
<span>{{ formatMessage(messages.size) }}</span>
<ChevronUpIcon
v-if="sortField === 'size' && !sortDesc"
class="h-4 w-4"
@@ -55,7 +55,7 @@
:class="sortField === 'created' ? 'text-contrast' : 'text-secondary'"
@click="$emit('sort', 'created')"
>
<span class="ml-2">{{ formatMessage(messages.created) }}</span>
<span>{{ formatMessage(messages.created) }}</span>
<ChevronUpIcon
v-if="sortField === 'created' && !sortDesc"
class="h-4 w-4"
@@ -72,7 +72,7 @@
:class="sortField === 'modified' ? 'text-contrast' : 'text-secondary'"
@click="$emit('sort', 'modified')"
>
<span class="ml-2">{{ formatMessage(messages.modified) }}</span>
<span>{{ formatMessage(messages.modified) }}</span>
<ChevronUpIcon
v-if="sortField === 'modified' && !sortDesc"
class="h-4 w-4"
@@ -84,7 +84,7 @@
aria-hidden="true"
/>
</button>
<span class="min-w-[51px] shrink-0 text-right font-semibold text-secondary">{{
<span class="min-w-[51px] shrink-0 text-nowrap text-right font-semibold text-secondary">{{
formatMessage(commonMessages.actionsLabel)
}}</span>
</div>
@@ -42,41 +42,49 @@
<span class="hidden w-[160px] text-nowrap text-sm text-secondary @[800px]:block">
{{ formattedModifiedDate }}
</span>
<div class="flex min-w-[51px] shrink-0 items-center justify-end">
<ButtonStyled circular type="transparent">
<TeleportOverflowMenu :options="menuOptions">
<MoreHorizontalIcon class="h-5 w-5 bg-transparent" />
<template #copy-filename
><ClipboardCopyIcon />
{{ formatMessage(commonMessages.copyFilenameButton) }}</template
>
<template #copy-full-path
><ClipboardCopyIcon />
{{ formatMessage(commonMessages.copyFullPathButton) }}</template
>
<template #open-in-folder
><FolderOpenIcon /> {{ formatMessage(commonMessages.openInFolderButton) }}</template
>
<template #extract
><PackageOpenIcon /> {{ formatMessage(commonMessages.extractButton) }}</template
>
<template #rename
><EditIcon /> {{ formatMessage(commonMessages.renameButton) }}</template
>
<template #move
><RightArrowIcon /> {{ formatMessage(commonMessages.moveButton) }}</template
>
<template #download
><DownloadIcon />
{{
ctx.downloadButtonLabel ?? formatMessage(commonMessages.downloadButton)
}}</template
>
<template #delete
><TrashIcon /> {{ formatMessage(commonMessages.deleteLabel) }}</template
>
</TeleportOverflowMenu>
</ButtonStyled>
<div class="grid min-w-[51px] shrink-0 items-center justify-items-end">
<span
aria-hidden="true"
class="invisible col-start-1 row-start-1 text-nowrap font-semibold"
>
{{ formatMessage(commonMessages.actionsLabel) }}
</span>
<div class="col-start-1 row-start-1 flex justify-end">
<ButtonStyled circular type="transparent">
<TeleportOverflowMenu :options="menuOptions">
<MoreHorizontalIcon class="h-5 w-5 bg-transparent" />
<template #copy-filename
><ClipboardCopyIcon />
{{ formatMessage(commonMessages.copyFilenameButton) }}</template
>
<template #copy-full-path
><ClipboardCopyIcon />
{{ formatMessage(commonMessages.copyFullPathButton) }}</template
>
<template #open-in-folder
><FolderOpenIcon /> {{ formatMessage(commonMessages.openInFolderButton) }}</template
>
<template #extract
><PackageOpenIcon /> {{ formatMessage(commonMessages.extractButton) }}</template
>
<template #rename
><EditIcon /> {{ formatMessage(commonMessages.renameButton) }}</template
>
<template #move
><RightArrowIcon /> {{ formatMessage(commonMessages.moveButton) }}</template
>
<template #download
><DownloadIcon />
{{
ctx.downloadButtonLabel ?? formatMessage(commonMessages.downloadButton)
}}</template
>
<template #delete
><TrashIcon /> {{ formatMessage(commonMessages.deleteLabel) }}</template
>
</TeleportOverflowMenu>
</ButtonStyled>
</div>
</div>
</div>
</li>
@@ -297,6 +297,52 @@ export const WithActionsColumn: StoryObj = {
}),
}
export const WithLocalizedActionsColumn: StoryObj = {
args: {},
render: () => ({
components: { Table, ButtonStyled, EditIcon, TrashIcon },
setup() {
const columns = [
{ key: 'name', label: 'Nombre' },
{ key: 'email', label: 'Correo' },
{ key: 'role', label: 'Rol' },
{ key: 'actions', label: 'Acciones', align: 'right' as const, width: '240px' },
]
const data = sampleUsers
function handleEdit(row: User) {
alert(`Editar usuario: ${row.name}`)
}
function handleDelete(row: User) {
alert(`Eliminar usuario: ${row.name}`)
}
return { columns, data, handleEdit, handleDelete }
},
template: /* html */ `
<Table :columns="columns" :data="data">
<template #cell-actions="{ row }">
<div class="flex items-center justify-end gap-2">
<ButtonStyled color="brand" type="transparent" @click="handleEdit(row)">
<button class="flex items-center gap-1">
<EditIcon class="size-4" />
Editar
</button>
</ButtonStyled>
<ButtonStyled color="red" type="transparent" @click="handleDelete(row)">
<button class="flex items-center gap-1">
<TrashIcon class="size-4" />
Eliminar
</button>
</ButtonStyled>
</div>
</template>
</Table>
`,
}),
}
export const FullFeatured: StoryObj = {
args: {},
render: () => ({