Sort categories by translated name (#5307)
* Sort categories by translated name * Use locale and numeric * Remove @modrinth/ui import
This commit is contained in:
@@ -154,19 +154,23 @@ interface Category {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tags = useGeneratedState()
|
const tags = useGeneratedState()
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage, locale } = useVIntl()
|
||||||
|
|
||||||
const { projectV2: project, patchProject } = injectProjectPageContext()
|
const { projectV2: project, patchProject } = injectProjectPageContext()
|
||||||
|
|
||||||
|
const formatCategoryName = (categoryName: string) => {
|
||||||
|
return formatCategory(formatMessage, categoryName)
|
||||||
|
}
|
||||||
|
|
||||||
const { saved, current, saving, reset, save } = useSavable(
|
const { saved, current, saving, reset, save } = useSavable(
|
||||||
() => ({
|
() => ({
|
||||||
selectedTags: sortedCategories(tags.value).filter(
|
selectedTags: sortedCategories(tags.value, formatCategoryName, locale.value).filter(
|
||||||
(x: Category) =>
|
(x: Category) =>
|
||||||
x.project_type === project.value.actualProjectType &&
|
x.project_type === project.value.actualProjectType &&
|
||||||
(project.value.categories.includes(x.name) ||
|
(project.value.categories.includes(x.name) ||
|
||||||
project.value.additional_categories.includes(x.name)),
|
project.value.additional_categories.includes(x.name)),
|
||||||
) as Category[],
|
) as Category[],
|
||||||
featuredTags: sortedCategories(tags.value).filter(
|
featuredTags: sortedCategories(tags.value, formatCategoryName, locale.value).filter(
|
||||||
(x: Category) =>
|
(x: Category) =>
|
||||||
x.project_type === project.value.actualProjectType &&
|
x.project_type === project.value.actualProjectType &&
|
||||||
project.value.categories.includes(x.name),
|
project.value.categories.includes(x.name),
|
||||||
@@ -212,7 +216,7 @@ const { saved, current, saving, reset, save } = useSavable(
|
|||||||
|
|
||||||
const categoryLists = computed(() => {
|
const categoryLists = computed(() => {
|
||||||
const lists: Record<string, Category[]> = {}
|
const lists: Record<string, Category[]> = {}
|
||||||
sortedCategories(tags.value).forEach((x: Category) => {
|
sortedCategories(tags.value, formatCategoryName, locale.value).forEach((x: Category) => {
|
||||||
if (x.project_type === project.value.actualProjectType) {
|
if (x.project_type === project.value.actualProjectType) {
|
||||||
const header = x.header
|
const header = x.header
|
||||||
if (!lists[header]) {
|
if (!lists[header]) {
|
||||||
@@ -253,9 +257,11 @@ const multipleResolutionTagsWarning = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const allTagsSelectedWarning = computed(() => {
|
const allTagsSelectedWarning = computed(() => {
|
||||||
const categoriesForProjectType = sortedCategories(tags.value).filter(
|
const categoriesForProjectType = sortedCategories(
|
||||||
(x: Category) => x.project_type === project.value.actualProjectType,
|
tags.value,
|
||||||
)
|
formatCategoryName,
|
||||||
|
locale.value,
|
||||||
|
).filter((x: Category) => x.project_type === project.value.actualProjectType)
|
||||||
const totalSelectedTags = current.value.selectedTags.length
|
const totalSelectedTags = current.value.selectedTags.length
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -104,22 +104,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
getProjectTypeForUrlShorthand(type, loaders, tags),
|
getProjectTypeForUrlShorthand(type, loaders, tags),
|
||||||
)
|
)
|
||||||
nuxtApp.provide('cycleValue', cycleValue)
|
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) => {
|
export const formatNumber = (number, abbreviate = true) => {
|
||||||
const x = +number
|
const x = +number
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Labrinth } from '@modrinth/api-client'
|
import type { Labrinth } from '@modrinth/api-client'
|
||||||
import { ClientIcon, getCategoryIcon, getLoaderIcon, ServerIcon } from '@modrinth/assets'
|
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 Component, computed, readonly, type Ref, ref } from 'vue'
|
||||||
import { type LocationQueryRaw, type LocationQueryValue, useRoute } from 'vue-router'
|
import { type LocationQueryRaw, type LocationQueryValue, useRoute } from 'vue-router'
|
||||||
|
|
||||||
@@ -114,26 +114,14 @@ export function useSearch(
|
|||||||
const toggledGroups = ref<string[]>([])
|
const toggledGroups = ref<string[]>([])
|
||||||
const overriddenProvidedFilterTypes = ref<string[]>([])
|
const overriddenProvidedFilterTypes = ref<string[]>([])
|
||||||
|
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage, locale } = useVIntl()
|
||||||
|
const formatCategoryName = (categoryName: string) => {
|
||||||
|
return formatCategory(formatMessage, categoryName)
|
||||||
|
}
|
||||||
|
|
||||||
const filters = computed(() => {
|
const filters = computed(() => {
|
||||||
const categoryFilters: Record<string, FilterType> = {}
|
const categoryFilters: Record<string, FilterType> = {}
|
||||||
const sortedCategories = sortByNameOrNumber(tags.value.categories.slice(), ['header', 'name'])
|
for (const category of sortedCategories(tags.value, formatCategoryName, locale.value)) {
|
||||||
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) {
|
|
||||||
const filterTypeId = `category_${category.project_type}_${category.header}`
|
const filterTypeId = `category_${category.project_type}_${category.header}`
|
||||||
if (!categoryFilters[filterTypeId]) {
|
if (!categoryFilters[filterTypeId]) {
|
||||||
categoryFilters[filterTypeId] = {
|
categoryFilters[filterTypeId] = {
|
||||||
|
|||||||
@@ -60,20 +60,21 @@ export const computeVersions = (versions, members) => {
|
|||||||
.sort((a, b) => dayjs(b.date_published) - dayjs(a.date_published))
|
.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) => {
|
return tags.categories.slice().sort((a, b) => {
|
||||||
const headerCompare = a.header.localeCompare(b.header)
|
const headerCompare = a.header.localeCompare(b.header)
|
||||||
if (headerCompare !== 0) {
|
if (headerCompare !== 0) {
|
||||||
return headerCompare
|
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 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[] => {
|
export const getArrayOrString = (x: string[] | string): string[] => {
|
||||||
if (typeof x === 'string') {
|
if (typeof x === 'string') {
|
||||||
return [x]
|
return [x]
|
||||||
|
|||||||
Reference in New Issue
Block a user