diff --git a/apps/frontend/src/pages/[type]/[id]/settings/tags.vue b/apps/frontend/src/pages/[type]/[id]/settings/tags.vue index a4299c508..d4c6e8d6b 100644 --- a/apps/frontend/src/pages/[type]/[id]/settings/tags.vue +++ b/apps/frontend/src/pages/[type]/[id]/settings/tags.vue @@ -154,19 +154,23 @@ interface Category { } const tags = useGeneratedState() -const { formatMessage } = useVIntl() +const { formatMessage, locale } = useVIntl() const { projectV2: project, patchProject } = injectProjectPageContext() +const formatCategoryName = (categoryName: string) => { + return formatCategory(formatMessage, categoryName) +} + const { saved, current, saving, reset, save } = useSavable( () => ({ - selectedTags: sortedCategories(tags.value).filter( + selectedTags: sortedCategories(tags.value, formatCategoryName, locale.value).filter( (x: Category) => x.project_type === project.value.actualProjectType && (project.value.categories.includes(x.name) || project.value.additional_categories.includes(x.name)), ) as Category[], - featuredTags: sortedCategories(tags.value).filter( + featuredTags: sortedCategories(tags.value, formatCategoryName, locale.value).filter( (x: Category) => x.project_type === project.value.actualProjectType && project.value.categories.includes(x.name), @@ -212,7 +216,7 @@ const { saved, current, saving, reset, save } = useSavable( const categoryLists = computed(() => { const lists: Record = {} - sortedCategories(tags.value).forEach((x: Category) => { + sortedCategories(tags.value, formatCategoryName, locale.value).forEach((x: Category) => { if (x.project_type === project.value.actualProjectType) { const header = x.header if (!lists[header]) { @@ -253,9 +257,11 @@ const multipleResolutionTagsWarning = computed(() => { }) const allTagsSelectedWarning = computed(() => { - const categoriesForProjectType = sortedCategories(tags.value).filter( - (x: Category) => x.project_type === project.value.actualProjectType, - ) + const categoriesForProjectType = sortedCategories( + tags.value, + formatCategoryName, + locale.value, + ).filter((x: Category) => x.project_type === project.value.actualProjectType) const totalSelectedTags = current.value.selectedTags.length if ( diff --git a/apps/frontend/src/plugins/shorthands.js b/apps/frontend/src/plugins/shorthands.js index 015fd5e6f..b342e5fe5 100644 --- a/apps/frontend/src/plugins/shorthands.js +++ b/apps/frontend/src/plugins/shorthands.js @@ -104,22 +104,6 @@ export default defineNuxtPlugin((nuxtApp) => { getProjectTypeForUrlShorthand(type, loaders, tags), ) nuxtApp.provide('cycleValue', cycleValue) - nuxtApp.provide('sortedCategories', () => { - return tagStore.value.categories.slice().sort((a, b) => { - const headerCompare = a.header.localeCompare(b.header) - if (headerCompare !== 0) { - return headerCompare - } - if (a.header === 'resolutions' && b.header === 'resolutions') { - return a.name.replace(/\D/g, '') - b.name.replace(/\D/g, '') - } else if (a.header === 'performance impact' && b.header === 'performance impact') { - const x = ['potato', 'low', 'medium', 'high', 'screenshot'] - - return x.indexOf(a.name) - x.indexOf(b.name) - } - return 0 - }) - }) }) export const formatNumber = (number, abbreviate = true) => { const x = +number diff --git a/packages/ui/src/utils/search.ts b/packages/ui/src/utils/search.ts index b8649ce5e..8d525edf1 100644 --- a/packages/ui/src/utils/search.ts +++ b/packages/ui/src/utils/search.ts @@ -1,6 +1,6 @@ import type { Labrinth } from '@modrinth/api-client' import { ClientIcon, getCategoryIcon, getLoaderIcon, ServerIcon } from '@modrinth/assets' -import { sortByNameOrNumber } from '@modrinth/utils' +import { sortedCategories } from '@modrinth/utils' import { type Component, computed, readonly, type Ref, ref } from 'vue' import { type LocationQueryRaw, type LocationQueryValue, useRoute } from 'vue-router' @@ -114,26 +114,14 @@ export function useSearch( const toggledGroups = ref([]) const overriddenProvidedFilterTypes = ref([]) - const { formatMessage } = useVIntl() + const { formatMessage, locale } = useVIntl() + const formatCategoryName = (categoryName: string) => { + return formatCategory(formatMessage, categoryName) + } const filters = computed(() => { const categoryFilters: Record = {} - const sortedCategories = sortByNameOrNumber(tags.value.categories.slice(), ['header', 'name']) - sortedCategories.sort((a, b) => { - if (a.header === 'performance impact' && b.header === 'performance impact') { - const qualityOrder = ['potato', 'low', 'medium', 'high', 'screenshot'] - const aIndex = qualityOrder.indexOf(a.name) - const bIndex = qualityOrder.indexOf(b.name) - - if (aIndex !== -1 && bIndex !== -1) { - return aIndex - bIndex - } - if (aIndex !== -1) return -1 - if (bIndex !== -1) return 1 - } - return 0 - }) - for (const category of sortedCategories) { + for (const category of sortedCategories(tags.value, formatCategoryName, locale.value)) { const filterTypeId = `category_${category.project_type}_${category.header}` if (!categoryFilters[filterTypeId]) { categoryFilters[filterTypeId] = { diff --git a/packages/utils/utils.ts b/packages/utils/utils.ts index d15ee0a4b..25147c456 100644 --- a/packages/utils/utils.ts +++ b/packages/utils/utils.ts @@ -60,20 +60,21 @@ export const computeVersions = (versions, members) => { .sort((a, b) => dayjs(b.date_published) - dayjs(a.date_published)) } -export const sortedCategories = (tags) => { +export const sortedCategories = (tags, formatCategoryName, locale) => { return tags.categories.slice().sort((a, b) => { const headerCompare = a.header.localeCompare(b.header) if (headerCompare !== 0) { return headerCompare } - if (a.header === 'resolutions' && b.header === 'resolutions') { - return a.name.replace(/\D/g, '') - b.name.replace(/\D/g, '') - } else if (a.header === 'performance impact' && b.header === 'performance impact') { - const x = ['potato', 'low', 'medium', 'high', 'screenshot'] + if (a.header === 'performance impact' && b.header === 'performance impact') { + const x = ['potato', 'low', 'medium', 'high', 'screenshot'] return x.indexOf(a.name) - x.indexOf(b.name) } - return 0 + + const aFormatted = formatCategoryName(a.name) + const bFormatted = formatCategoryName(b.name) + return aFormatted.localeCompare(bFormatted, locale, { numeric: true }) }) } @@ -286,32 +287,6 @@ export const acceptFileFromProjectType = (projectType) => { } } -// Sorts alphabetically, but correctly identifies 8x, 128x, 256x, etc -// identifier[0], then if it ties, identifier[1], etc -export const sortByNameOrNumber = (sortable, identifiers) => { - sortable.sort((a, b) => { - for (const identifier of identifiers) { - const aNum = parseFloat(a[identifier]) - const bNum = parseFloat(b[identifier]) - if (isNaN(aNum) && isNaN(bNum)) { - // Both are strings, sort alphabetically - const stringComp = a[identifier].localeCompare(b[identifier]) - if (stringComp != 0) return stringComp - } else if (!isNaN(aNum) && !isNaN(bNum)) { - // Both are numbers, sort numerically - const numComp = aNum - bNum - if (numComp != 0) return numComp - } else { - // One is a number and one is a string, numbers go first - const numStringComp = isNaN(aNum) ? 1 : -1 - if (numStringComp != 0) return numStringComp - } - } - return 0 - }) - return sortable -} - export const getArrayOrString = (x: string[] | string): string[] => { if (typeof x === 'string') { return [x]