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[]
|
||||
|
||||
Reference in New Issue
Block a user