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" /> <slot name="header" />
</div> </div>
<table class="w-full table-fixed border-separate border-spacing-0 border-surface-5"> <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=""> <thead class="">
<tr class="bg-surface-3"> <tr class="bg-surface-3">
<th v-if="showSelection" class="w-10 pl-4"> <th v-if="showSelection" class="w-10 pl-4">
@@ -25,24 +33,23 @@
`text-${column.align ?? 'left'}`, `text-${column.align ?? 'left'}`,
column.enableSorting ? 'cursor-pointer select-none' : '', column.enableSorting ? 'cursor-pointer select-none' : '',
]" ]"
:style="column.width ? { width: column.width } : undefined"
@click="column.enableSorting ? handleSort(column.key) : undefined" @click="column.enableSorting ? handleSort(column.key) : undefined"
> >
<slot :name="`header-${column.key}`" :column="column"> <slot :name="`header-${column.key}`" :column="column">
<span <span
v-if="column.label || column.enableSorting" 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' : ''}`" :class="`${sortColumn === column.key ? 'text-contrast' : ''}`"
> >
{{ column.label ?? '' }} <span class="min-w-0 truncate">{{ column.label ?? '' }}</span>
<template v-if="column.enableSorting"> <template v-if="column.enableSorting">
<ChevronUpIcon <ChevronUpIcon
v-if="sortColumn === column.key && sortDirection === 'asc'" v-if="sortColumn === column.key && sortDirection === 'asc'"
class="size-4" class="size-4 shrink-0"
/> />
<ChevronDownIcon <ChevronDownIcon
v-else-if="sortColumn === column.key && sortDirection === 'desc'" v-else-if="sortColumn === column.key && sortDirection === 'desc'"
class="size-4" class="size-4 shrink-0"
/> />
</template> </template>
</span> </span>
@@ -85,7 +92,6 @@
:key="column.key" :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-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'}`" :class="`text-${column.align ?? 'left'}`"
:style="column.width ? { width: column.width } : undefined"
> >
<slot <slot
:name="`cell-${column.key}`" :name="`cell-${column.key}`"
@@ -38,7 +38,7 @@
:class="sortField === 'size' ? 'text-contrast' : 'text-secondary'" :class="sortField === 'size' ? 'text-contrast' : 'text-secondary'"
@click="$emit('sort', 'size')" @click="$emit('sort', 'size')"
> >
<span class="ml-2">{{ formatMessage(messages.size) }}</span> <span>{{ formatMessage(messages.size) }}</span>
<ChevronUpIcon <ChevronUpIcon
v-if="sortField === 'size' && !sortDesc" v-if="sortField === 'size' && !sortDesc"
class="h-4 w-4" class="h-4 w-4"
@@ -55,7 +55,7 @@
:class="sortField === 'created' ? 'text-contrast' : 'text-secondary'" :class="sortField === 'created' ? 'text-contrast' : 'text-secondary'"
@click="$emit('sort', 'created')" @click="$emit('sort', 'created')"
> >
<span class="ml-2">{{ formatMessage(messages.created) }}</span> <span>{{ formatMessage(messages.created) }}</span>
<ChevronUpIcon <ChevronUpIcon
v-if="sortField === 'created' && !sortDesc" v-if="sortField === 'created' && !sortDesc"
class="h-4 w-4" class="h-4 w-4"
@@ -72,7 +72,7 @@
:class="sortField === 'modified' ? 'text-contrast' : 'text-secondary'" :class="sortField === 'modified' ? 'text-contrast' : 'text-secondary'"
@click="$emit('sort', 'modified')" @click="$emit('sort', 'modified')"
> >
<span class="ml-2">{{ formatMessage(messages.modified) }}</span> <span>{{ formatMessage(messages.modified) }}</span>
<ChevronUpIcon <ChevronUpIcon
v-if="sortField === 'modified' && !sortDesc" v-if="sortField === 'modified' && !sortDesc"
class="h-4 w-4" class="h-4 w-4"
@@ -84,7 +84,7 @@
aria-hidden="true" aria-hidden="true"
/> />
</button> </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) formatMessage(commonMessages.actionsLabel)
}}</span> }}</span>
</div> </div>
@@ -42,41 +42,49 @@
<span class="hidden w-[160px] text-nowrap text-sm text-secondary @[800px]:block"> <span class="hidden w-[160px] text-nowrap text-sm text-secondary @[800px]:block">
{{ formattedModifiedDate }} {{ formattedModifiedDate }}
</span> </span>
<div class="flex min-w-[51px] shrink-0 items-center justify-end"> <div class="grid min-w-[51px] shrink-0 items-center justify-items-end">
<ButtonStyled circular type="transparent"> <span
<TeleportOverflowMenu :options="menuOptions"> aria-hidden="true"
<MoreHorizontalIcon class="h-5 w-5 bg-transparent" /> class="invisible col-start-1 row-start-1 text-nowrap font-semibold"
<template #copy-filename >
><ClipboardCopyIcon /> {{ formatMessage(commonMessages.actionsLabel) }}
{{ formatMessage(commonMessages.copyFilenameButton) }}</template </span>
> <div class="col-start-1 row-start-1 flex justify-end">
<template #copy-full-path <ButtonStyled circular type="transparent">
><ClipboardCopyIcon /> <TeleportOverflowMenu :options="menuOptions">
{{ formatMessage(commonMessages.copyFullPathButton) }}</template <MoreHorizontalIcon class="h-5 w-5 bg-transparent" />
> <template #copy-filename
<template #open-in-folder ><ClipboardCopyIcon />
><FolderOpenIcon /> {{ formatMessage(commonMessages.openInFolderButton) }}</template {{ formatMessage(commonMessages.copyFilenameButton) }}</template
> >
<template #extract <template #copy-full-path
><PackageOpenIcon /> {{ formatMessage(commonMessages.extractButton) }}</template ><ClipboardCopyIcon />
> {{ formatMessage(commonMessages.copyFullPathButton) }}</template
<template #rename >
><EditIcon /> {{ formatMessage(commonMessages.renameButton) }}</template <template #open-in-folder
> ><FolderOpenIcon /> {{ formatMessage(commonMessages.openInFolderButton) }}</template
<template #move >
><RightArrowIcon /> {{ formatMessage(commonMessages.moveButton) }}</template <template #extract
> ><PackageOpenIcon /> {{ formatMessage(commonMessages.extractButton) }}</template
<template #download >
><DownloadIcon /> <template #rename
{{ ><EditIcon /> {{ formatMessage(commonMessages.renameButton) }}</template
ctx.downloadButtonLabel ?? formatMessage(commonMessages.downloadButton) >
}}</template <template #move
> ><RightArrowIcon /> {{ formatMessage(commonMessages.moveButton) }}</template
<template #delete >
><TrashIcon /> {{ formatMessage(commonMessages.deleteLabel) }}</template <template #download
> ><DownloadIcon />
</TeleportOverflowMenu> {{
</ButtonStyled> ctx.downloadButtonLabel ?? formatMessage(commonMessages.downloadButton)
}}</template
>
<template #delete
><TrashIcon /> {{ formatMessage(commonMessages.deleteLabel) }}</template
>
</TeleportOverflowMenu>
</ButtonStyled>
</div>
</div> </div>
</div> </div>
</li> </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 = { export const FullFeatured: StoryObj = {
args: {}, args: {},
render: () => ({ render: () => ({