Make tags translatable, move icons to frontend, a few other things (#5229)
* Make tags translatable, move icons to frontend, a few other things * Migrate more things * fix import * more import fixes * export tag-messages * lint
This commit is contained in:
19
packages/ui/src/components/base/FormattedTag.vue
Normal file
19
packages/ui/src/components/base/FormattedTag.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { useVIntl } from '../../composables'
|
||||
import { getTagMessageOrDefault } from '../../utils/tag-messages.ts'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps<{
|
||||
tag: string
|
||||
enforceType?: 'loader' | 'category'
|
||||
}>()
|
||||
|
||||
const message = computed(() => getTagMessageOrDefault(props.tag, props.enforceType))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ typeof message === 'string' ? message : formatMessage(message) }}
|
||||
</template>
|
||||
@@ -69,14 +69,13 @@
|
||||
|
||||
<script setup>
|
||||
import { CalendarIcon, DownloadIcon, EditIcon, HeartIcon } from '@modrinth/assets'
|
||||
import { Avatar, Categories } from '@modrinth/ui'
|
||||
import { formatNumber } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime.js'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { useRelativeTime } from '../../composables'
|
||||
import Categories from '../search/Categories.vue'
|
||||
import Avatar from './Avatar.vue'
|
||||
import EnvironmentIndicator from './EnvironmentIndicator.vue'
|
||||
import Badge from './SimpleBadge.vue'
|
||||
|
||||
|
||||
21
packages/ui/src/components/base/TagIcon.vue
Normal file
21
packages/ui/src/components/base/TagIcon.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { getCategoryIcon, getLoaderIcon, getTagIcon } from '@modrinth/assets'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
tag: string
|
||||
enforceType?: 'loader' | 'category'
|
||||
}>()
|
||||
|
||||
const icon = computed(() =>
|
||||
props.enforceType === 'loader'
|
||||
? getLoaderIcon(props.tag)
|
||||
: props.enforceType === 'category'
|
||||
? getCategoryIcon(props.tag)
|
||||
: getTagIcon(props.tag),
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component :is="icon" v-if="icon" />
|
||||
</template>
|
||||
@@ -28,6 +28,7 @@ export type { FilterBarOption } from './FilterBar.vue'
|
||||
export { default as FilterBar } from './FilterBar.vue'
|
||||
export { default as FloatingActionBar } from './FloatingActionBar.vue'
|
||||
export { default as FloatingPanel } from './FloatingPanel.vue'
|
||||
export { default as FormattedTag } from './FormattedTag.vue'
|
||||
export { default as HeadingLink } from './HeadingLink.vue'
|
||||
export { default as HorizontalRule } from './HorizontalRule.vue'
|
||||
export { default as IconSelect } from './IconSelect.vue'
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
:key="tag"
|
||||
class="text-sm font-semibold text-secondary flex gap-1 px-[0.375rem] py-0.5 bg-button-bg rounded-full"
|
||||
>
|
||||
{{ formatCategory(tag) }}
|
||||
<FormattedTag :tag="tag" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,10 +65,10 @@
|
||||
|
||||
<script setup>
|
||||
import { DownloadIcon, HeartIcon, HistoryIcon, TagsIcon } from '@modrinth/assets'
|
||||
import { formatCategory, formatNumber } from '@modrinth/utils'
|
||||
import { Avatar, FormattedTag } from '@modrinth/ui'
|
||||
import { formatNumber } from '@modrinth/utils'
|
||||
|
||||
import { useRelativeTime } from '../../composables'
|
||||
import Avatar from '../base/Avatar.vue'
|
||||
|
||||
const formatRelativeTime = useRelativeTime()
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
:key="index"
|
||||
:action="() => router.push(`/${project.project_type}s?f=categories:${category}`)"
|
||||
>
|
||||
{{ formatCategory(category) }}
|
||||
<FormattedTag :tag="category" />
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,11 +54,12 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { DownloadIcon, HeartIcon, TagsIcon } from '@modrinth/assets'
|
||||
import { formatCategory, formatNumber, type Project } from '@modrinth/utils'
|
||||
import { formatNumber, type Project } from '@modrinth/utils'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import Avatar from '../base/Avatar.vue'
|
||||
import ContentPageHeader from '../base/ContentPageHeader.vue'
|
||||
import FormattedTag from '../base/FormattedTag.vue'
|
||||
import TagItem from '../base/TagItem.vue'
|
||||
import ProjectStatusBadge from './ProjectStatusBadge.vue'
|
||||
|
||||
|
||||
@@ -149,9 +149,8 @@
|
||||
:style="`--_color: var(--color-platform-${platform})`"
|
||||
:action="() => versionFilters?.toggleFilter('platform', platform)"
|
||||
>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<svg v-html="loaders.find((x) => x.name === platform)?.icon"></svg>
|
||||
{{ formatCategory(platform) }}
|
||||
<component :is="getLoaderIcon(platform)" v-if="getLoaderIcon(platform)" />
|
||||
<FormattedTag :tag="platform" enforce-type="loader" />
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
@@ -221,11 +220,18 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { CalendarIcon, DownloadIcon, PlusIcon, StarIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled } from '@modrinth/ui'
|
||||
import { CalendarIcon, DownloadIcon, getLoaderIcon, PlusIcon, StarIcon } from '@modrinth/assets'
|
||||
import {
|
||||
AutoLink,
|
||||
ButtonStyled,
|
||||
FormattedTag,
|
||||
Pagination,
|
||||
TagItem,
|
||||
VersionChannelIndicator,
|
||||
VersionFilterControl,
|
||||
} from '@modrinth/ui'
|
||||
import {
|
||||
formatBytes,
|
||||
formatCategory,
|
||||
formatNumber,
|
||||
formatVersionsForDisplay,
|
||||
type GameVersionTag,
|
||||
@@ -237,9 +243,6 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import { useRelativeTime } from '../../composables'
|
||||
import { useVIntl } from '../../composables/i18n'
|
||||
import { commonMessages } from '../../utils/common-messages'
|
||||
import AutoLink from '../base/AutoLink.vue'
|
||||
import TagItem from '../base/TagItem.vue'
|
||||
import { Pagination, VersionChannelIndicator, VersionFilterControl } from '../index'
|
||||
import { getEnvironmentTags } from './settings/environment/environments'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
:action="() => router.push(`/${project.project_type}s?g=categories:${platform}`)"
|
||||
:style="`--_color: var(--color-platform-${platform})`"
|
||||
>
|
||||
<svg v-html="tags.loaders.find((x) => x.name === platform)?.icon"></svg>
|
||||
{{ formatCategory(platform) }}
|
||||
<component :is="getLoaderIcon(platform)" v-if="getLoaderIcon(platform)" />
|
||||
<FormattedTag :tag="platform" enforce-type="loader" />
|
||||
</TagItem>
|
||||
</div>
|
||||
</section>
|
||||
@@ -85,9 +85,16 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ClientIcon, MonitorSmartphoneIcon, ServerIcon, UserIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ClientIcon,
|
||||
getLoaderIcon,
|
||||
MonitorSmartphoneIcon,
|
||||
ServerIcon,
|
||||
UserIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { FormattedTag, TagItem } from '@modrinth/ui'
|
||||
import type { EnvironmentV3, GameVersionTag, PlatformTag, ProjectV3Partial } from '@modrinth/utils'
|
||||
import { formatCategory, getVersionsToDisplay } from '@modrinth/utils'
|
||||
import { getVersionsToDisplay } from '@modrinth/utils'
|
||||
import { type Component, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
@@ -97,7 +104,6 @@ import {
|
||||
type MessageDescriptor,
|
||||
useVIntl,
|
||||
} from '../../composables/i18n'
|
||||
import TagItem from '../base/TagItem.vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const router = useRouter()
|
||||
|
||||
@@ -33,13 +33,13 @@
|
||||
>
|
||||
<CalendarIcon aria-hidden="true" />
|
||||
<div>
|
||||
{{ formatMessage(messages.published, { date: publishedDate }) }}
|
||||
{{ capitalizeString(formatMessage(messages.published, { date: publishedDate })) }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else v-tooltip="dayjs(project.published).format('MMMM D, YYYY [at] h:mm A')">
|
||||
<CalendarIcon aria-hidden="true" />
|
||||
<div>
|
||||
{{ formatMessage(messages.created, { date: createdDate }) }}
|
||||
{{ capitalizeString(formatMessage(messages.created, { date: createdDate })) }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -48,7 +48,7 @@
|
||||
>
|
||||
<ScaleIcon aria-hidden="true" />
|
||||
<div>
|
||||
{{ formatMessage(messages.submitted, { date: submittedDate }) }}
|
||||
{{ capitalizeString(formatMessage(messages.submitted, { date: submittedDate })) }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -57,7 +57,7 @@
|
||||
>
|
||||
<VersionIcon aria-hidden="true" />
|
||||
<div>
|
||||
{{ formatMessage(messages.updated, { date: updatedDate }) }}
|
||||
{{ capitalizeString(formatMessage(messages.updated, { date: updatedDate })) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,6 +65,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { BookTextIcon, CalendarIcon, ExternalIcon, ScaleIcon, VersionIcon } from '@modrinth/assets'
|
||||
import { capitalizeString } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed } from 'vue'
|
||||
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
<template>
|
||||
<div class="categories">
|
||||
<slot />
|
||||
<span
|
||||
v-for="category in categories"
|
||||
:key="category.name"
|
||||
v-html="category.icon + formatCategory(category.name)"
|
||||
/>
|
||||
<span v-for="category in categories.filter((x) => !!x)" :key="category">
|
||||
<component :is="getTagIcon(category)" v-if="getTagIcon(category)" />
|
||||
{{ getFormattedMessage(category) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { formatCategory } from '@modrinth/utils'
|
||||
<script setup lang="ts">
|
||||
import { getTagIcon } from '@modrinth/assets'
|
||||
|
||||
defineProps({
|
||||
categories: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
})
|
||||
import { useVIntl } from '../../composables'
|
||||
import { getTagMessageOrDefault } from '../../utils/tag-messages.ts'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
defineProps<{
|
||||
categories: string[]
|
||||
}>()
|
||||
|
||||
const getFormattedMessage = (tag: string) => {
|
||||
const message = getTagMessageOrDefault(tag)
|
||||
return typeof message === 'string' ? message : formatMessage(message)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<FilterIcon class="h-5 w-5 text-secondary" />
|
||||
Platform
|
||||
<template #option="{ option }">
|
||||
{{ formatCategory(option) }}
|
||||
<FormattedTag :tag="option" enforce-type="loader" />
|
||||
</template>
|
||||
</ManySelect>
|
||||
<ManySelect
|
||||
@@ -72,7 +72,7 @@
|
||||
:action="() => toggleFilter('platform', platform)"
|
||||
>
|
||||
<XIcon />
|
||||
{{ formatCategory(platform) }}
|
||||
<FormattedTag :tag="platform" enforce-type="loader" />
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,13 +80,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { FilterIcon, XCircleIcon, XIcon } from '@modrinth/assets'
|
||||
import { formatCategory, type GameVersionTag, type Version } from '@modrinth/utils'
|
||||
import { Checkbox, FormattedTag, ManySelect, TagItem } from '@modrinth/ui'
|
||||
import type { GameVersionTag, Version } from '@modrinth/utils'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import TagItem from '../base/TagItem.vue'
|
||||
import { Checkbox, ManySelect } from '../index'
|
||||
|
||||
const props = defineProps<{
|
||||
versions: Version[]
|
||||
gameVersions: GameVersionTag[]
|
||||
|
||||
@@ -1235,6 +1235,291 @@
|
||||
"settings.sessions.title": {
|
||||
"defaultMessage": "Sessions"
|
||||
},
|
||||
"tag.category.128x": {
|
||||
"defaultMessage": "128x"
|
||||
},
|
||||
"tag.category.16x": {
|
||||
"defaultMessage": "16x"
|
||||
},
|
||||
"tag.category.256x": {
|
||||
"defaultMessage": "256x"
|
||||
},
|
||||
"tag.category.32x": {
|
||||
"defaultMessage": "32x"
|
||||
},
|
||||
"tag.category.48x": {
|
||||
"defaultMessage": "48x"
|
||||
},
|
||||
"tag.category.512x+": {
|
||||
"defaultMessage": "512x or higher"
|
||||
},
|
||||
"tag.category.64x": {
|
||||
"defaultMessage": "64x"
|
||||
},
|
||||
"tag.category.8x-": {
|
||||
"defaultMessage": "8x or lower"
|
||||
},
|
||||
"tag.category.adventure": {
|
||||
"defaultMessage": "Adventure"
|
||||
},
|
||||
"tag.category.atmosphere": {
|
||||
"defaultMessage": "Atmosphere"
|
||||
},
|
||||
"tag.category.audio": {
|
||||
"defaultMessage": "Audio"
|
||||
},
|
||||
"tag.category.blocks": {
|
||||
"defaultMessage": "Blocks"
|
||||
},
|
||||
"tag.category.bloom": {
|
||||
"defaultMessage": "Bloom"
|
||||
},
|
||||
"tag.category.cartoon": {
|
||||
"defaultMessage": "Cartoon"
|
||||
},
|
||||
"tag.category.challenging": {
|
||||
"defaultMessage": "Challenging"
|
||||
},
|
||||
"tag.category.colored-lighting": {
|
||||
"defaultMessage": "Colored Lighting"
|
||||
},
|
||||
"tag.category.combat": {
|
||||
"defaultMessage": "Combat"
|
||||
},
|
||||
"tag.category.core-shaders": {
|
||||
"defaultMessage": "Core Shaders"
|
||||
},
|
||||
"tag.category.cursed": {
|
||||
"defaultMessage": "Cursed"
|
||||
},
|
||||
"tag.category.decoration": {
|
||||
"defaultMessage": "Decoration"
|
||||
},
|
||||
"tag.category.economy": {
|
||||
"defaultMessage": "Economy"
|
||||
},
|
||||
"tag.category.entities": {
|
||||
"defaultMessage": "Entities"
|
||||
},
|
||||
"tag.category.environment": {
|
||||
"defaultMessage": "Environment"
|
||||
},
|
||||
"tag.category.equipment": {
|
||||
"defaultMessage": "Equipment"
|
||||
},
|
||||
"tag.category.fantasy": {
|
||||
"defaultMessage": "Fantasy"
|
||||
},
|
||||
"tag.category.foliage": {
|
||||
"defaultMessage": "Foliage"
|
||||
},
|
||||
"tag.category.fonts": {
|
||||
"defaultMessage": "Fonts"
|
||||
},
|
||||
"tag.category.food": {
|
||||
"defaultMessage": "Food"
|
||||
},
|
||||
"tag.category.game-mechanics": {
|
||||
"defaultMessage": "Game Mechanics"
|
||||
},
|
||||
"tag.category.gui": {
|
||||
"defaultMessage": "GUI"
|
||||
},
|
||||
"tag.category.high": {
|
||||
"defaultMessage": "High"
|
||||
},
|
||||
"tag.category.items": {
|
||||
"defaultMessage": "Items"
|
||||
},
|
||||
"tag.category.kitchen-sink": {
|
||||
"defaultMessage": "Kitchen Sink"
|
||||
},
|
||||
"tag.category.library": {
|
||||
"defaultMessage": "Library"
|
||||
},
|
||||
"tag.category.lightweight": {
|
||||
"defaultMessage": "Lightweight"
|
||||
},
|
||||
"tag.category.locale": {
|
||||
"defaultMessage": "Locale"
|
||||
},
|
||||
"tag.category.low": {
|
||||
"defaultMessage": "Low"
|
||||
},
|
||||
"tag.category.magic": {
|
||||
"defaultMessage": "Magic"
|
||||
},
|
||||
"tag.category.management": {
|
||||
"defaultMessage": "Management"
|
||||
},
|
||||
"tag.category.medium": {
|
||||
"defaultMessage": "Medium"
|
||||
},
|
||||
"tag.category.minigame": {
|
||||
"defaultMessage": "Minigame"
|
||||
},
|
||||
"tag.category.mobs": {
|
||||
"defaultMessage": "Mobs"
|
||||
},
|
||||
"tag.category.modded": {
|
||||
"defaultMessage": "Modded"
|
||||
},
|
||||
"tag.category.models": {
|
||||
"defaultMessage": "Models"
|
||||
},
|
||||
"tag.category.multiplayer": {
|
||||
"defaultMessage": "Multiplayer"
|
||||
},
|
||||
"tag.category.optimization": {
|
||||
"defaultMessage": "Optimization"
|
||||
},
|
||||
"tag.category.path-tracing": {
|
||||
"defaultMessage": "Path Tracing"
|
||||
},
|
||||
"tag.category.pbr": {
|
||||
"defaultMessage": "PBR"
|
||||
},
|
||||
"tag.category.potato": {
|
||||
"defaultMessage": "Potato"
|
||||
},
|
||||
"tag.category.quests": {
|
||||
"defaultMessage": "Quests"
|
||||
},
|
||||
"tag.category.realistic": {
|
||||
"defaultMessage": "Realistic"
|
||||
},
|
||||
"tag.category.reflections": {
|
||||
"defaultMessage": "Reflections"
|
||||
},
|
||||
"tag.category.screenshot": {
|
||||
"defaultMessage": "Screenshot"
|
||||
},
|
||||
"tag.category.semi-realistic": {
|
||||
"defaultMessage": "Semi Realistic"
|
||||
},
|
||||
"tag.category.shadows": {
|
||||
"defaultMessage": "Shadows"
|
||||
},
|
||||
"tag.category.simplistic": {
|
||||
"defaultMessage": "Simplistic"
|
||||
},
|
||||
"tag.category.social": {
|
||||
"defaultMessage": "Social"
|
||||
},
|
||||
"tag.category.storage": {
|
||||
"defaultMessage": "Storage"
|
||||
},
|
||||
"tag.category.technology": {
|
||||
"defaultMessage": "Technology"
|
||||
},
|
||||
"tag.category.themed": {
|
||||
"defaultMessage": "Themed"
|
||||
},
|
||||
"tag.category.transportation": {
|
||||
"defaultMessage": "Transportation"
|
||||
},
|
||||
"tag.category.tweaks": {
|
||||
"defaultMessage": "Tweaks"
|
||||
},
|
||||
"tag.category.utility": {
|
||||
"defaultMessage": "Utility"
|
||||
},
|
||||
"tag.category.vanilla-like": {
|
||||
"defaultMessage": "Vanilla Like"
|
||||
},
|
||||
"tag.category.worldgen": {
|
||||
"defaultMessage": "World Generation"
|
||||
},
|
||||
"tag.loader.babric": {
|
||||
"defaultMessage": "Babric"
|
||||
},
|
||||
"tag.loader.bta-babric": {
|
||||
"defaultMessage": "BTA (Babric)"
|
||||
},
|
||||
"tag.loader.bukkit": {
|
||||
"defaultMessage": "Bukkit"
|
||||
},
|
||||
"tag.loader.bungeecord": {
|
||||
"defaultMessage": "BungeeCord"
|
||||
},
|
||||
"tag.loader.canvas": {
|
||||
"defaultMessage": "Canvas"
|
||||
},
|
||||
"tag.loader.datapack": {
|
||||
"defaultMessage": "Data Pack"
|
||||
},
|
||||
"tag.loader.fabric": {
|
||||
"defaultMessage": "Fabric"
|
||||
},
|
||||
"tag.loader.folia": {
|
||||
"defaultMessage": "Folia"
|
||||
},
|
||||
"tag.loader.forge": {
|
||||
"defaultMessage": "Forge"
|
||||
},
|
||||
"tag.loader.geyser": {
|
||||
"defaultMessage": "Geyser Extension"
|
||||
},
|
||||
"tag.loader.iris": {
|
||||
"defaultMessage": "Iris"
|
||||
},
|
||||
"tag.loader.java-agent": {
|
||||
"defaultMessage": "Java Agent"
|
||||
},
|
||||
"tag.loader.legacy-fabric": {
|
||||
"defaultMessage": "Legacy Fabric"
|
||||
},
|
||||
"tag.loader.liteloader": {
|
||||
"defaultMessage": "LiteLoader"
|
||||
},
|
||||
"tag.loader.minecraft": {
|
||||
"defaultMessage": "Resource Pack"
|
||||
},
|
||||
"tag.loader.modloader": {
|
||||
"defaultMessage": "Risugami's ModLoader"
|
||||
},
|
||||
"tag.loader.mrpack": {
|
||||
"defaultMessage": "Modpack"
|
||||
},
|
||||
"tag.loader.neoforge": {
|
||||
"defaultMessage": "NeoForge"
|
||||
},
|
||||
"tag.loader.nilloader": {
|
||||
"defaultMessage": "NilLoader"
|
||||
},
|
||||
"tag.loader.optifine": {
|
||||
"defaultMessage": "OptiFine"
|
||||
},
|
||||
"tag.loader.ornithe": {
|
||||
"defaultMessage": "Ornithe"
|
||||
},
|
||||
"tag.loader.paper": {
|
||||
"defaultMessage": "Paper"
|
||||
},
|
||||
"tag.loader.purpur": {
|
||||
"defaultMessage": "Purpur"
|
||||
},
|
||||
"tag.loader.quilt": {
|
||||
"defaultMessage": "Quilt"
|
||||
},
|
||||
"tag.loader.rift": {
|
||||
"defaultMessage": "Rift"
|
||||
},
|
||||
"tag.loader.spigot": {
|
||||
"defaultMessage": "Spigot"
|
||||
},
|
||||
"tag.loader.sponge": {
|
||||
"defaultMessage": "Sponge"
|
||||
},
|
||||
"tag.loader.vanilla": {
|
||||
"defaultMessage": "Vanilla Shader"
|
||||
},
|
||||
"tag.loader.velocity": {
|
||||
"defaultMessage": "Velocity"
|
||||
},
|
||||
"tag.loader.waterfall": {
|
||||
"defaultMessage": "Waterfall"
|
||||
},
|
||||
"tooltip.date-at-time": {
|
||||
"defaultMessage": "{date, date, long} at {time, time, short}"
|
||||
},
|
||||
|
||||
@@ -6,4 +6,5 @@ export * from './game-modes'
|
||||
export * from './notices'
|
||||
export * from './savable'
|
||||
export * from './search'
|
||||
export * from './tag-messages'
|
||||
export * from './vue-children'
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { ClientIcon, ServerIcon } from '@modrinth/assets'
|
||||
import { formatCategory, formatCategoryHeader, sortByNameOrNumber } from '@modrinth/utils'
|
||||
import { ClientIcon, getCategoryIcon, getLoaderIcon, ServerIcon } from '@modrinth/assets'
|
||||
import { formatCategoryHeader, sortByNameOrNumber } from '@modrinth/utils'
|
||||
import { type Component, computed, readonly, type Ref, ref } from 'vue'
|
||||
import { type LocationQueryRaw, type LocationQueryValue, useRoute } from 'vue-router'
|
||||
|
||||
import { defineMessage, useVIntl } from '../composables/i18n'
|
||||
import { getTagMessageOrDefault } from './tag-messages.ts'
|
||||
|
||||
type BaseOption = {
|
||||
id: string
|
||||
@@ -111,7 +112,22 @@ export function useSearch(
|
||||
|
||||
const filters = computed(() => {
|
||||
const categoryFilters: Record<string, FilterType> = {}
|
||||
for (const category of sortByNameOrNumber(tags.value.categories.slice(), ['header', 'name'])) {
|
||||
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) {
|
||||
const filterTypeId = `category_${category.project_type}_${category.header}`
|
||||
if (!categoryFilters[filterTypeId]) {
|
||||
categoryFilters[filterTypeId] = {
|
||||
@@ -120,7 +136,7 @@ export function useSearch(
|
||||
supported_project_types:
|
||||
category.project_type === 'mod'
|
||||
? ['mod', 'plugin', 'datapack']
|
||||
: [category.project_type],
|
||||
: ([category.project_type] as ProjectType[]),
|
||||
display: 'all',
|
||||
query_param: category.header === 'resolutions' ? 'g' : 'f',
|
||||
supports_negative_filter: true,
|
||||
@@ -128,10 +144,11 @@ export function useSearch(
|
||||
options: [],
|
||||
}
|
||||
}
|
||||
const message = getTagMessageOrDefault(category.name, 'category')
|
||||
categoryFilters[filterTypeId].options.push({
|
||||
id: category.name,
|
||||
formatted_name: formatCategory(category.name),
|
||||
icon: category.icon,
|
||||
formatted_name: typeof message === 'string' ? message : formatMessage(message),
|
||||
icon: getCategoryIcon(category.name),
|
||||
value: `categories:${category.name}`,
|
||||
method: category.header === 'resolutions' ? 'or' : 'and',
|
||||
})
|
||||
@@ -225,7 +242,7 @@ export function useSearch(
|
||||
display: 'expandable',
|
||||
query_param: 'g',
|
||||
supports_negative_filter: true,
|
||||
default_values: ['fabric', 'forge', 'neoforge', 'quilt'],
|
||||
default_values: ['fabric', 'forge', 'neoforge'],
|
||||
searchable: false,
|
||||
options: tags.value.loaders
|
||||
.filter(
|
||||
@@ -235,10 +252,11 @@ export function useSearch(
|
||||
!loader.supported_project_types.includes('datapack'),
|
||||
)
|
||||
.map((loader) => {
|
||||
const message = getTagMessageOrDefault(loader.name, 'loader')
|
||||
return {
|
||||
id: loader.name,
|
||||
formatted_name: formatCategory(loader.name),
|
||||
icon: loader.icon,
|
||||
formatted_name: typeof message === 'string' ? message : formatMessage(message),
|
||||
icon: getLoaderIcon(loader.name),
|
||||
method: 'or',
|
||||
value: `categories:${loader.name}`,
|
||||
}
|
||||
@@ -261,10 +279,11 @@ export function useSearch(
|
||||
options: tags.value.loaders
|
||||
.filter((loader) => loader.supported_project_types.includes('modpack'))
|
||||
.map((loader) => {
|
||||
const message = getTagMessageOrDefault(loader.name, 'loader')
|
||||
return {
|
||||
id: loader.name,
|
||||
formatted_name: formatCategory(loader.name),
|
||||
icon: loader.icon,
|
||||
formatted_name: typeof message === 'string' ? message : formatMessage(message),
|
||||
icon: getLoaderIcon(loader.name),
|
||||
method: 'or',
|
||||
value: `categories:${loader.name}`,
|
||||
}
|
||||
@@ -290,10 +309,11 @@ export function useSearch(
|
||||
!PLUGIN_PLATFORMS.includes(loader.name),
|
||||
)
|
||||
.map((loader) => {
|
||||
const message = getTagMessageOrDefault(loader.name, 'loader')
|
||||
return {
|
||||
id: loader.name,
|
||||
formatted_name: formatCategory(loader.name),
|
||||
icon: loader.icon,
|
||||
formatted_name: typeof message === 'string' ? message : formatMessage(message),
|
||||
icon: getLoaderIcon(loader.name),
|
||||
method: 'or',
|
||||
value: `categories:${loader.name}`,
|
||||
}
|
||||
@@ -315,10 +335,11 @@ export function useSearch(
|
||||
options: tags.value.loaders
|
||||
.filter((loader) => PLUGIN_PLATFORMS.includes(loader.name))
|
||||
.map((loader) => {
|
||||
const message = getTagMessageOrDefault(loader.name, 'loader')
|
||||
return {
|
||||
id: loader.name,
|
||||
formatted_name: formatCategory(loader.name),
|
||||
icon: loader.icon,
|
||||
formatted_name: typeof message === 'string' ? message : formatMessage(message),
|
||||
icon: getLoaderIcon(loader.name),
|
||||
method: 'or',
|
||||
value: `categories:${loader.name}`,
|
||||
}
|
||||
@@ -333,17 +354,19 @@ export function useSearch(
|
||||
}),
|
||||
),
|
||||
supported_project_types: ['shader'],
|
||||
display: 'all',
|
||||
query_param: 'g',
|
||||
supports_negative_filter: true,
|
||||
searchable: false,
|
||||
display: 'expandable',
|
||||
default_values: ['iris', 'optifine', 'vanilla'],
|
||||
options: tags.value.loaders
|
||||
.filter((loader) => loader.supported_project_types.includes('shader'))
|
||||
.map((loader) => {
|
||||
const message = getTagMessageOrDefault(loader.name, 'loader')
|
||||
return {
|
||||
id: loader.name,
|
||||
formatted_name: formatCategory(loader.name),
|
||||
icon: loader.icon,
|
||||
formatted_name: typeof message === 'string' ? message : formatMessage(message),
|
||||
icon: getLoaderIcon(loader.name),
|
||||
method: 'or',
|
||||
value: `categories:${loader.name}`,
|
||||
}
|
||||
|
||||
409
packages/ui/src/utils/tag-messages.ts
Normal file
409
packages/ui/src/utils/tag-messages.ts
Normal file
@@ -0,0 +1,409 @@
|
||||
import { capitalizeString } from '@modrinth/utils'
|
||||
|
||||
import { defineMessages, type MessageDescriptor } from '../composables/i18n'
|
||||
|
||||
export const loaderMessages = defineMessages({
|
||||
babric: {
|
||||
id: 'tag.loader.babric',
|
||||
defaultMessage: 'Babric',
|
||||
},
|
||||
'bta-babric': {
|
||||
id: 'tag.loader.bta-babric',
|
||||
defaultMessage: 'BTA (Babric)',
|
||||
},
|
||||
bukkit: {
|
||||
id: 'tag.loader.bukkit',
|
||||
defaultMessage: 'Bukkit',
|
||||
},
|
||||
bungeecord: {
|
||||
id: 'tag.loader.bungeecord',
|
||||
defaultMessage: 'BungeeCord',
|
||||
},
|
||||
canvas: {
|
||||
id: 'tag.loader.canvas',
|
||||
defaultMessage: 'Canvas',
|
||||
},
|
||||
datapack: {
|
||||
id: 'tag.loader.datapack',
|
||||
defaultMessage: 'Data Pack',
|
||||
},
|
||||
fabric: {
|
||||
id: 'tag.loader.fabric',
|
||||
defaultMessage: 'Fabric',
|
||||
},
|
||||
folia: {
|
||||
id: 'tag.loader.folia',
|
||||
defaultMessage: 'Folia',
|
||||
},
|
||||
forge: {
|
||||
id: 'tag.loader.forge',
|
||||
defaultMessage: 'Forge',
|
||||
},
|
||||
geyser: {
|
||||
id: 'tag.loader.geyser',
|
||||
defaultMessage: 'Geyser Extension',
|
||||
},
|
||||
iris: {
|
||||
id: 'tag.loader.iris',
|
||||
defaultMessage: 'Iris',
|
||||
},
|
||||
'java-agent': {
|
||||
id: 'tag.loader.java-agent',
|
||||
defaultMessage: 'Java Agent',
|
||||
},
|
||||
'legacy-fabric': {
|
||||
id: 'tag.loader.legacy-fabric',
|
||||
defaultMessage: 'Legacy Fabric',
|
||||
},
|
||||
liteloader: {
|
||||
id: 'tag.loader.liteloader',
|
||||
defaultMessage: 'LiteLoader',
|
||||
},
|
||||
minecraft: {
|
||||
id: 'tag.loader.minecraft',
|
||||
defaultMessage: 'Resource Pack',
|
||||
},
|
||||
modloader: {
|
||||
id: 'tag.loader.modloader',
|
||||
defaultMessage: "Risugami's ModLoader",
|
||||
},
|
||||
mrpack: {
|
||||
id: 'tag.loader.mrpack',
|
||||
defaultMessage: 'Modpack',
|
||||
},
|
||||
neoforge: {
|
||||
id: 'tag.loader.neoforge',
|
||||
defaultMessage: 'NeoForge',
|
||||
},
|
||||
nilloader: {
|
||||
id: 'tag.loader.nilloader',
|
||||
defaultMessage: 'NilLoader',
|
||||
},
|
||||
optifine: {
|
||||
id: 'tag.loader.optifine',
|
||||
defaultMessage: 'OptiFine',
|
||||
},
|
||||
ornithe: {
|
||||
id: 'tag.loader.ornithe',
|
||||
defaultMessage: 'Ornithe',
|
||||
},
|
||||
paper: {
|
||||
id: 'tag.loader.paper',
|
||||
defaultMessage: 'Paper',
|
||||
},
|
||||
purpur: {
|
||||
id: 'tag.loader.purpur',
|
||||
defaultMessage: 'Purpur',
|
||||
},
|
||||
quilt: {
|
||||
id: 'tag.loader.quilt',
|
||||
defaultMessage: 'Quilt',
|
||||
},
|
||||
rift: {
|
||||
id: 'tag.loader.rift',
|
||||
defaultMessage: 'Rift',
|
||||
},
|
||||
spigot: {
|
||||
id: 'tag.loader.spigot',
|
||||
defaultMessage: 'Spigot',
|
||||
},
|
||||
sponge: {
|
||||
id: 'tag.loader.sponge',
|
||||
defaultMessage: 'Sponge',
|
||||
},
|
||||
vanilla: {
|
||||
id: 'tag.loader.vanilla',
|
||||
defaultMessage: 'Vanilla Shader',
|
||||
},
|
||||
velocity: {
|
||||
id: 'tag.loader.velocity',
|
||||
defaultMessage: 'Velocity',
|
||||
},
|
||||
waterfall: {
|
||||
id: 'tag.loader.waterfall',
|
||||
defaultMessage: 'Waterfall',
|
||||
},
|
||||
})
|
||||
|
||||
export const categoryMessages = defineMessages({
|
||||
'128x': {
|
||||
id: 'tag.category.128x',
|
||||
defaultMessage: '128x',
|
||||
},
|
||||
'16x': {
|
||||
id: 'tag.category.16x',
|
||||
defaultMessage: '16x',
|
||||
},
|
||||
'256x': {
|
||||
id: 'tag.category.256x',
|
||||
defaultMessage: '256x',
|
||||
},
|
||||
'32x': {
|
||||
id: 'tag.category.32x',
|
||||
defaultMessage: '32x',
|
||||
},
|
||||
'48x': {
|
||||
id: 'tag.category.48x',
|
||||
defaultMessage: '48x',
|
||||
},
|
||||
'512x+': {
|
||||
id: 'tag.category.512x+',
|
||||
defaultMessage: '512x or higher',
|
||||
},
|
||||
'64x': {
|
||||
id: 'tag.category.64x',
|
||||
defaultMessage: '64x',
|
||||
},
|
||||
'8x-': {
|
||||
id: 'tag.category.8x-',
|
||||
defaultMessage: '8x or lower',
|
||||
},
|
||||
adventure: {
|
||||
id: 'tag.category.adventure',
|
||||
defaultMessage: 'Adventure',
|
||||
},
|
||||
atmosphere: {
|
||||
id: 'tag.category.atmosphere',
|
||||
defaultMessage: 'Atmosphere',
|
||||
},
|
||||
audio: {
|
||||
id: 'tag.category.audio',
|
||||
defaultMessage: 'Audio',
|
||||
},
|
||||
blocks: {
|
||||
id: 'tag.category.blocks',
|
||||
defaultMessage: 'Blocks',
|
||||
},
|
||||
bloom: {
|
||||
id: 'tag.category.bloom',
|
||||
defaultMessage: 'Bloom',
|
||||
},
|
||||
cartoon: {
|
||||
id: 'tag.category.cartoon',
|
||||
defaultMessage: 'Cartoon',
|
||||
},
|
||||
challenging: {
|
||||
id: 'tag.category.challenging',
|
||||
defaultMessage: 'Challenging',
|
||||
},
|
||||
'colored-lighting': {
|
||||
id: 'tag.category.colored-lighting',
|
||||
defaultMessage: 'Colored Lighting',
|
||||
},
|
||||
combat: {
|
||||
id: 'tag.category.combat',
|
||||
defaultMessage: 'Combat',
|
||||
},
|
||||
'core-shaders': {
|
||||
id: 'tag.category.core-shaders',
|
||||
defaultMessage: 'Core Shaders',
|
||||
},
|
||||
cursed: {
|
||||
id: 'tag.category.cursed',
|
||||
defaultMessage: 'Cursed',
|
||||
},
|
||||
decoration: {
|
||||
id: 'tag.category.decoration',
|
||||
defaultMessage: 'Decoration',
|
||||
},
|
||||
economy: {
|
||||
id: 'tag.category.economy',
|
||||
defaultMessage: 'Economy',
|
||||
},
|
||||
entities: {
|
||||
id: 'tag.category.entities',
|
||||
defaultMessage: 'Entities',
|
||||
},
|
||||
environment: {
|
||||
id: 'tag.category.environment',
|
||||
defaultMessage: 'Environment',
|
||||
},
|
||||
equipment: {
|
||||
id: 'tag.category.equipment',
|
||||
defaultMessage: 'Equipment',
|
||||
},
|
||||
fantasy: {
|
||||
id: 'tag.category.fantasy',
|
||||
defaultMessage: 'Fantasy',
|
||||
},
|
||||
foliage: {
|
||||
id: 'tag.category.foliage',
|
||||
defaultMessage: 'Foliage',
|
||||
},
|
||||
fonts: {
|
||||
id: 'tag.category.fonts',
|
||||
defaultMessage: 'Fonts',
|
||||
},
|
||||
food: {
|
||||
id: 'tag.category.food',
|
||||
defaultMessage: 'Food',
|
||||
},
|
||||
'game-mechanics': {
|
||||
id: 'tag.category.game-mechanics',
|
||||
defaultMessage: 'Game Mechanics',
|
||||
},
|
||||
gui: {
|
||||
id: 'tag.category.gui',
|
||||
defaultMessage: 'GUI',
|
||||
},
|
||||
high: {
|
||||
id: 'tag.category.high',
|
||||
defaultMessage: 'High',
|
||||
},
|
||||
items: {
|
||||
id: 'tag.category.items',
|
||||
defaultMessage: 'Items',
|
||||
},
|
||||
'kitchen-sink': {
|
||||
id: 'tag.category.kitchen-sink',
|
||||
defaultMessage: 'Kitchen Sink',
|
||||
},
|
||||
library: {
|
||||
id: 'tag.category.library',
|
||||
defaultMessage: 'Library',
|
||||
},
|
||||
lightweight: {
|
||||
id: 'tag.category.lightweight',
|
||||
defaultMessage: 'Lightweight',
|
||||
},
|
||||
locale: {
|
||||
id: 'tag.category.locale',
|
||||
defaultMessage: 'Locale',
|
||||
},
|
||||
low: {
|
||||
id: 'tag.category.low',
|
||||
defaultMessage: 'Low',
|
||||
},
|
||||
magic: {
|
||||
id: 'tag.category.magic',
|
||||
defaultMessage: 'Magic',
|
||||
},
|
||||
management: {
|
||||
id: 'tag.category.management',
|
||||
defaultMessage: 'Management',
|
||||
},
|
||||
medium: {
|
||||
id: 'tag.category.medium',
|
||||
defaultMessage: 'Medium',
|
||||
},
|
||||
minigame: {
|
||||
id: 'tag.category.minigame',
|
||||
defaultMessage: 'Minigame',
|
||||
},
|
||||
mobs: {
|
||||
id: 'tag.category.mobs',
|
||||
defaultMessage: 'Mobs',
|
||||
},
|
||||
modded: {
|
||||
id: 'tag.category.modded',
|
||||
defaultMessage: 'Modded',
|
||||
},
|
||||
models: {
|
||||
id: 'tag.category.models',
|
||||
defaultMessage: 'Models',
|
||||
},
|
||||
multiplayer: {
|
||||
id: 'tag.category.multiplayer',
|
||||
defaultMessage: 'Multiplayer',
|
||||
},
|
||||
optimization: {
|
||||
id: 'tag.category.optimization',
|
||||
defaultMessage: 'Optimization',
|
||||
},
|
||||
'path-tracing': {
|
||||
id: 'tag.category.path-tracing',
|
||||
defaultMessage: 'Path Tracing',
|
||||
},
|
||||
pbr: {
|
||||
id: 'tag.category.pbr',
|
||||
defaultMessage: 'PBR',
|
||||
},
|
||||
potato: {
|
||||
id: 'tag.category.potato',
|
||||
defaultMessage: 'Potato',
|
||||
},
|
||||
quests: {
|
||||
id: 'tag.category.quests',
|
||||
defaultMessage: 'Quests',
|
||||
},
|
||||
realistic: {
|
||||
id: 'tag.category.realistic',
|
||||
defaultMessage: 'Realistic',
|
||||
},
|
||||
reflections: {
|
||||
id: 'tag.category.reflections',
|
||||
defaultMessage: 'Reflections',
|
||||
},
|
||||
screenshot: {
|
||||
id: 'tag.category.screenshot',
|
||||
defaultMessage: 'Screenshot',
|
||||
},
|
||||
'semi-realistic': {
|
||||
id: 'tag.category.semi-realistic',
|
||||
defaultMessage: 'Semi Realistic',
|
||||
},
|
||||
shadows: {
|
||||
id: 'tag.category.shadows',
|
||||
defaultMessage: 'Shadows',
|
||||
},
|
||||
simplistic: {
|
||||
id: 'tag.category.simplistic',
|
||||
defaultMessage: 'Simplistic',
|
||||
},
|
||||
social: {
|
||||
id: 'tag.category.social',
|
||||
defaultMessage: 'Social',
|
||||
},
|
||||
storage: {
|
||||
id: 'tag.category.storage',
|
||||
defaultMessage: 'Storage',
|
||||
},
|
||||
technology: {
|
||||
id: 'tag.category.technology',
|
||||
defaultMessage: 'Technology',
|
||||
},
|
||||
themed: {
|
||||
id: 'tag.category.themed',
|
||||
defaultMessage: 'Themed',
|
||||
},
|
||||
transportation: {
|
||||
id: 'tag.category.transportation',
|
||||
defaultMessage: 'Transportation',
|
||||
},
|
||||
tweaks: {
|
||||
id: 'tag.category.tweaks',
|
||||
defaultMessage: 'Tweaks',
|
||||
},
|
||||
utility: {
|
||||
id: 'tag.category.utility',
|
||||
defaultMessage: 'Utility',
|
||||
},
|
||||
'vanilla-like': {
|
||||
id: 'tag.category.vanilla-like',
|
||||
defaultMessage: 'Vanilla Like',
|
||||
},
|
||||
worldgen: {
|
||||
id: 'tag.category.worldgen',
|
||||
defaultMessage: 'World Generation',
|
||||
},
|
||||
})
|
||||
|
||||
export function getTagMessage(
|
||||
tag: string,
|
||||
enforceType?: 'loader' | 'category',
|
||||
): MessageDescriptor | undefined {
|
||||
if (enforceType === 'loader') {
|
||||
return loaderMessages[tag]
|
||||
} else if (enforceType === 'category') {
|
||||
return categoryMessages[tag]
|
||||
} else {
|
||||
return loaderMessages[tag] ?? categoryMessages[tag]
|
||||
}
|
||||
}
|
||||
|
||||
export function getTagMessageOrDefault(
|
||||
tag: string,
|
||||
enforceType?: 'loader' | 'category',
|
||||
): MessageDescriptor | string {
|
||||
return getTagMessage(tag, enforceType) ?? capitalizeString(tag)
|
||||
}
|
||||
Reference in New Issue
Block a user