mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
fix: version table overflow issues (#6583)
* feat: shorten ModLoader * fix: game version and platform tag overflow issues * feat: add table version row below and move version files to version row below * fix: platform plural * pnpm prepr
This commit is contained in:
@@ -33,7 +33,7 @@
|
||||
<th
|
||||
v-for="column in columns"
|
||||
:key="column.key"
|
||||
class="h-12 first:pl-4 last:pr-4"
|
||||
class="h-12 pr-2 first:pl-4 last:pr-4"
|
||||
:class="[
|
||||
`text-${column.align ?? 'left'}`,
|
||||
column.enableSorting ? 'cursor-pointer select-none' : '',
|
||||
@@ -79,39 +79,53 @@
|
||||
</td>
|
||||
</tr>
|
||||
<template v-else>
|
||||
<tr
|
||||
<template
|
||||
v-for="(row, rowIndex) in renderedRows"
|
||||
:key="getRowRenderKey(row, getAbsoluteRowIndex(rowIndex))"
|
||||
:class="getRowClass(row, getAbsoluteRowIndex(rowIndex))"
|
||||
@click="handleRowClick(row, getAbsoluteRowIndex(rowIndex), $event)"
|
||||
:key="getRowPartRenderKey(row, getAbsoluteRowIndex(rowIndex), 'group')"
|
||||
>
|
||||
<td
|
||||
v-if="showSelection"
|
||||
class="w-12 border-solid border-0 border-t border-surface-4 focus:outline-none"
|
||||
<tr
|
||||
:class="getRowClass(row, getAbsoluteRowIndex(rowIndex))"
|
||||
@click="handleRowClick(row, getAbsoluteRowIndex(rowIndex), $event)"
|
||||
>
|
||||
<Checkbox
|
||||
:model-value="isSelected(row)"
|
||||
class="shrink-0 p-4 -outline-offset-[14px] outline rounded-2xl"
|
||||
@update:model-value="(selectRow, event) => toggleSelection(row, selectRow, event)"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
v-for="column in columns"
|
||||
:key="column.key"
|
||||
class="text-secondary h-14 overflow-hidden first:pl-4 last:pr-4 border-solid border-0 border-t border-surface-4"
|
||||
:class="[`text-${column.align ?? 'left'}`, column.cellClass]"
|
||||
>
|
||||
<slot
|
||||
:name="`cell-${column.key}`"
|
||||
:row="row"
|
||||
:value="row[column.key]"
|
||||
:column="column"
|
||||
:index="getAbsoluteRowIndex(rowIndex)"
|
||||
<td
|
||||
v-if="showSelection"
|
||||
class="w-12 border-solid border-0 border-t border-surface-4 focus:outline-none"
|
||||
>
|
||||
{{ row[column.key] ?? '' }}
|
||||
</slot>
|
||||
</td>
|
||||
</tr>
|
||||
<Checkbox
|
||||
:model-value="isSelected(row)"
|
||||
class="shrink-0 p-4 -outline-offset-[14px] outline rounded-2xl"
|
||||
@update:model-value="
|
||||
(selectRow, event) => toggleSelection(row, selectRow, event)
|
||||
"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
v-for="column in columns"
|
||||
:key="column.key"
|
||||
class="text-secondary h-14 overflow-hidden first:pl-4 last:pr-4 border-solid border-0 border-t border-surface-4"
|
||||
:class="[`text-${column.align ?? 'left'}`, column.cellClass]"
|
||||
>
|
||||
<slot
|
||||
:name="`cell-${column.key}`"
|
||||
:row="row"
|
||||
:value="row[column.key]"
|
||||
:column="column"
|
||||
:index="getAbsoluteRowIndex(rowIndex)"
|
||||
>
|
||||
{{ row[column.key] ?? '' }}
|
||||
</slot>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-if="isRowBelowVisible(row, getAbsoluteRowIndex(rowIndex))"
|
||||
:class="getRowBelowClass(row, getAbsoluteRowIndex(rowIndex))"
|
||||
@click="handleRowClick(row, getAbsoluteRowIndex(rowIndex), $event)"
|
||||
>
|
||||
<td :colspan="columnSpan" class="p-0">
|
||||
<slot name="row-below" :row="row" :index="getAbsoluteRowIndex(rowIndex)" />
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</template>
|
||||
</TransitionGroup>
|
||||
<tbody v-else :ref="setListContainer">
|
||||
@@ -132,39 +146,53 @@
|
||||
:style="{ height: `${topSpacerHeight}px` }"
|
||||
></td>
|
||||
</tr>
|
||||
<tr
|
||||
<template
|
||||
v-for="(row, rowIndex) in renderedRows"
|
||||
:key="getRowRenderKey(row, getAbsoluteRowIndex(rowIndex))"
|
||||
:class="getRowClass(row, getAbsoluteRowIndex(rowIndex))"
|
||||
@click="handleRowClick(row, getAbsoluteRowIndex(rowIndex), $event)"
|
||||
:key="getRowPartRenderKey(row, getAbsoluteRowIndex(rowIndex), 'group')"
|
||||
>
|
||||
<td
|
||||
v-if="showSelection"
|
||||
class="w-12 border-solid border-0 border-t border-surface-4 focus:outline-none"
|
||||
<tr
|
||||
:class="getRowClass(row, getAbsoluteRowIndex(rowIndex))"
|
||||
@click="handleRowClick(row, getAbsoluteRowIndex(rowIndex), $event)"
|
||||
>
|
||||
<Checkbox
|
||||
:model-value="isSelected(row)"
|
||||
class="shrink-0 p-4 -outline-offset-[14px] outline rounded-2xl"
|
||||
@update:model-value="(selectRow, event) => toggleSelection(row, selectRow, event)"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
v-for="column in columns"
|
||||
:key="column.key"
|
||||
class="text-secondary h-14 overflow-hidden first:pl-4 last:pr-4 border-solid border-0 border-t border-surface-4"
|
||||
:class="[`text-${column.align ?? 'left'}`, column.cellClass]"
|
||||
>
|
||||
<slot
|
||||
:name="`cell-${column.key}`"
|
||||
:row="row"
|
||||
:value="row[column.key]"
|
||||
:column="column"
|
||||
:index="getAbsoluteRowIndex(rowIndex)"
|
||||
<td
|
||||
v-if="showSelection"
|
||||
class="w-12 border-solid border-0 border-t border-surface-4 focus:outline-none"
|
||||
>
|
||||
{{ row[column.key] ?? '' }}
|
||||
</slot>
|
||||
</td>
|
||||
</tr>
|
||||
<Checkbox
|
||||
:model-value="isSelected(row)"
|
||||
class="shrink-0 p-4 -outline-offset-[14px] outline rounded-2xl"
|
||||
@update:model-value="
|
||||
(selectRow, event) => toggleSelection(row, selectRow, event)
|
||||
"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
v-for="column in columns"
|
||||
:key="column.key"
|
||||
class="text-secondary h-14 overflow-hidden first:pl-4 last:pr-4 border-solid border-0 border-t border-surface-4"
|
||||
:class="[`text-${column.align ?? 'left'}`, column.cellClass]"
|
||||
>
|
||||
<slot
|
||||
:name="`cell-${column.key}`"
|
||||
:row="row"
|
||||
:value="row[column.key]"
|
||||
:column="column"
|
||||
:index="getAbsoluteRowIndex(rowIndex)"
|
||||
>
|
||||
{{ row[column.key] ?? '' }}
|
||||
</slot>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-if="isRowBelowVisible(row, getAbsoluteRowIndex(rowIndex))"
|
||||
:class="getRowBelowClass(row, getAbsoluteRowIndex(rowIndex))"
|
||||
@click="handleRowClick(row, getAbsoluteRowIndex(rowIndex), $event)"
|
||||
>
|
||||
<td :colspan="columnSpan" class="p-0">
|
||||
<slot name="row-below" :row="row" :index="getAbsoluteRowIndex(rowIndex)" />
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<tr v-if="virtualized && bottomSpacerHeight > 0" aria-hidden="true">
|
||||
<td
|
||||
:colspan="columnSpan"
|
||||
@@ -231,6 +259,7 @@ const props = withDefaults(
|
||||
*/
|
||||
tableMinWidth?: string
|
||||
tableLayout?: TableLayout
|
||||
rowBelowVisible?: boolean | ((row: T, index: number) => boolean)
|
||||
rowClass?: string | ((row: T, index: number) => string)
|
||||
rowClickable?: boolean | ((row: T, index: number) => boolean)
|
||||
}>(),
|
||||
@@ -250,6 +279,7 @@ const sortDirection = defineModel<SortDirection>('sortDirection', { default: 'as
|
||||
const slots = useSlots()
|
||||
const selectionAnchorId = ref<unknown>()
|
||||
const hasHeaderSlot = computed(() => Boolean(slots.header))
|
||||
const hasRowBelowSlot = computed(() => Boolean(slots['row-below']))
|
||||
const columnSpan = computed(() => Math.max(props.columns.length + (props.showSelection ? 1 : 0), 1))
|
||||
|
||||
const {
|
||||
@@ -331,6 +361,22 @@ function getRowRenderKey(row: T, rowIndex: number): PropertyKey {
|
||||
return rowIndex
|
||||
}
|
||||
|
||||
function getRowPartRenderKey(row: T, rowIndex: number, part: 'group' | 'row' | 'below'): string {
|
||||
return `${String(getRowRenderKey(row, rowIndex))}-${part}`
|
||||
}
|
||||
|
||||
function isRowBelowVisible(row: T, rowIndex: number): boolean {
|
||||
if (!hasRowBelowSlot.value || props.virtualized) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (typeof props.rowBelowVisible === 'function') {
|
||||
return props.rowBelowVisible(row, rowIndex)
|
||||
}
|
||||
|
||||
return props.rowBelowVisible ?? true
|
||||
}
|
||||
|
||||
function getRowClass(row: T, rowIndex: number): string[] {
|
||||
const baseClass = rowIndex % 2 === 0 ? 'bg-surface-2' : 'bg-surface-1.5'
|
||||
const customClass =
|
||||
@@ -339,6 +385,20 @@ function getRowClass(row: T, rowIndex: number): string[] {
|
||||
return customClass ? [baseClass, customClass] : [baseClass]
|
||||
}
|
||||
|
||||
function getRowBelowClass(row: T, rowIndex: number): string[] {
|
||||
const classes = [
|
||||
rowIndex % 2 === 0 ? 'bg-surface-2' : 'bg-surface-1.5',
|
||||
'table-row-below',
|
||||
'transition-[filter]',
|
||||
]
|
||||
|
||||
if (isRowClickable(row, rowIndex)) {
|
||||
classes.push('cursor-pointer')
|
||||
}
|
||||
|
||||
return classes
|
||||
}
|
||||
|
||||
function isRowClickable(row: T, rowIndex: number): boolean {
|
||||
return typeof props.rowClickable === 'function'
|
||||
? props.rowClickable(row, rowIndex)
|
||||
|
||||
@@ -49,13 +49,14 @@
|
||||
row-key="id"
|
||||
:row-class="getVersionRowClass"
|
||||
:row-clickable="!!versionLink"
|
||||
:row-below-visible="isFileRowVisible"
|
||||
table-layout="auto"
|
||||
@row-click="openVersionRow"
|
||||
>
|
||||
<template #cell-channel="{ row: version }">
|
||||
<div class="flex items-center justify-center">
|
||||
<VersionChannelIndicator
|
||||
v-tooltip="`Toggle filter for ${version.version_type}`"
|
||||
v-tooltip="getFilterTooltip(version.version_type)"
|
||||
:channel="version.version_type"
|
||||
class="cursor-pointer"
|
||||
data-no-row-click
|
||||
@@ -88,52 +89,62 @@
|
||||
'--_color': 'var(--color-orange)',
|
||||
}"
|
||||
>
|
||||
<TagItem> <CircleAlertIcon /> {{ formatMessage(messages.withheld) }}</TagItem>
|
||||
<TagItem class="w-fit max-w-full truncate">
|
||||
<CircleAlertIcon />
|
||||
<span class="min-w-0 truncate">{{ formatMessage(messages.withheld) }}</span>
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
</AutoLink>
|
||||
<div v-if="showFiles" class="tag-list">
|
||||
<div
|
||||
v-for="(file, fileIdx) in version.files"
|
||||
:key="`file-tag-${fileIdx}`"
|
||||
:class="`flex items-center gap-1 text-wrap rounded-full bg-button-bg px-2 py-0.5 text-xs font-medium ${file.primary || fileIdx === 0 ? 'bg-brand-highlight text-contrast' : 'text-primary'}`"
|
||||
>
|
||||
<StarIcon v-if="file.primary || fileIdx === 0" class="shrink-0" />
|
||||
{{ file.filename }} - {{ formatBytes(file.size) }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #row-below="{ row: version }">
|
||||
<div class="tag-list px-4 pb-3 -mt-0.5">
|
||||
<div
|
||||
v-for="(file, fileIdx) in version.files"
|
||||
:key="`file-tag-${fileIdx}`"
|
||||
:class="`flex items-center gap-1 text-wrap rounded-full bg-button-bg px-2 py-0.5 text-xs font-medium ${file.primary || fileIdx === 0 ? 'text-contrast' : 'text-primary'}`"
|
||||
>
|
||||
<StarIcon v-if="file.primary || fileIdx === 0" class="shrink-0" />
|
||||
{{ file.filename }} - {{ formatBytes(file.size) }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #cell-gameVersions="{ row: version }">
|
||||
<div class="flex flex-wrap gap-1 w-fit">
|
||||
<div class="flex min-w-0 w-full max-w-[12rem] flex-wrap gap-1">
|
||||
<TagItem
|
||||
v-for="gameVersion in getDisplayGameVersions(version).slice(0, MAX_GAME_VERSION_TAGS)"
|
||||
:key="`version-tag-${gameVersion}`"
|
||||
v-tooltip="`Toggle filter for ${gameVersion}`"
|
||||
v-tooltip="getFilterTooltip(gameVersion)"
|
||||
data-no-row-click
|
||||
class="w-fit max-w-full truncate"
|
||||
:action="() => versionFilters?.toggleFilters('gameVersion', version.game_versions)"
|
||||
>
|
||||
{{ gameVersion }}
|
||||
<span class="min-w-0 truncate">{{ gameVersion }}</span>
|
||||
</TagItem>
|
||||
<Menu
|
||||
v-if="getDisplayGameVersions(version).length > MAX_GAME_VERSION_TAGS"
|
||||
data-no-row-click
|
||||
:delay="{ hide: 50, show: 0 }"
|
||||
no-auto-focus
|
||||
class="cursor-default"
|
||||
class="w-full min-w-0 cursor-default"
|
||||
>
|
||||
<TagItem tabindex="0">
|
||||
+{{ getDisplayGameVersions(version).length - MAX_GAME_VERSION_TAGS }}
|
||||
<TagItem class="w-fit max-w-full truncate" tabindex="0">
|
||||
<span class="min-w-0 truncate">
|
||||
+{{ getDisplayGameVersions(version).length - MAX_GAME_VERSION_TAGS }}
|
||||
</span>
|
||||
</TagItem>
|
||||
<template #popper>
|
||||
<div class="flex max-w-[20rem] flex-wrap gap-1">
|
||||
<TagItem
|
||||
v-for="gameVersion in getDisplayGameVersions(version).slice(MAX_GAME_VERSION_TAGS)"
|
||||
:key="`overflow-version-tag-${gameVersion}`"
|
||||
class="w-fit max-w-full truncate"
|
||||
:action="() => versionFilters?.toggleFilters('gameVersion', version.game_versions)"
|
||||
>
|
||||
{{ gameVersion }}
|
||||
<span class="min-w-0 truncate">{{ gameVersion }}</span>
|
||||
</TagItem>
|
||||
</div>
|
||||
</template>
|
||||
@@ -142,40 +153,49 @@
|
||||
</template>
|
||||
|
||||
<template #cell-platforms="{ row: version }">
|
||||
<div class="flex flex-wrap gap-1 w-fit">
|
||||
<div class="flex min-w-0 w-full max-w-[12rem] flex-wrap gap-1">
|
||||
<template v-if="version.noModLoader">
|
||||
<TagItem class="border !border-solid border-surface-5"> No mod loader </TagItem>
|
||||
<TagItem class="w-fit max-w-full truncate border !border-solid border-surface-5">
|
||||
<span class="min-w-0 truncate">No mod loader</span>
|
||||
</TagItem>
|
||||
</template>
|
||||
<template v-else>
|
||||
<TagItem
|
||||
v-for="platform in version.loaders.slice(0, MAX_PLATFORM_TAGS)"
|
||||
:key="`platform-tag-${platform}`"
|
||||
v-tooltip="`Toggle filter for ${platform}`"
|
||||
v-tooltip="getPlatformTooltip(platform)"
|
||||
data-no-row-click
|
||||
class="w-fit max-w-full truncate"
|
||||
:style="`--_color: var(--color-platform-${platform})`"
|
||||
:action="() => versionFilters?.toggleFilter('platform', platform)"
|
||||
>
|
||||
<component :is="getLoaderIcon(platform)" v-if="getLoaderIcon(platform)" />
|
||||
<FormattedTag :tag="platform" enforce-type="loader" />
|
||||
<span class="min-w-0 truncate">{{ getPlatformLabel(platform) }}</span>
|
||||
</TagItem>
|
||||
<Menu
|
||||
v-if="version.loaders.length > MAX_PLATFORM_TAGS"
|
||||
data-no-row-click
|
||||
:delay="{ hide: 50, show: 0 }"
|
||||
no-auto-focus
|
||||
class="cursor-default"
|
||||
class="w-full min-w-0 cursor-default"
|
||||
>
|
||||
<TagItem tabindex="0"> +{{ version.loaders.length - MAX_PLATFORM_TAGS }} </TagItem>
|
||||
<TagItem class="w-fit max-w-full truncate" tabindex="0">
|
||||
<span class="min-w-0 truncate">
|
||||
+{{ version.loaders.length - MAX_PLATFORM_TAGS }}
|
||||
</span>
|
||||
</TagItem>
|
||||
<template #popper>
|
||||
<div class="flex max-w-[20rem] flex-wrap gap-1">
|
||||
<TagItem
|
||||
v-for="platform in version.loaders.slice(MAX_PLATFORM_TAGS)"
|
||||
:key="`overflow-platform-tag-${platform}`"
|
||||
v-tooltip="getPlatformTooltip(platform)"
|
||||
class="w-fit max-w-full truncate"
|
||||
:style="`--_color: var(--color-platform-${platform})`"
|
||||
:action="() => versionFilters?.toggleFilter('platform', platform)"
|
||||
>
|
||||
<component :is="getLoaderIcon(platform)" v-if="getLoaderIcon(platform)" />
|
||||
<FormattedTag :tag="platform" enforce-type="loader" />
|
||||
<span class="min-w-0 truncate">{{ getPlatformLabel(platform) }}</span>
|
||||
</TagItem>
|
||||
</div>
|
||||
</template>
|
||||
@@ -185,15 +205,15 @@
|
||||
</template>
|
||||
|
||||
<template v-if="showEnvironmentColumn" #cell-environment="{ row: version }">
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<div class="flex min-w-0 w-full max-w-[12rem] flex-wrap gap-1">
|
||||
<TagItem
|
||||
v-for="(tag, tagIdx) in getEnvironmentTags(version.environment)"
|
||||
:key="`env-tag-${tagIdx}`"
|
||||
data-no-row-click
|
||||
class="text-center"
|
||||
class="w-fit max-w-full truncate text-center"
|
||||
>
|
||||
<component :is="tag.icon" />
|
||||
{{ formatMessage(tag.label).replace('and', '&') }}
|
||||
<span class="min-w-0 truncate">{{ formatMessage(tag.label).replace('and', '&') }}</span>
|
||||
</TagItem>
|
||||
</div>
|
||||
</template>
|
||||
@@ -258,7 +278,7 @@
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="self-center">
|
||||
<VersionChannelIndicator
|
||||
v-tooltip="`Toggle filter for ${version.version_type}`"
|
||||
v-tooltip="getFilterTooltip(version.version_type)"
|
||||
:channel="version.version_type"
|
||||
class="cursor-pointer smart-clickable:allow-pointer-events"
|
||||
size="sm"
|
||||
@@ -282,7 +302,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-start justify-end gap-1 max-[400px]:flex-col max-[400px]:justify-start smart-clickable:allow-pointer-events"
|
||||
class="flex items-start justify-end gap-1 max-[350px]:flex-col max-[350px]:justify-start smart-clickable:allow-pointer-events"
|
||||
>
|
||||
<slot name="actions" :version="version"></slot>
|
||||
</div>
|
||||
@@ -296,7 +316,7 @@
|
||||
MAX_GAME_VERSION_TAGS,
|
||||
)"
|
||||
:key="`version-tag-${gameVersion}`"
|
||||
v-tooltip="`Toggle filter for ${gameVersion}`"
|
||||
v-tooltip="getFilterTooltip(gameVersion)"
|
||||
class="smart-clickable:allow-pointer-events"
|
||||
:action="() => versionFilters?.toggleFilters('gameVersion', version.game_versions)"
|
||||
>
|
||||
@@ -334,13 +354,13 @@
|
||||
<TagItem
|
||||
v-for="platform in version.loaders.slice(0, MAX_PLATFORM_TAGS)"
|
||||
:key="`platform-tag-${platform}`"
|
||||
v-tooltip="`Toggle filter for ${platform}`"
|
||||
v-tooltip="getPlatformTooltip(platform)"
|
||||
class="smart-clickable:allow-pointer-events"
|
||||
:style="`--_color: var(--color-platform-${platform})`"
|
||||
:action="() => versionFilters?.toggleFilter('platform', platform)"
|
||||
>
|
||||
<component :is="getLoaderIcon(platform)" v-if="getLoaderIcon(platform)" />
|
||||
<FormattedTag :tag="platform" enforce-type="loader" />
|
||||
{{ getPlatformLabel(platform) }}
|
||||
</TagItem>
|
||||
<Menu
|
||||
v-if="version.loaders.length > MAX_PLATFORM_TAGS"
|
||||
@@ -356,11 +376,12 @@
|
||||
<TagItem
|
||||
v-for="platform in version.loaders.slice(MAX_PLATFORM_TAGS)"
|
||||
:key="`overflow-platform-tag-${platform}`"
|
||||
v-tooltip="getPlatformTooltip(platform)"
|
||||
:style="`--_color: var(--color-platform-${platform})`"
|
||||
:action="() => versionFilters?.toggleFilter('platform', platform)"
|
||||
>
|
||||
<component :is="getLoaderIcon(platform)" v-if="getLoaderIcon(platform)" />
|
||||
<FormattedTag :tag="platform" enforce-type="loader" />
|
||||
{{ getPlatformLabel(platform) }}
|
||||
</TagItem>
|
||||
</div>
|
||||
</template>
|
||||
@@ -425,7 +446,6 @@ import {
|
||||
import {
|
||||
AutoLink,
|
||||
ButtonStyled,
|
||||
FormattedTag,
|
||||
Pagination,
|
||||
SmartClickable,
|
||||
Table,
|
||||
@@ -444,6 +464,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { useRelativeTime } from '../../composables'
|
||||
import { defineMessages, useVIntl } from '../../composables/i18n'
|
||||
import { formatTag } from '../../utils/tag-messages'
|
||||
import { getEnvironmentTags } from './settings/environment/environments'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
@@ -519,18 +540,18 @@ const versionColumns = computed<TableColumn<VersionTableColumn>[]>(() => {
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: 'Name',
|
||||
label: 'Version',
|
||||
cellClass: '!overflow-visible py-3 pr-4 min-w-[7rem]',
|
||||
},
|
||||
{
|
||||
key: 'gameVersions',
|
||||
label: 'Game version',
|
||||
cellClass: '!overflow-visible py-3 align-middle pr-2.5 w-fit max-w-[10rem]',
|
||||
cellClass: '!overflow-visible py-3 align-middle pr-2.5 min-w-0 max-w-[12rem]',
|
||||
},
|
||||
{
|
||||
key: 'platforms',
|
||||
label: 'Platforms',
|
||||
cellClass: '!overflow-visible py-3 align-middle pr-2.5 w-fit max-w-[10rem]',
|
||||
label: 'Platform',
|
||||
cellClass: '!overflow-visible py-3 align-middle pr-2.5 min-w-0 max-w-[12rem]',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -538,7 +559,7 @@ const versionColumns = computed<TableColumn<VersionTableColumn>[]>(() => {
|
||||
columns.push({
|
||||
key: 'environment',
|
||||
label: 'Environment',
|
||||
cellClass: visibleCellClass,
|
||||
cellClass: `${visibleCellClass} min-w-0 max-w-[12rem]`,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -599,6 +620,26 @@ function getDisplayGameVersions(version: DisplayVersion): string[] {
|
||||
return formatVersionsForDisplay(version.game_versions, props.gameVersions)
|
||||
}
|
||||
|
||||
function getFilterTooltip(filter: string): string {
|
||||
return formatMessage(messages.toggleFilterTooltip, { filter })
|
||||
}
|
||||
|
||||
function getPlatformLabel(platform: string): string {
|
||||
if (platform === 'modloader') {
|
||||
return formatMessage(messages.modloaderShort)
|
||||
}
|
||||
|
||||
return formatTag(formatMessage, platform, 'loader')
|
||||
}
|
||||
|
||||
function getPlatformTooltip(platform: string): string {
|
||||
return getFilterTooltip(formatTag(formatMessage, platform, 'loader'))
|
||||
}
|
||||
|
||||
function isFileRowVisible(version: VersionTableRow): boolean {
|
||||
return props.showFiles && Array.isArray(version.files) && version.files.length > 0
|
||||
}
|
||||
|
||||
const normalizedVersions = computed<DisplayVersion[]>(() =>
|
||||
props.versions.map((version) => {
|
||||
const loaders = getModpackLoaders(version)
|
||||
@@ -674,9 +715,7 @@ function switchPage(page: number) {
|
||||
}
|
||||
|
||||
function getVersionRowClass(): string {
|
||||
return props.versionLink
|
||||
? 'group version-row-link cursor-pointer transition-[filter] [&:hover:not(:has([data-no-row-click]:hover))]:brightness-[115%]'
|
||||
: 'group'
|
||||
return props.versionLink ? 'group version-row-link cursor-pointer transition-[filter]' : 'group'
|
||||
}
|
||||
|
||||
function openVersionRow(version: VersionTableRow) {
|
||||
@@ -709,11 +748,27 @@ const messages = defineMessages({
|
||||
id: 'project.versions.version.withheld.tooltip',
|
||||
defaultMessage: 'Version withheld due to missing permissions',
|
||||
},
|
||||
toggleFilterTooltip: {
|
||||
id: 'project.versions.filter.toggle-tooltip',
|
||||
defaultMessage: 'Toggle filter for {filter}',
|
||||
},
|
||||
modloaderShort: {
|
||||
id: 'project.versions.platform.modloader.short',
|
||||
defaultMessage: 'ModLoader',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.version-row-link:hover:not(:has([data-no-row-click]:hover)) .version-row-name) {
|
||||
:deep(.version-row-link:hover:not(:has([data-no-row-click]:hover))),
|
||||
:deep(.version-row-link:hover:not(:has([data-no-row-click]:hover)) + .table-row-below),
|
||||
:deep(.version-row-link:has(+ .table-row-below:hover)),
|
||||
:deep(.version-row-link:has(+ .table-row-below:hover) + .table-row-below) {
|
||||
filter: brightness(115%);
|
||||
}
|
||||
|
||||
:deep(.version-row-link:hover:not(:has([data-no-row-click]:hover)) .version-row-name),
|
||||
:deep(.version-row-link:has(+ .table-row-below:hover) .version-row-name) {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3473,6 +3473,12 @@
|
||||
"project.versions.channel.release.symbol": {
|
||||
"defaultMessage": "R"
|
||||
},
|
||||
"project.versions.filter.toggle-tooltip": {
|
||||
"defaultMessage": "Toggle filter for {filter}"
|
||||
},
|
||||
"project.versions.platform.modloader.short": {
|
||||
"defaultMessage": "ModLoader"
|
||||
},
|
||||
"project.versions.version.withheld": {
|
||||
"defaultMessage": "Withheld"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user