mirror of
https://github.com/modrinth/code.git
synced 2026-08-31 12:05:53 +00:00
disclosures in search
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<NewModal
|
||||
ref="modal"
|
||||
:header="formatMessage(messages.title)"
|
||||
:on-hide="handleHide"
|
||||
:on-after-hide="handleAfterHide"
|
||||
:closable="false"
|
||||
fade="warning"
|
||||
max-width="544px"
|
||||
>
|
||||
<div class="flex flex-col gap-6">
|
||||
<p class="m-0 leading-normal">
|
||||
{{ formatMessage(messages.body1) }}
|
||||
</p>
|
||||
<p class="m-0 leading-normal">
|
||||
{{ formatMessage(messages.body2) }}
|
||||
</p>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<Checkbox v-model="dontShowAgain" :label="formatMessage(messages.dontShowAgain)" />
|
||||
<Button type="colored" color="brand" native-type="button" @click="acknowledge">
|
||||
<CheckCircleIcon class="size-4" />
|
||||
{{ formatMessage(messages.iUnderstand) }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CheckCircleIcon } from '@modrinth/assets'
|
||||
import { ref, useTemplateRef } from 'vue'
|
||||
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
|
||||
import { defineMessages, useVIntl } from '../../composables/i18n'
|
||||
import Checkbox from '../base/Checkbox.vue'
|
||||
import NewModal from './NewModal.vue'
|
||||
|
||||
const emit = defineEmits<{
|
||||
dismiss: [dontShowAgain: boolean]
|
||||
}>()
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const modal = useTemplateRef('modal')
|
||||
const dontShowAgain = ref(false)
|
||||
let pendingDontShowAgain = false
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'search.photosensitivity-warning-modal.title',
|
||||
defaultMessage: 'Results are not guaranteed to be safe',
|
||||
},
|
||||
body1: {
|
||||
id: 'search.photosensitivity-warning-modal.body.1',
|
||||
defaultMessage:
|
||||
'We cannot guarantee that all content on Modrinth that may be dangerous for users with photosensitivity is labeled appropriately with a photosensitivity warning.',
|
||||
},
|
||||
body2: {
|
||||
id: 'search.photosensitivity-warning-modal.body.2',
|
||||
defaultMessage:
|
||||
'The label is self-assigned by the users who uploaded the content, and do not indicate that the content has gone through any kind of safety testing. Using any content on Modrinth is at your own risk. Please stay safe.',
|
||||
},
|
||||
dontShowAgain: {
|
||||
id: 'search.photosensitivity-warning-modal.dont-show-again',
|
||||
defaultMessage: "Don't show this again",
|
||||
},
|
||||
iUnderstand: {
|
||||
id: 'search.photosensitivity-warning-modal.i-understand',
|
||||
defaultMessage: 'I understand',
|
||||
},
|
||||
})
|
||||
|
||||
function show() {
|
||||
dontShowAgain.value = false
|
||||
pendingDontShowAgain = false
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
function handleHide() {
|
||||
pendingDontShowAgain = dontShowAgain.value
|
||||
}
|
||||
|
||||
function handleAfterHide() {
|
||||
emit('dismiss', pendingDontShowAgain)
|
||||
dontShowAgain.value = false
|
||||
pendingDontShowAgain = false
|
||||
}
|
||||
|
||||
function acknowledge() {
|
||||
pendingDontShowAgain = dontShowAgain.value
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
defineExpose({ show, hide })
|
||||
</script>
|
||||
@@ -3,6 +3,7 @@ export { default as ConfirmModal } from './ConfirmModal.vue'
|
||||
export { default as NewModal } from './NewModal.vue'
|
||||
export type { ServerProject as OpenInAppModalServerProject } from './OpenInAppModal.vue'
|
||||
export { default as OpenInAppModal } from './OpenInAppModal.vue'
|
||||
export { default as PhotosensitivityWarningModal } from './PhotosensitivityWarningModal.vue'
|
||||
export { default as ShareModal } from './ShareModal.vue'
|
||||
export type { Tab as TabbedModalTab } from './TabbedModal.vue'
|
||||
export { default as TabbedModal } from './TabbedModal.vue'
|
||||
|
||||
@@ -74,6 +74,7 @@ export interface BrowseManagerContext {
|
||||
serverOnlyLabel?: ComputedRef<string>
|
||||
hiddenFilterTypes?: ComputedRef<string[]>
|
||||
advancedFiltersCollapsed?: Ref<boolean>
|
||||
dismissedPhotosensitivityFilterWarning?: Ref<boolean>
|
||||
onInstalled?: (projectId: string) => void
|
||||
|
||||
displayMode?: Ref<'list' | 'grid' | 'gallery'> | ComputedRef<'list' | 'grid' | 'gallery'>
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { InfoIcon, XIcon } from '@modrinth/assets'
|
||||
import { computed, toValue } from 'vue'
|
||||
import { computed, nextTick, toValue, useTemplateRef, watch } from 'vue'
|
||||
|
||||
import { IconButton } from '#ui/components/base/buttons'
|
||||
import Toggle from '#ui/components/base/Toggle.vue'
|
||||
import PhotosensitivityWarningModal from '#ui/components/modal/PhotosensitivityWarningModal.vue'
|
||||
import SearchSidebarFilter from '#ui/components/search/SearchSidebarFilter.vue'
|
||||
import { useVIntl } from '#ui/composables/i18n'
|
||||
import { commonMessages } from '#ui/utils/common-messages'
|
||||
|
||||
import { injectBrowseManager } from './providers/browse-manager'
|
||||
|
||||
const PHOTOSENSITIVITY_FILTER_OPTION = 'epilepsy_triggers'
|
||||
|
||||
const ctx = injectBrowseManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
@@ -18,6 +21,7 @@ const lockedMessages = computed(() => toValue(ctx.lockedFilterMessages))
|
||||
const hiddenFilterTypes = computed(() => ctx.hiddenFilterTypes?.value ?? [])
|
||||
|
||||
const advancedFiltersCollapsed = computed(() => ctx.advancedFiltersCollapsed?.value ?? true)
|
||||
const photosensitivityWarningModal = useTemplateRef('photosensitivityWarningModal')
|
||||
|
||||
function setAdvancedFiltersCollapsed(collapsed: boolean) {
|
||||
if (ctx.advancedFiltersCollapsed) {
|
||||
@@ -25,6 +29,28 @@ function setAdvancedFiltersCollapsed(collapsed: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
function isPhotosensitivityExclusionSelected(filters: { type: string; option: string }[]) {
|
||||
return filters.some(
|
||||
(filter) => filter.type === 'advanced' && filter.option === PHOTOSENSITIVITY_FILTER_OPTION,
|
||||
)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => isPhotosensitivityExclusionSelected(ctx.currentFilters.value),
|
||||
(isSelected, wasSelected) => {
|
||||
if (isSelected && !wasSelected && !ctx.dismissedPhotosensitivityFilterWarning?.value) {
|
||||
nextTick(() => photosensitivityWarningModal.value?.show())
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
function onPhotosensitivityWarningDismiss(dontShowAgain: boolean) {
|
||||
if (dontShowAgain && ctx.dismissedPhotosensitivityFilterWarning) {
|
||||
ctx.dismissedPhotosensitivityFilterWarning.value = true
|
||||
}
|
||||
}
|
||||
|
||||
function closeFiltersMenu() {
|
||||
if (ctx.filtersMenuOpen) {
|
||||
ctx.filtersMenuOpen.value = false
|
||||
@@ -88,6 +114,11 @@ function getFilterOpenByDefault(filterId: string): boolean {
|
||||
<template>
|
||||
<slot name="prepend" />
|
||||
|
||||
<PhotosensitivityWarningModal
|
||||
ref="photosensitivityWarningModal"
|
||||
@dismiss="onPhotosensitivityWarningDismiss"
|
||||
/>
|
||||
|
||||
<div v-if="ctx.filtersMenuOpen?.value" class="fixed inset-0 z-40 bg-bg" />
|
||||
|
||||
<div
|
||||
|
||||
@@ -3836,15 +3836,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Erweitert"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Datenpakete ausschließen"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Mods ausschließen"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Plugins ausschließen"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Umgebung"
|
||||
},
|
||||
@@ -6240,4 +6231,3 @@
|
||||
"defaultMessage": "Typ"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3836,15 +3836,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Erweitert"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Datenpakete ausschließen"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Mods ausschließen"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Plugins ausschließen"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Umgebung"
|
||||
},
|
||||
@@ -6240,4 +6231,3 @@
|
||||
"defaultMessage": "Typ"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3876,16 +3876,31 @@
|
||||
"defaultMessage": "Show more"
|
||||
},
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Advanced"
|
||||
"defaultMessage": "Advanced exclusions"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Exclude data packs"
|
||||
"search.filter_type.advanced.disclosure.advertisements": {
|
||||
"defaultMessage": "Advertisements"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Exclude mods"
|
||||
"search.filter_type.advanced.disclosure.ai_content": {
|
||||
"defaultMessage": "AI-generated content"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Exclude plugins"
|
||||
"search.filter_type.advanced.disclosure.archived": {
|
||||
"defaultMessage": "Archived"
|
||||
},
|
||||
"search.filter_type.advanced.disclosure.derivative_work": {
|
||||
"defaultMessage": "Derivative content"
|
||||
},
|
||||
"search.filter_type.advanced.disclosure.epilepsy_triggers": {
|
||||
"defaultMessage": "Photosensitivity triggers"
|
||||
},
|
||||
"search.filter_type.advanced.disclosure.paid_features": {
|
||||
"defaultMessage": "Paid features"
|
||||
},
|
||||
"search.filter_type.advanced.disclosure.system_interactions": {
|
||||
"defaultMessage": "External system interactions"
|
||||
},
|
||||
"search.filter_type.advanced.disclosure.telemetry": {
|
||||
"defaultMessage": "Telemetry"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Environment"
|
||||
@@ -3938,6 +3953,21 @@
|
||||
"search.filter_type.shader_loader": {
|
||||
"defaultMessage": "Loader"
|
||||
},
|
||||
"search.photosensitivity-warning-modal.body.1": {
|
||||
"defaultMessage": "We cannot guarantee that all content on Modrinth that may be dangerous for users with photosensitivity is labeled appropriately with a photosensitivity warning."
|
||||
},
|
||||
"search.photosensitivity-warning-modal.body.2": {
|
||||
"defaultMessage": "The label is self-assigned by the users who uploaded the content, and do not indicate that the content has gone through any kind of safety testing. Using any content on Modrinth is at your own risk. Please stay safe."
|
||||
},
|
||||
"search.photosensitivity-warning-modal.dont-show-again": {
|
||||
"defaultMessage": "Don't show this again"
|
||||
},
|
||||
"search.photosensitivity-warning-modal.i-understand": {
|
||||
"defaultMessage": "I understand"
|
||||
},
|
||||
"search.photosensitivity-warning-modal.title": {
|
||||
"defaultMessage": "Results are not guaranteed to be safe"
|
||||
},
|
||||
"search.server_content_type.modpack": {
|
||||
"defaultMessage": "Modded"
|
||||
},
|
||||
|
||||
@@ -3851,15 +3851,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Avanzado"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Excluir paquetes de datos"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Excluir mods"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Excluir complementos"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Entorno"
|
||||
},
|
||||
@@ -6255,4 +6246,3 @@
|
||||
"defaultMessage": "Tipo"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3830,15 +3830,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Avancé"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Exclure les data packs"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Exclure les mods"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Exclure les plugins"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Environnement"
|
||||
},
|
||||
|
||||
@@ -3809,15 +3809,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Avanzate"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Escludi pacchetti di dati"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Escludi mod"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Escludi plugin"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Ambiente"
|
||||
},
|
||||
|
||||
@@ -3572,9 +3572,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "もっと見る"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "データパックを除く"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "環境"
|
||||
},
|
||||
|
||||
@@ -3836,15 +3836,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "고급"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "데이터 팩 제외"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "모드 제외"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "플러그인 제외"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "실행 환경"
|
||||
},
|
||||
|
||||
@@ -3770,15 +3770,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Gevorderd"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Gegevenspakketten uitsluiten"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Mods uitsluiten"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Plug-ins uitsluiten"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Omgeving"
|
||||
},
|
||||
|
||||
@@ -3815,15 +3815,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Zaawansowane"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Wyklucz paczki danych"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Wyklucz mody"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Wyklucz pluginy"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Środowisko"
|
||||
},
|
||||
|
||||
@@ -3851,15 +3851,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Avançado"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Excluir pacotes de dados"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Excluir mods"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Excluir plugins"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Ambiente"
|
||||
},
|
||||
@@ -6255,4 +6246,3 @@
|
||||
"defaultMessage": "Tipo"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3764,15 +3764,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Расширенные"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Исключать наборы данных"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Исключать моды"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Исключать плагины"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Среда"
|
||||
},
|
||||
|
||||
@@ -3593,15 +3593,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Napredno"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Isključi data pakete"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Isključi modove"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Isključi plugine"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Okruže"
|
||||
},
|
||||
@@ -5784,4 +5775,3 @@
|
||||
"defaultMessage": "Tip"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3455,12 +3455,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Avancerat"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Exkludera datapaket"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Exkludera moddar"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Miljö"
|
||||
},
|
||||
@@ -5442,4 +5436,3 @@
|
||||
"defaultMessage": "Typ"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3653,15 +3653,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Gelişmiş"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Veri paketlerini hariç tut"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Modları hariç tut"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Eklentileri hariç tut"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Ortam"
|
||||
},
|
||||
|
||||
@@ -3800,15 +3800,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "Більше"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "Виключити пакети даних"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "Виключити моди"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "Виключити плаґіни"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "Середовище"
|
||||
},
|
||||
|
||||
@@ -3851,15 +3851,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "高级"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "排除数据包"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "排除模组"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "排除插件"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "运行环境"
|
||||
},
|
||||
@@ -6255,4 +6246,3 @@
|
||||
"defaultMessage": "类型"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3851,15 +3851,6 @@
|
||||
"search.filter_type.advanced": {
|
||||
"defaultMessage": "進階篩選"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_datapack": {
|
||||
"defaultMessage": "排除資料包"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_mod": {
|
||||
"defaultMessage": "排除模組"
|
||||
},
|
||||
"search.filter_type.advanced.exclude_plugin": {
|
||||
"defaultMessage": "排除插件"
|
||||
},
|
||||
"search.filter_type.environment": {
|
||||
"defaultMessage": "環境"
|
||||
},
|
||||
@@ -6255,4 +6246,3 @@
|
||||
"defaultMessage": "類型"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+132
-24
@@ -1,10 +1,25 @@
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { ClientIcon, getCategoryIcon, getLoaderIcon, ServerIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ArchiveIcon,
|
||||
CircleDollarSignIcon,
|
||||
CircuitBoardIcon,
|
||||
ClientIcon,
|
||||
EyeIcon,
|
||||
getCategoryIcon,
|
||||
getLoaderIcon,
|
||||
GitForkIcon,
|
||||
MegaphoneIcon,
|
||||
RadioTowerIcon,
|
||||
ServerIcon,
|
||||
SparklesIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { sortedCategories } 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 { getProjectTypeIcon } from './auto-icons'
|
||||
import { getProjectTypeCategoryMessage } from './common-messages'
|
||||
import {
|
||||
DEFAULT_MOD_LOADERS,
|
||||
DEFAULT_PLUGIN_LOADERS,
|
||||
@@ -120,6 +135,48 @@ const PROJECT_TYPE_EXCLUSION_FILTERS: Partial<Record<ProjectType, ProjectType[]>
|
||||
datapack: ['mod', 'plugin'],
|
||||
}
|
||||
|
||||
const DISCLOSURE_TYPE_FILTERS = [
|
||||
'ai_content',
|
||||
'advertisements',
|
||||
'epilepsy_triggers',
|
||||
'system_interactions',
|
||||
'telemetry',
|
||||
'derivative_work',
|
||||
'paid_features',
|
||||
'archived',
|
||||
] as const
|
||||
|
||||
type DisclosureTypeFilter = (typeof DISCLOSURE_TYPE_FILTERS)[number]
|
||||
|
||||
const DISCLOSURE_TYPE_SUPPORTED_PROJECT_TYPES: Record<
|
||||
DisclosureTypeFilter,
|
||||
readonly ProjectType[]
|
||||
> = {
|
||||
ai_content: ALL_PROJECT_TYPES,
|
||||
advertisements: ALL_PROJECT_TYPES,
|
||||
epilepsy_triggers: ALL_PROJECT_TYPES,
|
||||
derivative_work: ALL_PROJECT_TYPES,
|
||||
paid_features: ALL_PROJECT_TYPES,
|
||||
archived: ALL_PROJECT_TYPES,
|
||||
telemetry: ['mod', 'plugin', 'modpack', 'server'],
|
||||
system_interactions: ['mod', 'plugin', 'modpack'],
|
||||
}
|
||||
|
||||
const DISCLOSURE_TYPE_ICONS: Record<DisclosureTypeFilter, Component> = {
|
||||
ai_content: SparklesIcon,
|
||||
advertisements: MegaphoneIcon,
|
||||
epilepsy_triggers: EyeIcon,
|
||||
system_interactions: CircuitBoardIcon,
|
||||
telemetry: RadioTowerIcon,
|
||||
derivative_work: GitForkIcon,
|
||||
paid_features: CircleDollarSignIcon,
|
||||
archived: ArchiveIcon,
|
||||
}
|
||||
|
||||
function isProjectTypeExclusionOption(optionId: string): optionId is ProjectType {
|
||||
return (ALL_PROJECT_TYPES as string[]).includes(optionId)
|
||||
}
|
||||
|
||||
export function useSearch(
|
||||
projectTypes: Ref<ProjectType[]>,
|
||||
tags: Ref<Tags>,
|
||||
@@ -151,31 +208,64 @@ export function useSearch(
|
||||
return formatCategory(formatMessage, categoryName)
|
||||
}
|
||||
|
||||
const formatExcludeProjectTypeLabel = (projectType: ProjectType): string => {
|
||||
switch (projectType) {
|
||||
case 'mod':
|
||||
const formatDisclosureTypeLabel = (disclosureType: DisclosureTypeFilter): string => {
|
||||
switch (disclosureType) {
|
||||
case 'ai_content':
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'search.filter_type.advanced.exclude_mod',
|
||||
defaultMessage: 'Exclude mods',
|
||||
id: 'search.filter_type.advanced.disclosure.ai_content',
|
||||
defaultMessage: 'AI-generated content',
|
||||
}),
|
||||
)
|
||||
case 'plugin':
|
||||
case 'advertisements':
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'search.filter_type.advanced.exclude_plugin',
|
||||
defaultMessage: 'Exclude plugins',
|
||||
id: 'search.filter_type.advanced.disclosure.advertisements',
|
||||
defaultMessage: 'Advertisements',
|
||||
}),
|
||||
)
|
||||
case 'datapack':
|
||||
case 'epilepsy_triggers':
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'search.filter_type.advanced.exclude_datapack',
|
||||
defaultMessage: 'Exclude data packs',
|
||||
id: 'search.filter_type.advanced.disclosure.epilepsy_triggers',
|
||||
defaultMessage: 'Photosensitivity triggers',
|
||||
}),
|
||||
)
|
||||
case 'system_interactions':
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'search.filter_type.advanced.disclosure.system_interactions',
|
||||
defaultMessage: 'External system interactions',
|
||||
}),
|
||||
)
|
||||
case 'telemetry':
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'search.filter_type.advanced.disclosure.telemetry',
|
||||
defaultMessage: 'Telemetry',
|
||||
}),
|
||||
)
|
||||
case 'derivative_work':
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'search.filter_type.advanced.disclosure.derivative_work',
|
||||
defaultMessage: 'Derivative content',
|
||||
}),
|
||||
)
|
||||
case 'paid_features':
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'search.filter_type.advanced.disclosure.paid_features',
|
||||
defaultMessage: 'Paid features',
|
||||
}),
|
||||
)
|
||||
case 'archived':
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'search.filter_type.advanced.disclosure.archived',
|
||||
defaultMessage: 'Archived',
|
||||
}),
|
||||
)
|
||||
default:
|
||||
return projectType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,21 +569,35 @@ export function useSearch(
|
||||
formatted_name: formatMessage(
|
||||
defineMessage({
|
||||
id: 'search.filter_type.advanced',
|
||||
defaultMessage: 'Advanced',
|
||||
defaultMessage: 'Advanced exclusions',
|
||||
}),
|
||||
),
|
||||
supported_project_types: ['mod', 'plugin', 'datapack'],
|
||||
supported_project_types: ALL_PROJECT_TYPES,
|
||||
display: 'all',
|
||||
query_param: 'a',
|
||||
supports: ['exclude'],
|
||||
searchable: false,
|
||||
ordering: -1000,
|
||||
options: excludeableProjectTypes.map((target) => ({
|
||||
id: target,
|
||||
formatted_name: formatExcludeProjectTypeLabel(target),
|
||||
method: 'and',
|
||||
value: `all_project_types:${mapProjectTypeToSearch(target)}`,
|
||||
})),
|
||||
options: [
|
||||
...DISCLOSURE_TYPE_FILTERS.filter((disclosureType) =>
|
||||
DISCLOSURE_TYPE_SUPPORTED_PROJECT_TYPES[disclosureType].some((projectType) =>
|
||||
projectTypes.value.includes(projectType),
|
||||
),
|
||||
).map((disclosureType) => ({
|
||||
id: disclosureType,
|
||||
formatted_name: formatDisclosureTypeLabel(disclosureType),
|
||||
icon: DISCLOSURE_TYPE_ICONS[disclosureType],
|
||||
method: 'or' as const,
|
||||
value: `disclosure_types:${disclosureType}`,
|
||||
})),
|
||||
...excludeableProjectTypes.map((target) => ({
|
||||
id: target,
|
||||
formatted_name: formatMessage(getProjectTypeCategoryMessage(target)),
|
||||
icon: getProjectTypeIcon(target),
|
||||
method: 'and' as const,
|
||||
value: `all_project_types:${mapProjectTypeToSearch(target)}`,
|
||||
})),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -503,6 +607,7 @@ export function useSearch(
|
||||
projectTypes.value.includes(projectType),
|
||||
),
|
||||
)
|
||||
.filter((filterType) => filterType.id !== 'advanced' || filterType.options.length > 0)
|
||||
.sort((a, b) => (b.ordering ?? 0) - (a.ordering ?? 0))
|
||||
})
|
||||
|
||||
@@ -526,7 +631,7 @@ export function useSearch(
|
||||
console.error(`Filter type ${filterValue.type} not found`)
|
||||
continue
|
||||
}
|
||||
if (type.id === 'advanced') {
|
||||
if (type.id === 'advanced' && isProjectTypeExclusionOption(filterValue.option)) {
|
||||
continue
|
||||
}
|
||||
let option = type?.options.find((option) => option.id === filterValue.option)
|
||||
@@ -620,7 +725,10 @@ export function useSearch(
|
||||
}
|
||||
|
||||
const excludedProjectTypes = filterValues
|
||||
.filter((filterValue) => filterValue.type === 'advanced')
|
||||
.filter(
|
||||
(filterValue) =>
|
||||
filterValue.type === 'advanced' && isProjectTypeExclusionOption(filterValue.option),
|
||||
)
|
||||
.map((filterValue) =>
|
||||
formatSearchFilterValue(mapProjectTypeToSearch(filterValue.option as ProjectType)),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user