mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 13:16:38 +00:00
cleaup app layout, add missing translations to it (#6904)
* cleaup app layout, add missing translations to it * remove feature flag in backend * add app-messages * clean up nav slightly * allow more than 3 quick instances * make quick instances resizable
This commit is contained in:
+90
-196
@@ -10,24 +10,20 @@ import {
|
||||
} from '@modrinth/api-client'
|
||||
import {
|
||||
ArrowBigUpDashIcon,
|
||||
ChangeSkinIcon,
|
||||
CompassIcon,
|
||||
ExternalIcon,
|
||||
HomeIcon,
|
||||
LeftArrowIcon,
|
||||
LibraryIcon,
|
||||
LogInIcon,
|
||||
LogOutIcon,
|
||||
NewspaperIcon,
|
||||
NotepadTextIcon,
|
||||
PlusIcon,
|
||||
RefreshCwIcon,
|
||||
RightArrowIcon,
|
||||
ServerStackIcon,
|
||||
SettingsIcon,
|
||||
ShirtIcon,
|
||||
UserIcon,
|
||||
WorldIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
@@ -39,6 +35,7 @@ import {
|
||||
CreationFlowModal,
|
||||
defineMessages,
|
||||
I18nDebugPanel,
|
||||
IntlFormatted,
|
||||
LoadingBar,
|
||||
NewsArticleCard,
|
||||
NotificationPanel,
|
||||
@@ -63,7 +60,6 @@ import { fetch as tauriFetch } from '@tauri-apps/plugin-http'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
|
||||
import { $fetch } from 'ofetch'
|
||||
import { computed, onMounted, onUnmounted, provide, ref, watch } from 'vue'
|
||||
import { RouterView, useRoute, useRouter } from 'vue-router'
|
||||
|
||||
@@ -88,6 +84,7 @@ import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
|
||||
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
|
||||
import SharedInstanceInviteHandler from '@/components/ui/shared-instances/shared-instance-invite-handler/index.vue'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
import SurveyPopup from '@/components/ui/SurveyPopup.vue'
|
||||
import WindowControls from '@/components/ui/WindowControls.vue'
|
||||
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
||||
import { config } from '@/config'
|
||||
@@ -104,12 +101,7 @@ import { check_reachable } from '@/helpers/auth.js'
|
||||
import { get_user, get_version } from '@/helpers/cache.js'
|
||||
import { command_listener, notification_listener, warning_listener } from '@/helpers/events.js'
|
||||
import { install_create_modpack_instance, install_get_modpack_preview } from '@/helpers/install'
|
||||
import {
|
||||
can_current_user_use_shared_instances,
|
||||
get as getInstance,
|
||||
list,
|
||||
run,
|
||||
} from '@/helpers/instance'
|
||||
import { can_current_user_use_shared_instances, get as getInstance, run } from '@/helpers/instance'
|
||||
import { get as getCreds, login, logout } from '@/helpers/mr_auth.ts'
|
||||
import { mergeUrlQuery, parseModrinthLink } from '@/helpers/project-links.ts'
|
||||
import { get as getSettings, set as setSettings } from '@/helpers/settings.ts'
|
||||
@@ -148,6 +140,7 @@ import { setupAuthProvider } from '@/providers/setup/auth'
|
||||
import { setupLoadingStateProvider } from '@/providers/setup/loading-state'
|
||||
import { useError } from '@/store/error.js'
|
||||
import { useTheming } from '@/store/state'
|
||||
import { appMessages } from '@/utils/app-messages'
|
||||
|
||||
import { generateSkinPreviews } from './helpers/rendering/batch-skin-renderer'
|
||||
import { get_available_capes, get_available_skins } from './helpers/skins'
|
||||
@@ -289,7 +282,6 @@ const {
|
||||
} = setupProviders(notificationManager, popupNotificationManager)
|
||||
|
||||
const news = ref([])
|
||||
const availableSurvey = ref(false)
|
||||
const displayedServerInviteNotifications = new Set()
|
||||
const serverInvitePopupNotificationIds = new Set()
|
||||
let liveNotificationGeneration = 0
|
||||
@@ -403,6 +395,54 @@ const messages = defineMessages({
|
||||
id: 'app.ads-consent.accept',
|
||||
defaultMessage: 'Accept all',
|
||||
},
|
||||
home: {
|
||||
id: 'app.nav.home',
|
||||
defaultMessage: 'Home',
|
||||
},
|
||||
library: {
|
||||
id: 'app.nav.library',
|
||||
defaultMessage: 'Library',
|
||||
},
|
||||
modrinthHosting: {
|
||||
id: 'app.nav.modrinth-hosting',
|
||||
defaultMessage: 'Modrinth Hosting',
|
||||
},
|
||||
createNewInstance: {
|
||||
id: 'app.nav.create-new-instance',
|
||||
defaultMessage: 'Create new instance',
|
||||
},
|
||||
modrinthAccount: {
|
||||
id: 'app.nav.modrinth-account',
|
||||
defaultMessage: 'Modrinth account',
|
||||
},
|
||||
signedInAs: {
|
||||
id: 'app.nav.signed-in-as',
|
||||
defaultMessage: 'Signed in as <user>{username}</user>',
|
||||
},
|
||||
signInToModrinthAccount: {
|
||||
id: 'app.nav.sign-in-to-modrinth-account',
|
||||
defaultMessage: 'Sign in to a Modrinth account',
|
||||
},
|
||||
restarting: {
|
||||
id: 'app.restarting',
|
||||
defaultMessage: 'Restarting...',
|
||||
},
|
||||
upgradeToModrinthPlus: {
|
||||
id: 'app.nav.upgrade-to-modrinth-plus',
|
||||
defaultMessage: 'Upgrade to Modrinth+',
|
||||
},
|
||||
news: {
|
||||
id: 'app.news.title',
|
||||
defaultMessage: 'News',
|
||||
},
|
||||
viewAllNews: {
|
||||
id: 'app.news.view-all',
|
||||
defaultMessage: 'View all news',
|
||||
},
|
||||
playingAs: {
|
||||
id: 'app.sidebar.playing-as',
|
||||
defaultMessage: 'Playing as',
|
||||
},
|
||||
})
|
||||
|
||||
function handleAdsConsentRequired(required) {
|
||||
@@ -571,12 +611,6 @@ async function setupApp() {
|
||||
settings.pending_update_toast_for_version = null
|
||||
await setSettings(settings)
|
||||
}
|
||||
|
||||
if (osType === 'windows') {
|
||||
await processPendingSurveys()
|
||||
} else {
|
||||
console.info('Skipping user surveys on non-Windows platforms')
|
||||
}
|
||||
}
|
||||
|
||||
const stateFailed = ref(false)
|
||||
@@ -1439,115 +1473,6 @@ function handleAuxClick(e) {
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupOldSurveyDisplayData() {
|
||||
const threeWeeksAgo = new Date()
|
||||
threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21)
|
||||
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i)
|
||||
|
||||
if (key.startsWith('survey-') && key.endsWith('-display')) {
|
||||
const dateValue = new Date(localStorage.getItem(key))
|
||||
if (dateValue < threeWeeksAgo) {
|
||||
localStorage.removeItem(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function openSurvey() {
|
||||
if (!availableSurvey.value) {
|
||||
console.error('No survey to open')
|
||||
return
|
||||
}
|
||||
|
||||
const creds = await getCreds().catch(handleError)
|
||||
const userId = creds?.user_id
|
||||
|
||||
const formId = availableSurvey.value.tally_id
|
||||
|
||||
const popupOptions = {
|
||||
layout: 'modal',
|
||||
width: 700,
|
||||
autoClose: 2000,
|
||||
hideTitle: true,
|
||||
hiddenFields: {
|
||||
user_id: userId,
|
||||
},
|
||||
onOpen: () => console.info('Opened user survey'),
|
||||
onClose: () => {
|
||||
console.info('Closed user survey')
|
||||
show_ads_window()
|
||||
},
|
||||
onSubmit: () => console.info('Active user survey submitted'),
|
||||
}
|
||||
|
||||
try {
|
||||
hide_ads_window()
|
||||
if (window.Tally?.openPopup) {
|
||||
console.info(`Opening Tally popup for user survey (form ID: ${formId})`)
|
||||
dismissSurvey()
|
||||
window.Tally.openPopup(formId, popupOptions)
|
||||
} else {
|
||||
console.warn('Tally script not yet loaded')
|
||||
show_ads_window()
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error opening Tally popup:', e)
|
||||
show_ads_window()
|
||||
}
|
||||
|
||||
console.info(`Found user survey to show with tally_id: ${formId}`)
|
||||
window.Tally.openPopup(formId, popupOptions)
|
||||
}
|
||||
|
||||
function dismissSurvey() {
|
||||
localStorage.setItem(`survey-${availableSurvey.value.id}-display`, new Date())
|
||||
availableSurvey.value = undefined
|
||||
}
|
||||
|
||||
async function processPendingSurveys() {
|
||||
function isWithinLastTwoWeeks(date) {
|
||||
const twoWeeksAgo = new Date()
|
||||
twoWeeksAgo.setDate(twoWeeksAgo.getDate() - 14)
|
||||
return date >= twoWeeksAgo
|
||||
}
|
||||
|
||||
cleanupOldSurveyDisplayData()
|
||||
|
||||
const creds = await getCreds().catch(handleError)
|
||||
const userId = creds?.user_id
|
||||
|
||||
const instances = (await list().catch(handleError)) ?? []
|
||||
const isActivePlayer = instances.some(
|
||||
(instance) =>
|
||||
isWithinLastTwoWeeks(instance.last_played) && !isWithinLastTwoWeeks(instance.created),
|
||||
)
|
||||
|
||||
let surveys = []
|
||||
try {
|
||||
surveys = await $fetch('https://api.modrinth.com/v2/surveys')
|
||||
} catch (e) {
|
||||
console.error('Error fetching surveys:', e)
|
||||
}
|
||||
|
||||
const surveyToShow = surveys.find(
|
||||
(survey) =>
|
||||
!!(
|
||||
localStorage.getItem(`survey-${survey.id}-display`) === null &&
|
||||
survey.type === 'tally_app' &&
|
||||
((survey.condition === 'active_player' && isActivePlayer) ||
|
||||
(survey.assigned_users?.includes(userId) && !survey.dismissed_users?.includes(userId)))
|
||||
),
|
||||
)
|
||||
|
||||
if (surveyToShow) {
|
||||
availableSurvey.value = surveyToShow
|
||||
} else {
|
||||
console.info('No user survey to show')
|
||||
}
|
||||
}
|
||||
|
||||
provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
</script>
|
||||
|
||||
@@ -1570,7 +1495,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
class="flex items-center gap-4 text-contrast font-semibold text-xl select-none cursor-default"
|
||||
>
|
||||
<RefreshCwIcon data-tauri-drag-region class="animate-spin w-6 h-6" />
|
||||
Restarting...
|
||||
{{ formatMessage(messages.restarting) }}
|
||||
</span>
|
||||
</div>
|
||||
</Transition>
|
||||
@@ -1593,27 +1518,24 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
/>
|
||||
<UnknownPackWarningModal ref="unknownPackWarningModal" />
|
||||
<div
|
||||
class="app-grid-navbar bg-bg-raised flex flex-col p-[0.5rem] pt-0 gap-[0.5rem] w-[--left-bar-width]"
|
||||
class="app-grid-navbar bg-bg-raised flex flex-col p-[0.5rem] pt-0 gap-[0.25rem] w-[--left-bar-width]"
|
||||
>
|
||||
<NavButton v-tooltip.right="'Home'" to="/">
|
||||
<NavButton v-tooltip.right="formatMessage(messages.home)" to="/">
|
||||
<HomeIcon />
|
||||
</NavButton>
|
||||
<NavButton v-if="themeStore.featureFlags.worlds_tab" v-tooltip.right="'Worlds'" to="/worlds">
|
||||
<WorldIcon />
|
||||
</NavButton>
|
||||
<NavButton
|
||||
v-tooltip.right="'Discover content'"
|
||||
v-tooltip.right="formatMessage(commonMessages.discoverContentLabel)"
|
||||
to="/browse/modpack"
|
||||
:is-primary="() => route.path.startsWith('/browse') && !route.query.i"
|
||||
:is-subpage="(route) => route.path.startsWith('/project') && !route.query.i"
|
||||
>
|
||||
<CompassIcon />
|
||||
</NavButton>
|
||||
<NavButton v-tooltip.right="'Skin selector'" to="/skins">
|
||||
<ChangeSkinIcon />
|
||||
<NavButton v-tooltip.right="formatMessage(appMessages.skinSelectorLabel)" to="/skins">
|
||||
<ShirtIcon />
|
||||
</NavButton>
|
||||
<NavButton
|
||||
v-tooltip.right="'Library'"
|
||||
v-tooltip.right="formatMessage(messages.library)"
|
||||
to="/library"
|
||||
:is-primary="(r) => r.path === '/library' || r.path === '/library'"
|
||||
:is-subpage="
|
||||
@@ -1626,19 +1548,18 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
<LibraryIcon />
|
||||
</NavButton>
|
||||
<NavButton
|
||||
v-tooltip.right="'Modrinth Hosting'"
|
||||
v-tooltip.right="formatMessage(messages.modrinthHosting)"
|
||||
to="/hosting/manage"
|
||||
:is-primary="(r) => r.path === '/hosting/manage' || r.path === '/hosting/manage/'"
|
||||
:is-subpage="(r) => r.path.startsWith('/hosting/manage/') && r.path !== '/hosting/manage/'"
|
||||
>
|
||||
<ServerStackIcon />
|
||||
</NavButton>
|
||||
<div class="h-px w-6 mx-auto my-2 bg-surface-5"></div>
|
||||
<suspense>
|
||||
<QuickInstanceSwitcher />
|
||||
</suspense>
|
||||
<NavButton
|
||||
v-tooltip.right="'Create new instance'"
|
||||
v-tooltip.right="formatMessage(messages.createNewInstance)"
|
||||
:to="() => installationModal?.show()"
|
||||
:disabled="offline"
|
||||
>
|
||||
@@ -1653,7 +1574,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
</NavButton>
|
||||
<OverflowMenu
|
||||
v-if="credentials?.user"
|
||||
v-tooltip.right="`Modrinth account`"
|
||||
v-tooltip.right="formatMessage(messages.modrinthAccount)"
|
||||
class="w-12 h-12 text-primary rounded-full flex items-center justify-center text-2xl transition-all bg-transparent hover:bg-button-bg hover:text-contrast border-0 cursor-pointer"
|
||||
:options="[
|
||||
{
|
||||
@@ -1672,19 +1593,27 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
<template #view-profile>
|
||||
<UserIcon />
|
||||
<span class="inline-flex items-center gap-1">
|
||||
Signed in as
|
||||
<span class="inline-flex items-center gap-1 text-contrast font-semibold">
|
||||
<Avatar :src="credentials?.user?.avatar_url" alt="" size="20px" circle />
|
||||
{{ credentials?.user?.username }}
|
||||
</span>
|
||||
<IntlFormatted
|
||||
:message-id="messages.signedInAs"
|
||||
:values="{ username: credentials?.user?.username }"
|
||||
>
|
||||
<template #user="{ children }">
|
||||
<span class="inline-flex items-center gap-1 text-contrast font-semibold">
|
||||
<Avatar :src="credentials?.user?.avatar_url" alt="" size="20px" circle />
|
||||
<component :is="() => children" />
|
||||
</span>
|
||||
</template>
|
||||
</IntlFormatted>
|
||||
</span>
|
||||
<ExternalIcon />
|
||||
</template>
|
||||
<template #sign-out> <LogOutIcon /> Sign out </template>
|
||||
<template #sign-out>
|
||||
<LogOutIcon />
|
||||
{{ formatMessage(commonMessages.signOutButton) }}
|
||||
</template>
|
||||
</OverflowMenu>
|
||||
<NavButton
|
||||
v-else
|
||||
v-tooltip.right="'Sign in to a Modrinth account'"
|
||||
v-tooltip.right="formatMessage(messages.signInToModrinthAccount)"
|
||||
:to="() => requestSignIn()"
|
||||
>
|
||||
<LogInIcon class="text-brand" />
|
||||
@@ -1741,28 +1670,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
}"
|
||||
>
|
||||
<div class="app-viewport flex-grow router-view">
|
||||
<transition name="popup-survey">
|
||||
<div
|
||||
v-if="availableSurvey"
|
||||
class="w-[400px] z-20 fixed -bottom-12 pb-16 right-[--right-bar-width] mr-4 rounded-t-2xl card-shadow bg-bg-raised border-surface-5 border-[1px] border-solid border-b-0 p-4"
|
||||
>
|
||||
<h2 class="text-lg font-extrabold mt-0 mb-2">Hey there Modrinth user!</h2>
|
||||
<p class="m-0 leading-tight">
|
||||
Would you mind answering a few questions about your experience with Modrinth App?
|
||||
</p>
|
||||
<p class="mt-3 mb-4 leading-tight">
|
||||
This feedback will go directly to the Modrinth team and help guide future updates!
|
||||
</p>
|
||||
<div class="flex gap-2">
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="openSurvey"><NotepadTextIcon /> Take survey</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button @click="dismissSurvey"><XIcon /> No thanks</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<SurveyPopup />
|
||||
<div
|
||||
class="loading-indicator-container h-8 fixed z-50 pointer-events-none"
|
||||
:style="{
|
||||
@@ -1826,7 +1734,9 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
<div id="sidebar-teleport-target" class="sidebar-teleport-content"></div>
|
||||
<div class="sidebar-default-content" :class="{ 'sidebar-enabled': sidebarVisible }">
|
||||
<div class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid">
|
||||
<h3 class="text-base text-primary font-medium m-0">Playing as</h3>
|
||||
<h3 class="text-base text-primary font-medium m-0">
|
||||
{{ formatMessage(messages.playingAs) }}
|
||||
</h3>
|
||||
<suspense>
|
||||
<AccountsCard ref="accounts" />
|
||||
</suspense>
|
||||
@@ -1841,7 +1751,9 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
class="p-4 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid"
|
||||
/>
|
||||
<div v-if="news && news.length > 0" class="p-4 flex flex-col items-center">
|
||||
<h3 class="text-base mb-4 text-primary font-medium m-0 text-left w-full">News</h3>
|
||||
<h3 class="text-base mb-4 text-primary font-medium m-0 text-left w-full">
|
||||
{{ formatMessage(messages.news) }}
|
||||
</h3>
|
||||
<div class="space-y-4 flex flex-col items-center w-full">
|
||||
<NewsArticleCard
|
||||
v-for="(item, index) in news"
|
||||
@@ -1850,7 +1762,8 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
/>
|
||||
<ButtonStyled color="brand" size="large">
|
||||
<a href="https://modrinth.com/news" target="_blank" class="my-4">
|
||||
<NewspaperIcon /> View all news
|
||||
<NewspaperIcon />
|
||||
{{ formatMessage(messages.viewAllNews) }}
|
||||
</a>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
@@ -1863,7 +1776,8 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
class="absolute bottom-[250px] w-full flex justify-center items-center gap-1 px-4 py-3 text-purple font-medium hover:underline z-10"
|
||||
target="_blank"
|
||||
>
|
||||
<ArrowBigUpDashIcon class="text-2xl" /> Upgrade to Modrinth+
|
||||
<ArrowBigUpDashIcon class="text-2xl" />
|
||||
{{ formatMessage(messages.upgradeToModrinthPlus) }}
|
||||
</a>
|
||||
<PromotionWrapper />
|
||||
</template>
|
||||
@@ -2075,26 +1989,6 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.popup-survey-enter-active {
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
transform 0.25s cubic-bezier(0.51, 1.08, 0.35, 1.15);
|
||||
transform-origin: top center;
|
||||
}
|
||||
|
||||
.popup-survey-leave-active {
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
transform 0.25s cubic-bezier(0.68, -0.17, 0.23, 0.11);
|
||||
transform-origin: top center;
|
||||
}
|
||||
|
||||
.popup-survey-enter-from,
|
||||
.popup-survey-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(10rem) scale(0.8) scaleY(1.6);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.nav-button-animated-enter-active {
|
||||
transition: all 0.5s cubic-bezier(0.15, 1.4, 0.64, 0.96);
|
||||
|
||||
@@ -1,41 +1,145 @@
|
||||
<script setup>
|
||||
import { SpinnerIcon } from '@modrinth/assets'
|
||||
import { Avatar, injectNotificationManager } from '@modrinth/ui'
|
||||
import { Avatar, defineMessages, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import dayjs from 'dayjs'
|
||||
import { onUnmounted, ref } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
import NavButton from '@/components/ui/NavButton.vue'
|
||||
import { instance_listener } from '@/helpers/events.js'
|
||||
import { list } from '@/helpers/instance'
|
||||
|
||||
const ITEM_SIZE = 52
|
||||
const APPROX_USED_VERTICAL_SPACE = 513 // doesn't need to be exact lol just close enough so there's a little gap and no overflow
|
||||
const STORAGE_KEY = 'modrinth-quick-instance-count'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
const recentInstances = ref([])
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const maxAuto = ref(0)
|
||||
const allInstances = ref([])
|
||||
const dragging = ref(false)
|
||||
|
||||
const stored = localStorage.getItem(STORAGE_KEY)
|
||||
const userLimit = ref(stored === null ? null : Number(stored))
|
||||
|
||||
const maxVisible = computed(() => Math.min(maxAuto.value, allInstances.value.length))
|
||||
const visibleCount = computed(() => Math.min(userLimit.value ?? maxVisible.value, maxVisible.value))
|
||||
const recentInstances = computed(() => allInstances.value.slice(0, visibleCount.value))
|
||||
const canDrag = computed(() => maxVisible.value > 0)
|
||||
const showOverdrag = ref(false)
|
||||
|
||||
const updateMaxAuto = () => {
|
||||
maxAuto.value = Math.max(
|
||||
0,
|
||||
Math.floor((window.innerHeight - APPROX_USED_VERTICAL_SPACE) / ITEM_SIZE),
|
||||
)
|
||||
}
|
||||
|
||||
const setLimit = (count) => {
|
||||
const clamped = Math.max(0, Math.min(count, maxVisible.value))
|
||||
if (clamped >= maxVisible.value) {
|
||||
userLimit.value = null
|
||||
localStorage.removeItem(STORAGE_KEY)
|
||||
} else {
|
||||
userLimit.value = clamped
|
||||
localStorage.setItem(STORAGE_KEY, String(clamped))
|
||||
}
|
||||
}
|
||||
|
||||
let dragStartY = 0
|
||||
let dragStartCount = 0
|
||||
let wasOverdragging = false
|
||||
let overdragTimeout = null
|
||||
|
||||
const clearOverdragFlash = () => {
|
||||
showOverdrag.value = false
|
||||
if (overdragTimeout !== null) {
|
||||
clearTimeout(overdragTimeout)
|
||||
overdragTimeout = null
|
||||
}
|
||||
}
|
||||
|
||||
const flashOverdrag = () => {
|
||||
showOverdrag.value = true
|
||||
if (overdragTimeout !== null) {
|
||||
clearTimeout(overdragTimeout)
|
||||
}
|
||||
overdragTimeout = setTimeout(() => {
|
||||
showOverdrag.value = false
|
||||
overdragTimeout = null
|
||||
}, 500)
|
||||
}
|
||||
|
||||
const onDividerPointerDown = (event) => {
|
||||
if (!canDrag.value) {
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
dragging.value = true
|
||||
wasOverdragging = false
|
||||
clearOverdragFlash()
|
||||
dragStartY = event.clientY
|
||||
dragStartCount = visibleCount.value
|
||||
document.body.classList.add('quick-instance-dragging')
|
||||
event.currentTarget.setPointerCapture(event.pointerId)
|
||||
}
|
||||
|
||||
const onDividerPointerMove = (event) => {
|
||||
if (!dragging.value) {
|
||||
return
|
||||
}
|
||||
const delta = event.clientY - dragStartY
|
||||
const target = dragStartCount + Math.round(delta / ITEM_SIZE)
|
||||
const isOverdragging = target < 0 || target > maxAuto.value
|
||||
if (isOverdragging && !wasOverdragging) {
|
||||
flashOverdrag()
|
||||
}
|
||||
wasOverdragging = isOverdragging
|
||||
setLimit(target)
|
||||
}
|
||||
|
||||
const endDrag = (event) => {
|
||||
if (!dragging.value) {
|
||||
return
|
||||
}
|
||||
dragging.value = false
|
||||
wasOverdragging = false
|
||||
clearOverdragFlash()
|
||||
document.body.classList.remove('quick-instance-dragging')
|
||||
if (event?.currentTarget?.hasPointerCapture?.(event.pointerId)) {
|
||||
event.currentTarget.releasePointerCapture(event.pointerId)
|
||||
}
|
||||
}
|
||||
|
||||
const onDividerPointerUp = (event) => {
|
||||
endDrag(event)
|
||||
}
|
||||
|
||||
const getInstances = async () => {
|
||||
const instances = await list().catch(handleError)
|
||||
|
||||
recentInstances.value = instances
|
||||
.sort((a, b) => {
|
||||
const dateACreated = dayjs(a.created)
|
||||
const dateAPlayed = a.last_played ? dayjs(a.last_played) : dayjs(0)
|
||||
allInstances.value = instances.sort((a, b) => {
|
||||
const dateACreated = dayjs(a.created)
|
||||
const dateAPlayed = a.last_played ? dayjs(a.last_played) : dayjs(0)
|
||||
|
||||
const dateBCreated = dayjs(b.created)
|
||||
const dateBPlayed = b.last_played ? dayjs(b.last_played) : dayjs(0)
|
||||
const dateBCreated = dayjs(b.created)
|
||||
const dateBPlayed = b.last_played ? dayjs(b.last_played) : dayjs(0)
|
||||
|
||||
const dateA = dateACreated.isAfter(dateAPlayed) ? dateACreated : dateAPlayed
|
||||
const dateB = dateBCreated.isAfter(dateBPlayed) ? dateBCreated : dateBPlayed
|
||||
const dateA = dateACreated.isAfter(dateAPlayed) ? dateACreated : dateAPlayed
|
||||
const dateB = dateBCreated.isAfter(dateBPlayed) ? dateBCreated : dateBPlayed
|
||||
|
||||
if (dateA.isSame(dateB)) {
|
||||
return a.name.localeCompare(b.name)
|
||||
}
|
||||
if (dateA.isSame(dateB)) {
|
||||
return a.name.localeCompare(b.name)
|
||||
}
|
||||
|
||||
return dateB - dateA
|
||||
})
|
||||
.slice(0, 3)
|
||||
return dateB - dateA
|
||||
})
|
||||
}
|
||||
|
||||
await getInstances()
|
||||
updateMaxAuto()
|
||||
|
||||
const unlistenInstance = await instance_listener(async (event) => {
|
||||
if (event.event !== 'synced') {
|
||||
@@ -43,29 +147,157 @@ const unlistenInstance = await instance_listener(async (event) => {
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', updateMaxAuto)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', updateMaxAuto)
|
||||
document.body.classList.remove('quick-instance-dragging')
|
||||
clearOverdragFlash()
|
||||
unlistenInstance()
|
||||
})
|
||||
|
||||
const messages = defineMessages({
|
||||
dragTooltip: {
|
||||
id: 'app.quick-instance-switcher.drag-tooltip',
|
||||
defaultMessage: 'Drag to resize',
|
||||
},
|
||||
dragShowTooltip: {
|
||||
id: 'app.quick-instance-switcher.drag-show-tooltip',
|
||||
defaultMessage: 'Drag to show recent instances',
|
||||
},
|
||||
})
|
||||
|
||||
const dividerTooltip = computed(() => {
|
||||
if (!canDrag.value || dragging.value) {
|
||||
return null
|
||||
}
|
||||
return formatMessage(visibleCount.value === 0 ? messages.dragShowTooltip : messages.dragTooltip)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-for="instance in recentInstances" :key="instance.id" v-tooltip.right="instance.name">
|
||||
<NavButton :to="`/instance/${encodeURIComponent(instance.id)}`" class="relative">
|
||||
<Avatar
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
|
||||
size="28px"
|
||||
:tint-by="instance.id"
|
||||
:class="`transition-all ${instance.install_stage !== 'installed' ? `brightness-[0.25] scale-[0.85]` : `group-hover:brightness-75`}`"
|
||||
/>
|
||||
<div
|
||||
v-if="instance.install_stage !== 'installed'"
|
||||
class="absolute inset-0 flex items-center justify-center z-10 pointer-events-none"
|
||||
>
|
||||
<SpinnerIcon class="animate-spin w-4 h-4" />
|
||||
</div>
|
||||
</NavButton>
|
||||
<Transition name="top-divider">
|
||||
<div
|
||||
v-if="recentInstances.length > 0"
|
||||
class="top-divider flex items-center justify-center overflow-hidden"
|
||||
>
|
||||
<div class="h-px w-8 bg-surface-5 shrink-0"></div>
|
||||
</div>
|
||||
</Transition>
|
||||
<TransitionGroup name="quick-instance" tag="div" class="flex flex-col items-center">
|
||||
<div
|
||||
v-for="instance in recentInstances"
|
||||
:key="instance.id"
|
||||
v-tooltip.right="instance.name"
|
||||
class="quick-instance-item"
|
||||
>
|
||||
<NavButton :to="`/instance/${encodeURIComponent(instance.id)}`" class="relative">
|
||||
<Avatar
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
|
||||
size="28px"
|
||||
:tint-by="instance.id"
|
||||
:class="`transition-all ${instance.install_stage !== 'installed' ? `brightness-[0.25] scale-[0.85]` : `group-hover:brightness-75`}`"
|
||||
/>
|
||||
<div
|
||||
v-if="instance.install_stage !== 'installed'"
|
||||
class="absolute inset-0 flex items-center justify-center z-10 pointer-events-none"
|
||||
>
|
||||
<SpinnerIcon class="animate-spin w-4 h-4" />
|
||||
</div>
|
||||
</NavButton>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
<div
|
||||
v-tooltip.right="dividerTooltip"
|
||||
class="flex items-center justify-center py-2 select-none"
|
||||
:class="canDrag ? 'cursor-ns-resize touch-none group' : ''"
|
||||
@pointerdown="onDividerPointerDown"
|
||||
@pointermove="onDividerPointerMove"
|
||||
@pointerup="onDividerPointerUp"
|
||||
@pointercancel="onDividerPointerUp"
|
||||
>
|
||||
<div
|
||||
class="h-px w-8 transition-colors duration-200"
|
||||
:class="
|
||||
showOverdrag ? 'bg-red' : canDrag ? 'bg-surface-5 group-hover:bg-secondary' : 'bg-surface-5'
|
||||
"
|
||||
></div>
|
||||
</div>
|
||||
<div v-if="recentInstances.length > 0" class="h-px w-6 mx-auto my-2 bg-divider"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
.top-divider {
|
||||
height: calc(1rem + 1px);
|
||||
}
|
||||
|
||||
.top-divider-enter-active,
|
||||
.top-divider-leave-active {
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
height 0.25s ease;
|
||||
}
|
||||
|
||||
.top-divider-enter-from,
|
||||
.top-divider-leave-to {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.quick-instance-item {
|
||||
height: 3rem;
|
||||
overflow: hidden;
|
||||
|
||||
& + & {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.quick-instance-enter-active,
|
||||
.quick-instance-leave-active {
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
transform 0.25s ease,
|
||||
height 0.25s ease,
|
||||
margin-top 0.25s ease;
|
||||
}
|
||||
|
||||
.quick-instance-enter-from,
|
||||
.quick-instance-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
height: 0;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.top-divider-enter-active,
|
||||
.top-divider-leave-active,
|
||||
.quick-instance-enter-active,
|
||||
.quick-instance-leave-active {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.top-divider-enter-from,
|
||||
.top-divider-leave-to {
|
||||
opacity: 1;
|
||||
height: calc(1rem + 1px);
|
||||
}
|
||||
|
||||
.quick-instance-enter-from,
|
||||
.quick-instance-leave-to {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
height: 3rem;
|
||||
margin-top: unset !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
body.quick-instance-dragging,
|
||||
body.quick-instance-dragging * {
|
||||
cursor: ns-resize !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
<script setup lang="ts">
|
||||
import { NotepadTextIcon, XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, defineMessages, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
import { type } from '@tauri-apps/plugin-os'
|
||||
import { $fetch } from 'ofetch'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
import { list } from '@/helpers/instance'
|
||||
import { get as getCreds } from '@/helpers/mr_auth.ts'
|
||||
|
||||
type Survey = {
|
||||
id: string
|
||||
tally_id: string
|
||||
type: string
|
||||
condition?: string
|
||||
assigned_users?: string[]
|
||||
dismissed_users?: string[]
|
||||
}
|
||||
|
||||
type TallyApi = {
|
||||
openPopup: (formId: string, options: object) => void
|
||||
}
|
||||
|
||||
const tallyWindow = window as Window & { Tally?: TallyApi }
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
const availableSurvey = ref<Survey | null>(null)
|
||||
|
||||
const messages = defineMessages({
|
||||
surveyTitle: {
|
||||
id: 'app.survey.title',
|
||||
defaultMessage: 'Hey there Modrinth user!',
|
||||
},
|
||||
surveyBody: {
|
||||
id: 'app.survey.body',
|
||||
defaultMessage:
|
||||
'Would you mind answering a few questions about your experience with Modrinth App?',
|
||||
},
|
||||
surveyFooter: {
|
||||
id: 'app.survey.footer',
|
||||
defaultMessage:
|
||||
'This feedback will go directly to the Modrinth team and help guide future updates!',
|
||||
},
|
||||
takeSurvey: {
|
||||
id: 'app.survey.take-survey',
|
||||
defaultMessage: 'Take survey',
|
||||
},
|
||||
surveyNoThanks: {
|
||||
id: 'app.survey.no-thanks',
|
||||
defaultMessage: 'No thanks',
|
||||
},
|
||||
})
|
||||
|
||||
function cleanupOldSurveyDisplayData() {
|
||||
const threeWeeksAgo = new Date()
|
||||
threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21)
|
||||
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i)
|
||||
|
||||
if (key?.startsWith('survey-') && key.endsWith('-display')) {
|
||||
const dateValue = new Date(localStorage.getItem(key) ?? '')
|
||||
if (dateValue < threeWeeksAgo) {
|
||||
localStorage.removeItem(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function openSurvey() {
|
||||
if (!availableSurvey.value) {
|
||||
console.error('No survey to open')
|
||||
return
|
||||
}
|
||||
|
||||
const creds = await getCreds().catch(handleError)
|
||||
const userId = creds?.user_id
|
||||
|
||||
const formId = availableSurvey.value.tally_id
|
||||
|
||||
const popupOptions = {
|
||||
layout: 'modal',
|
||||
width: 700,
|
||||
autoClose: 2000,
|
||||
hideTitle: true,
|
||||
hiddenFields: {
|
||||
user_id: userId,
|
||||
},
|
||||
onOpen: () => console.info('Opened user survey'),
|
||||
onClose: () => {
|
||||
console.info('Closed user survey')
|
||||
show_ads_window()
|
||||
},
|
||||
onSubmit: () => console.info('Active user survey submitted'),
|
||||
}
|
||||
|
||||
try {
|
||||
hide_ads_window()
|
||||
if (tallyWindow.Tally?.openPopup) {
|
||||
console.info(`Opening Tally popup for user survey (form ID: ${formId})`)
|
||||
dismissSurvey()
|
||||
tallyWindow.Tally.openPopup(formId, popupOptions)
|
||||
} else {
|
||||
console.warn('Tally script not yet loaded')
|
||||
show_ads_window()
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error opening Tally popup:', e)
|
||||
show_ads_window()
|
||||
}
|
||||
|
||||
console.info(`Found user survey to show with tally_id: ${formId}`)
|
||||
tallyWindow.Tally?.openPopup(formId, popupOptions)
|
||||
}
|
||||
|
||||
function dismissSurvey() {
|
||||
if (!availableSurvey.value) return
|
||||
localStorage.setItem(`survey-${availableSurvey.value.id}-display`, String(new Date()))
|
||||
availableSurvey.value = null
|
||||
}
|
||||
|
||||
async function processPendingSurveys() {
|
||||
function isWithinLastTwoWeeks(date: string | Date | null | undefined) {
|
||||
if (!date) return false
|
||||
const twoWeeksAgo = new Date()
|
||||
twoWeeksAgo.setDate(twoWeeksAgo.getDate() - 14)
|
||||
return new Date(date) >= twoWeeksAgo
|
||||
}
|
||||
|
||||
cleanupOldSurveyDisplayData()
|
||||
|
||||
const creds = await getCreds().catch(handleError)
|
||||
const userId = creds?.user_id
|
||||
|
||||
const instances = (await list().catch(handleError)) ?? []
|
||||
const isActivePlayer = instances.some(
|
||||
(instance) =>
|
||||
isWithinLastTwoWeeks(instance.last_played) && !isWithinLastTwoWeeks(instance.created),
|
||||
)
|
||||
|
||||
let surveys: Survey[] = []
|
||||
try {
|
||||
surveys = await $fetch('https://api.modrinth.com/v2/surveys')
|
||||
} catch (e) {
|
||||
console.error('Error fetching surveys:', e)
|
||||
}
|
||||
|
||||
const surveyToShow = surveys.find(
|
||||
(survey) =>
|
||||
!!(
|
||||
localStorage.getItem(`survey-${survey.id}-display`) === null &&
|
||||
survey.type === 'tally_app' &&
|
||||
((survey.condition === 'active_player' && isActivePlayer) ||
|
||||
(!!userId &&
|
||||
survey.assigned_users?.includes(userId) &&
|
||||
!survey.dismissed_users?.includes(userId)))
|
||||
),
|
||||
)
|
||||
|
||||
if (surveyToShow) {
|
||||
availableSurvey.value = surveyToShow
|
||||
} else {
|
||||
console.info('No user survey to show')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const osType = await type()
|
||||
if (osType === 'windows') {
|
||||
await processPendingSurveys()
|
||||
} else {
|
||||
console.info('Skipping user surveys on non-Windows platforms')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<transition name="popup-survey">
|
||||
<div
|
||||
v-if="availableSurvey"
|
||||
class="w-[400px] z-20 fixed -bottom-12 pb-16 right-[--right-bar-width] mr-4 rounded-t-2xl card-shadow bg-bg-raised border-surface-5 border-[1px] border-solid border-b-0 p-4"
|
||||
>
|
||||
<h2 class="text-lg font-extrabold mt-0 mb-2">
|
||||
{{ formatMessage(messages.surveyTitle) }}
|
||||
</h2>
|
||||
<p class="m-0 leading-tight">
|
||||
{{ formatMessage(messages.surveyBody) }}
|
||||
</p>
|
||||
<p class="mt-3 mb-4 leading-tight">
|
||||
{{ formatMessage(messages.surveyFooter) }}
|
||||
</p>
|
||||
<div class="flex gap-2">
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="openSurvey">
|
||||
<NotepadTextIcon />
|
||||
{{ formatMessage(messages.takeSurvey) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button @click="dismissSurvey">
|
||||
<XIcon />
|
||||
{{ formatMessage(messages.surveyNoThanks) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.popup-survey-enter-active {
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
transform 0.25s cubic-bezier(0.51, 1.08, 0.35, 1.15);
|
||||
transform-origin: top center;
|
||||
}
|
||||
|
||||
.popup-survey-leave-active {
|
||||
transition:
|
||||
opacity 0.25s ease,
|
||||
transform 0.25s cubic-bezier(0.68, -0.17, 0.23, 0.11);
|
||||
transform-origin: top center;
|
||||
}
|
||||
|
||||
.popup-survey-enter-from,
|
||||
.popup-survey-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(10rem) scale(0.8) scaleY(1.6);
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { LoaderCircleIcon } from '@modrinth/assets'
|
||||
import type { GameVersion } from '@modrinth/ui'
|
||||
import { GAME_MODES, HeadingLink, injectNotificationManager } from '@modrinth/ui'
|
||||
import { GAME_MODES, injectNotificationManager } from '@modrinth/ui'
|
||||
import { platform } from '@tauri-apps/plugin-os'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import dayjs from 'dayjs'
|
||||
@@ -268,13 +268,7 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="jumpBackInItems.length > 0" class="flex flex-col gap-2">
|
||||
<HeadingLink v-if="theme.getFeatureFlag('worlds_tab')" to="/worlds" class="mt-1">
|
||||
Jump back in
|
||||
</HeadingLink>
|
||||
<span
|
||||
v-else
|
||||
class="flex mt-1 mb-3 leading-none items-center gap-1 text-primary text-lg font-bold"
|
||||
>
|
||||
<span class="flex mt-1 mb-3 leading-none items-center gap-1 text-primary text-lg font-bold">
|
||||
Jump back in
|
||||
</span>
|
||||
<div class="grid-when-huge flex flex-col w-full gap-2">
|
||||
|
||||
@@ -233,9 +233,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "العودة للنموذج"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "استكشف محتوى"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "استكشف خوادم"
|
||||
},
|
||||
|
||||
@@ -164,9 +164,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Zpět k instanci"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Objevit obsah"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Objevit servery"
|
||||
},
|
||||
|
||||
@@ -218,9 +218,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Tilbage til instance"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Opdag indhold"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Opdag servere"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Zu Instanz zurückgehen"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Inhalte entdecken"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Server entdecken"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Zurück zur Instanz"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Inhalte entdecken"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Server entdecken"
|
||||
},
|
||||
|
||||
@@ -251,9 +251,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Back to instance"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Discover content"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Discover servers"
|
||||
},
|
||||
@@ -761,6 +758,36 @@
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "An update is required to play {name}. Please update to latest version to launch the game."
|
||||
},
|
||||
"app.nav.create-new-instance": {
|
||||
"message": "Create new instance"
|
||||
},
|
||||
"app.nav.home": {
|
||||
"message": "Home"
|
||||
},
|
||||
"app.nav.library": {
|
||||
"message": "Library"
|
||||
},
|
||||
"app.nav.modrinth-account": {
|
||||
"message": "Modrinth account"
|
||||
},
|
||||
"app.nav.modrinth-hosting": {
|
||||
"message": "Modrinth Hosting"
|
||||
},
|
||||
"app.nav.sign-in-to-modrinth-account": {
|
||||
"message": "Sign in to a Modrinth account"
|
||||
},
|
||||
"app.nav.signed-in-as": {
|
||||
"message": "Signed in as <user>{username}</user>"
|
||||
},
|
||||
"app.nav.upgrade-to-modrinth-plus": {
|
||||
"message": "Upgrade to Modrinth+"
|
||||
},
|
||||
"app.news.title": {
|
||||
"message": "News"
|
||||
},
|
||||
"app.news.view-all": {
|
||||
"message": "View all news"
|
||||
},
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "This project is already installed"
|
||||
},
|
||||
@@ -782,6 +809,15 @@
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Already installed"
|
||||
},
|
||||
"app.quick-instance-switcher.drag-show-tooltip": {
|
||||
"message": "Drag to show recent instances"
|
||||
},
|
||||
"app.quick-instance-switcher.drag-tooltip": {
|
||||
"message": "Drag to resize"
|
||||
},
|
||||
"app.restarting": {
|
||||
"message": "Restarting..."
|
||||
},
|
||||
"app.settings.app-version": {
|
||||
"message": "Modrinth App {version}"
|
||||
},
|
||||
@@ -968,6 +1004,9 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Resource management"
|
||||
},
|
||||
"app.sidebar.playing-as": {
|
||||
"message": "Playing as"
|
||||
},
|
||||
"app.skins.add-button": {
|
||||
"message": "Add skin"
|
||||
},
|
||||
@@ -1127,6 +1166,21 @@
|
||||
"app.skins.toggle-ears-features-on": {
|
||||
"message": "Toggle on"
|
||||
},
|
||||
"app.survey.body": {
|
||||
"message": "Would you mind answering a few questions about your experience with Modrinth App?"
|
||||
},
|
||||
"app.survey.footer": {
|
||||
"message": "This feedback will go directly to the Modrinth team and help guide future updates!"
|
||||
},
|
||||
"app.survey.no-thanks": {
|
||||
"message": "No thanks"
|
||||
},
|
||||
"app.survey.take-survey": {
|
||||
"message": "Take survey"
|
||||
},
|
||||
"app.survey.title": {
|
||||
"message": "Hey there Modrinth user!"
|
||||
},
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Modrinth App v{version} has finished downloading. Reload to update now, or automatically when you close Modrinth App."
|
||||
},
|
||||
|
||||
@@ -224,9 +224,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Volver a instancia"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Descubrir contenido"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Descubrir servidores"
|
||||
},
|
||||
|
||||
@@ -158,9 +158,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Volver a la instancia"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Descubrir contenido"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Descubrir servidores"
|
||||
},
|
||||
|
||||
@@ -170,9 +170,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Takaisin instanssiin"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Löydä sisältöä"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Löydä palvelimia"
|
||||
},
|
||||
|
||||
@@ -137,9 +137,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Bumalik sa instansiya"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Tumuklas ng kontento"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Tumuklas ng mga server"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Retour à l'instance"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Découvrir du contenu"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Découvrir des serveurs"
|
||||
},
|
||||
|
||||
@@ -44,9 +44,6 @@
|
||||
"app.browse.already-added": {
|
||||
"message": "כבר נוסף"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "גלה תוכן"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "גלה שרתים"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Vissza a játékpéldányhoz"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Tartalom böngészése"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Szerverek böngészése"
|
||||
},
|
||||
|
||||
@@ -137,9 +137,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Kembali ke instans"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Temukan konten"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Temukan server"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Torna all'istanza"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Esplora i contenuti"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Sfoglia i server"
|
||||
},
|
||||
|
||||
@@ -239,9 +239,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "インスタンスに戻る"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "コンテンツを探す"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "サーバーを探す"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "인스턴스로 돌아가기"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "콘텐츠 탐색하기"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "서버 탐색하기"
|
||||
},
|
||||
|
||||
@@ -134,9 +134,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Kembali ke pemasangan"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Temui kandungan"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Temui pelayan"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Terug naar instantie"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Inhoud ontdekken"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Ontdek servers"
|
||||
},
|
||||
|
||||
@@ -140,9 +140,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Tilbake til tilfelle"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Oppdag innhold"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Oppdag servere"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Powrót do instancji"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Odkrywaj zawartość"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Odkryj serwery"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Voltar à instância"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Descobrir conteúdo"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Descobrir servidores"
|
||||
},
|
||||
|
||||
@@ -239,9 +239,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Voltar à instância"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Descobrir conteúdo"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Descobrir servidores"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Вернуться к сборке"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Поиск проектов"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Поиск серверов"
|
||||
},
|
||||
|
||||
@@ -224,9 +224,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Nazad na instancu"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Otkrij sadržaj"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Otkrij servere"
|
||||
},
|
||||
|
||||
@@ -224,9 +224,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Tillbaka till instans"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Upptäck innehåll"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Upptäck servrar"
|
||||
},
|
||||
|
||||
@@ -152,9 +152,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "กลับสู่อินสแตนซ์"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "สำรวจเนื้อหา"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "สำรวจเซิร์ฟเวอร์"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Kuruluma dön"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "İçerik keşfet"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Sunucuları keşfet"
|
||||
},
|
||||
|
||||
@@ -239,9 +239,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Назад до профілю"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Дослідити вміст"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Дослідити сервери"
|
||||
},
|
||||
|
||||
@@ -233,9 +233,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Quay lại phiên bản"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Khám phá nội dung"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Khám phá máy chủ"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "返回实例"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "发现内容"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "发现服务器"
|
||||
},
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "回到實例"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "探索內容"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "探索伺服器"
|
||||
},
|
||||
|
||||
@@ -385,10 +385,6 @@ const messages = defineMessages({
|
||||
id: 'app.browse.add-to-an-instance',
|
||||
defaultMessage: 'Add to an instance',
|
||||
},
|
||||
discoverContent: {
|
||||
id: 'app.browse.discover-content',
|
||||
defaultMessage: 'Discover content',
|
||||
},
|
||||
discoverServers: {
|
||||
id: 'app.browse.discover-servers',
|
||||
defaultMessage: 'Discover servers',
|
||||
@@ -450,7 +446,9 @@ const messages = defineMessages({
|
||||
|
||||
const breadcrumbs = useBreadcrumbs()
|
||||
const browseTitle = computed(() =>
|
||||
formatMessage(isFromWorlds.value ? messages.discoverServers : messages.discoverContent),
|
||||
formatMessage(
|
||||
isFromWorlds.value ? messages.discoverServers : commonMessages.discoverContentLabel,
|
||||
),
|
||||
)
|
||||
breadcrumbs.setName('BrowseTitle', browseTitle.value)
|
||||
if (instance.value) {
|
||||
@@ -484,7 +482,7 @@ function resetInstanceContext() {
|
||||
hiddenInstanceProjectIds.value = new Set()
|
||||
hiddenInstanceProjectIdsInitialized.value = false
|
||||
isServerInstance.value = false
|
||||
breadcrumbs.setName('BrowseTitle', formatMessage(messages.discoverContent))
|
||||
breadcrumbs.setName('BrowseTitle', formatMessage(commonMessages.discoverContentLabel))
|
||||
breadcrumbs.setContext(null)
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ import {
|
||||
import { hasPride26Badge } from '@/helpers/user-campaigns.ts'
|
||||
import { handleSevereError } from '@/store/error'
|
||||
import { useTheming } from '@/store/state'
|
||||
import { appMessages } from '@/utils/app-messages'
|
||||
|
||||
type UnlistenFn = () => void
|
||||
type VirtualSkinSectionListExpose = {
|
||||
@@ -68,10 +69,6 @@ const PENDING_SKIN_REFRESH_DELAY_MS = 11_000
|
||||
const DEFAULT_SKIN_SECTION_SORT_ORDER = ['Default skins', 'Modrinth Pride']
|
||||
const EARS_NOTICE_PLACEHOLDER = '__EARS_MOD_NAME__'
|
||||
const messages = defineMessages({
|
||||
skinSelectorTitle: {
|
||||
id: 'app.skins.title',
|
||||
defaultMessage: 'Skin selector',
|
||||
},
|
||||
modrinthPrideSection: {
|
||||
id: 'app.skins.section.modrinth-pride',
|
||||
defaultMessage: 'Modrinth Pride',
|
||||
@@ -1071,7 +1068,7 @@ await loadSkins()
|
||||
<div v-if="currentUser" class="skin-layout box-border min-h-full p-4">
|
||||
<div class="sticky top-6 self-start p-2 pt-0">
|
||||
<h1 class="m-0 text-2xl font-bold flex items-center gap-2">
|
||||
{{ formatMessage(messages.skinSelectorTitle) }}
|
||||
{{ formatMessage(appMessages.skinSelectorLabel) }}
|
||||
</h1>
|
||||
<div
|
||||
class="ml-5 mt-4 flex h-[calc(80vh-1rem)] items-center justify-center max-[700px]:h-[calc(50vh-1rem)]"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<script setup lang="ts"></script>
|
||||
<template>
|
||||
<div class="p-6 flex flex-col gap-2">Worlds</div>
|
||||
</template>
|
||||
@@ -3,6 +3,5 @@ import Index from './Index.vue'
|
||||
import Servers from './Servers.vue'
|
||||
import Skins from './Skins.vue'
|
||||
import User from './User.vue'
|
||||
import Worlds from './Worlds.vue'
|
||||
|
||||
export { Browse, Index, Servers, Skins, User, Worlds }
|
||||
export { Browse, Index, Servers, Skins, User }
|
||||
|
||||
@@ -20,14 +20,6 @@ export default new createRouter({
|
||||
breadcrumb: [{ name: 'Home' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/worlds',
|
||||
name: 'Worlds',
|
||||
component: Pages.Worlds,
|
||||
meta: {
|
||||
breadcrumb: [{ name: 'Worlds' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/hosting/manage/',
|
||||
name: 'Servers',
|
||||
|
||||
@@ -5,7 +5,6 @@ let systemThemeMq: MediaQueryList | null = null
|
||||
export const DEFAULT_FEATURE_FLAGS = {
|
||||
project_background: false,
|
||||
page_path: false,
|
||||
worlds_tab: false,
|
||||
worlds_in_home: true,
|
||||
server_project_qa: false,
|
||||
show_version_environment_column: false,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineMessages } from '@modrinth/ui'
|
||||
|
||||
export const appMessages = defineMessages({
|
||||
skinSelectorLabel: {
|
||||
id: 'app.skins.title',
|
||||
defaultMessage: 'Skin selector',
|
||||
},
|
||||
})
|
||||
@@ -253,7 +253,7 @@
|
||||
/>
|
||||
<CompassIcon v-else aria-hidden="true" />
|
||||
<span class="hidden md:contents">{{
|
||||
formatMessage(navMenuMessages.discoverContent)
|
||||
formatMessage(commonMessages.discoverContentLabel)
|
||||
}}</span>
|
||||
<span class="contents md:hidden">{{ formatMessage(navMenuMessages.discover) }}</span>
|
||||
<DropdownIcon aria-hidden="true" class="h-5 w-5" />
|
||||
@@ -933,10 +933,6 @@ const navMenuMessages = defineMessages({
|
||||
id: 'layout.nav.search',
|
||||
defaultMessage: 'Search',
|
||||
},
|
||||
discoverContent: {
|
||||
id: 'layout.nav.discover-content',
|
||||
defaultMessage: 'Discover content',
|
||||
},
|
||||
discover: {
|
||||
id: 'layout.nav.discover',
|
||||
defaultMessage: 'Discover',
|
||||
|
||||
@@ -1949,9 +1949,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Objevit"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Objevit obsah"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Získat Modrinth App"
|
||||
},
|
||||
|
||||
@@ -1985,9 +1985,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Opdag"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Opdag indhold"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Hent Modrinth-app"
|
||||
},
|
||||
|
||||
@@ -2879,9 +2879,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Entdecken"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Inhalte entdecken"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Modrinth App herunterladen"
|
||||
},
|
||||
|
||||
@@ -2879,9 +2879,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Entdecken"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Inhalte entdecken"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Modrinth App herunterladen"
|
||||
},
|
||||
|
||||
@@ -2879,9 +2879,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Discover"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Discover content"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Get Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2630,9 +2630,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Descubre"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Descubrir contenido"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Obtener la Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2498,9 +2498,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Descubre"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Descubra el contenido"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Descargar la aplicación Modrinth"
|
||||
},
|
||||
|
||||
@@ -1829,9 +1829,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Tumuklas"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Tumuklas ng kontento"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Kunin ang Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2873,9 +2873,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Découvrir"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Découvrir du contenu"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Obtenir Modrinth App"
|
||||
},
|
||||
|
||||
@@ -1580,9 +1580,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "גלה"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "גלה תוכן"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "להוריד אפליקציאת Modrinth"
|
||||
},
|
||||
|
||||
@@ -2699,9 +2699,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Felfedezés"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Tartalom felfedezése"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Szerezd meg a Modrinth Appot"
|
||||
},
|
||||
|
||||
@@ -1841,9 +1841,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Temukan"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Temukan konten"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Dapatkan Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2870,9 +2870,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Esplora"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Sfoglia i contenuti"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Scarica Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2369,9 +2369,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "探索"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "コンテンツを探索"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Modrinth Appを入手"
|
||||
},
|
||||
|
||||
@@ -2873,9 +2873,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "탐색"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "콘텐츠 탐색하기"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Modrinth App 받기"
|
||||
},
|
||||
|
||||
@@ -2354,9 +2354,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Temui"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Temui kandungan"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Dapatkan Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2876,9 +2876,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Ontdek"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Ontdek inhoud"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Modrinth-app downloaden"
|
||||
},
|
||||
|
||||
@@ -2285,9 +2285,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Utforsk"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Utforsk innhold"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Skaff deg Modrinth App-en"
|
||||
},
|
||||
|
||||
@@ -2870,9 +2870,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Odkrywaj"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Odkrywaj zawartość"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Pobierz Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2879,9 +2879,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Descubra"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Descubra conteúdo"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Baixe o Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2183,9 +2183,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Descobrir"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Descobrir conteúdo"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Obter a Modrinth App"
|
||||
},
|
||||
|
||||
@@ -1106,9 +1106,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Descoperă"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Descoperă conținut"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Ia-ți Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2873,9 +2873,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Найти"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Найти проекты"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Скачать Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2552,9 +2552,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Utforska"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Utforska innehåll"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Installera Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2630,9 +2630,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Keşfet"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "İçerik keşfet"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Modrinth App yükle"
|
||||
},
|
||||
|
||||
@@ -2870,9 +2870,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Дослідити"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Дослідити вміст"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Установити Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2519,9 +2519,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "Khám phá"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "Khám phá nội dung"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "Tải ứng dụng Modrinth"
|
||||
},
|
||||
|
||||
@@ -2879,9 +2879,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "发现"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "发现内容"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "获取 Modrinth App"
|
||||
},
|
||||
|
||||
@@ -2879,9 +2879,6 @@
|
||||
"layout.nav.discover": {
|
||||
"message": "探索"
|
||||
},
|
||||
"layout.nav.discover-content": {
|
||||
"message": "探索內容"
|
||||
},
|
||||
"layout.nav.get-modrinth-app": {
|
||||
"message": "取得 Modrinth App"
|
||||
},
|
||||
|
||||
@@ -53,7 +53,6 @@ pub struct Settings {
|
||||
pub enum FeatureFlag {
|
||||
PagePath,
|
||||
ProjectBackground,
|
||||
WorldsTab,
|
||||
WorldsInHome,
|
||||
ServerRamAsBytesAlwaysOn,
|
||||
AlwaysShowAppControls,
|
||||
|
||||
@@ -244,6 +244,7 @@ import _ShareIcon from './icons/share.svg?component'
|
||||
import _ShieldIcon from './icons/shield.svg?component'
|
||||
import _ShieldAlertIcon from './icons/shield-alert.svg?component'
|
||||
import _ShieldCheckIcon from './icons/shield-check.svg?component'
|
||||
import _ShirtIcon from './icons/shirt.svg?component'
|
||||
import _SignalIcon from './icons/signal.svg?component'
|
||||
import _SignatureIcon from './icons/signature.svg?component'
|
||||
import _SkullIcon from './icons/skull.svg?component'
|
||||
@@ -676,6 +677,7 @@ export const ShareIcon = _ShareIcon
|
||||
export const ShieldIcon = _ShieldIcon
|
||||
export const ShieldAlertIcon = _ShieldAlertIcon
|
||||
export const ShieldCheckIcon = _ShieldCheckIcon
|
||||
export const ShirtIcon = _ShirtIcon
|
||||
export const SignalIcon = _SignalIcon
|
||||
export const SignatureIcon = _SignatureIcon
|
||||
export const SkullIcon = _SkullIcon
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<!-- @license lucide-static v0.562.0 - ISC -->
|
||||
<svg
|
||||
class="lucide lucide-shirt"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M20.38 3.46 16 2a4 4 0 0 1-8 0L3.62 3.46a2 2 0 0 0-1.34 2.23l.58 3.47a1 1 0 0 0 .99.84H6v10c0 1.1.9 2 2 2h8a2 2 0 0 0 2-2V10h2.15a1 1 0 0 0 .99-.84l.58-3.47a2 2 0 0 0-1.34-2.23z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 478 B |
@@ -117,7 +117,7 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<div
|
||||
ref="containerRef"
|
||||
class="@container flex flex-col gap-4 rounded-[20px] bg-bg-raised p-6 shadow-md"
|
||||
class="@container flex flex-col gap-4 rounded-[20px] bg-bg-raised p-6 shadow-md border border-solid border-surface-4"
|
||||
:class="{ 'opacity-50': disabled }"
|
||||
>
|
||||
<div class="flex flex-wrap items-start justify-between gap-4">
|
||||
|
||||
@@ -2240,6 +2240,9 @@
|
||||
"label.details": {
|
||||
"defaultMessage": "Details"
|
||||
},
|
||||
"label.discover-content": {
|
||||
"defaultMessage": "Discover content"
|
||||
},
|
||||
"label.done": {
|
||||
"defaultMessage": "Done"
|
||||
},
|
||||
|
||||
@@ -111,6 +111,10 @@ export const commonMessages = defineMessages({
|
||||
id: 'label.details',
|
||||
defaultMessage: 'Details',
|
||||
},
|
||||
discoverContentLabel: {
|
||||
id: 'label.discover-content',
|
||||
defaultMessage: 'Discover content',
|
||||
},
|
||||
downloadButton: {
|
||||
id: 'button.download',
|
||||
defaultMessage: 'Download',
|
||||
|
||||
Reference in New Issue
Block a user