fix: deeplink modal use new modal & DI stability (#5577)
* fix: deeplink * feat: DI stability * fix: lint * fix: play server project deep link * switch toggle icons * pnpm prepr --------- Co-authored-by: tdgao <mr.trumgao@gmail.com>
This commit is contained in:
@@ -79,12 +79,11 @@ import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
|
|||||||
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
|
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
|
||||||
import RunningAppBar from '@/components/ui/RunningAppBar.vue'
|
import RunningAppBar from '@/components/ui/RunningAppBar.vue'
|
||||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||||
import URLConfirmModal from '@/components/ui/URLConfirmModal.vue'
|
|
||||||
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
||||||
import { hide_ads_window, init_ads_window, show_ads_window } from '@/helpers/ads.js'
|
import { hide_ads_window, init_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||||
import { debugAnalytics, initAnalytics, trackEvent } from '@/helpers/analytics'
|
import { debugAnalytics, initAnalytics, trackEvent } from '@/helpers/analytics'
|
||||||
import { check_reachable } from '@/helpers/auth.js'
|
import { check_reachable } from '@/helpers/auth.js'
|
||||||
import { get_user } from '@/helpers/cache.js'
|
import { get_user, get_version } from '@/helpers/cache.js'
|
||||||
import { command_listener, warning_listener } from '@/helpers/events.js'
|
import { command_listener, warning_listener } from '@/helpers/events.js'
|
||||||
import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.ts'
|
import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.ts'
|
||||||
import { create_profile_and_install_from_file } from '@/helpers/pack'
|
import { create_profile_and_install_from_file } from '@/helpers/pack'
|
||||||
@@ -157,8 +156,6 @@ const {
|
|||||||
const news = ref([])
|
const news = ref([])
|
||||||
const availableSurvey = ref(false)
|
const availableSurvey = ref(false)
|
||||||
|
|
||||||
const urlModal = ref(null)
|
|
||||||
|
|
||||||
const offline = ref(!navigator.onLine)
|
const offline = ref(!navigator.onLine)
|
||||||
window.addEventListener('offline', () => {
|
window.addEventListener('offline', () => {
|
||||||
offline.value = true
|
offline.value = true
|
||||||
@@ -421,6 +418,7 @@ const {
|
|||||||
preferredLoader: contentInstallPreferredLoader,
|
preferredLoader: contentInstallPreferredLoader,
|
||||||
preferredGameVersion: contentInstallPreferredGameVersion,
|
preferredGameVersion: contentInstallPreferredGameVersion,
|
||||||
releaseGameVersions: contentInstallReleaseGameVersions,
|
releaseGameVersions: contentInstallReleaseGameVersions,
|
||||||
|
projectInfo: contentInstallProjectInfo,
|
||||||
handleInstallToInstance,
|
handleInstallToInstance,
|
||||||
handleCreateAndInstall,
|
handleCreateAndInstall,
|
||||||
handleNavigate: handleContentInstallNavigate,
|
handleNavigate: handleContentInstallNavigate,
|
||||||
@@ -436,6 +434,7 @@ const {
|
|||||||
setInstallToPlayModal: setServerInstallToPlayModal,
|
setInstallToPlayModal: setServerInstallToPlayModal,
|
||||||
setUpdateToPlayModal: setServerUpdateToPlayModal,
|
setUpdateToPlayModal: setServerUpdateToPlayModal,
|
||||||
setAddServerToInstanceModal: setServerAddServerToInstanceModal,
|
setAddServerToInstanceModal: setServerAddServerToInstanceModal,
|
||||||
|
playServerProject,
|
||||||
} = serverInstall
|
} = serverInstall
|
||||||
|
|
||||||
const modInstallModal = ref()
|
const modInstallModal = ref()
|
||||||
@@ -545,9 +544,19 @@ async function handleCommand(e) {
|
|||||||
} else if (e.event === 'InstallServer') {
|
} else if (e.event === 'InstallServer') {
|
||||||
await router.push(`/project/${e.id}`)
|
await router.push(`/project/${e.id}`)
|
||||||
await playServerProject(e.id).catch(handleError)
|
await playServerProject(e.id).catch(handleError)
|
||||||
|
} else if (e.event === 'InstallVersion') {
|
||||||
|
const version = await get_version(e.id, 'must_revalidate').catch(handleError)
|
||||||
|
if (version) {
|
||||||
|
await contentInstall
|
||||||
|
.install(version.project_id, version.id, null, 'URLConfirmModal', undefined, undefined, {
|
||||||
|
showProjectInfo: true,
|
||||||
|
})
|
||||||
|
.catch(handleError)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Other commands are URL-based (deep linking)
|
await contentInstall
|
||||||
urlModal.value.show(e)
|
.install(e.id, null, null, 'URLConfirmModal', undefined, undefined, { showProjectInfo: true })
|
||||||
|
.catch(handleError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1265,7 +1274,6 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<URLConfirmModal ref="urlModal" />
|
|
||||||
<I18nDebugPanel />
|
<I18nDebugPanel />
|
||||||
<NotificationPanel has-sidebar />
|
<NotificationPanel has-sidebar />
|
||||||
<PopupNotificationPanel has-sidebar />
|
<PopupNotificationPanel has-sidebar />
|
||||||
@@ -1281,6 +1289,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
|||||||
:preferred-loader="contentInstallPreferredLoader"
|
:preferred-loader="contentInstallPreferredLoader"
|
||||||
:preferred-game-version="contentInstallPreferredGameVersion"
|
:preferred-game-version="contentInstallPreferredGameVersion"
|
||||||
:release-game-versions="contentInstallReleaseGameVersions"
|
:release-game-versions="contentInstallReleaseGameVersions"
|
||||||
|
:project-info="contentInstallProjectInfo"
|
||||||
@install="handleInstallToInstance"
|
@install="handleInstallToInstance"
|
||||||
@create-and-install="handleCreateAndInstall"
|
@create-and-install="handleCreateAndInstall"
|
||||||
@navigate="handleContentInstallNavigate"
|
@navigate="handleContentInstallNavigate"
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
import type { Labrinth } from '@modrinth/api-client'
|
import type { Labrinth } from '@modrinth/api-client'
|
||||||
import type { ContentInstallInstance, ContentItem } from '@modrinth/ui'
|
import type { ContentInstallInstance, ContentInstallProjectInfo, ContentItem } from '@modrinth/ui'
|
||||||
import { createContext } from '@modrinth/ui'
|
import { createContext } from '@modrinth/ui'
|
||||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||||
|
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { nextTick, type Ref, ref } from 'vue'
|
import { nextTick, type Ref, ref } from 'vue'
|
||||||
import type { Router } from 'vue-router'
|
import type { Router } from 'vue-router'
|
||||||
|
|
||||||
import { trackEvent } from '@/helpers/analytics'
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
import { get_project, get_project_v3_many, get_version_many } from '@/helpers/cache.js'
|
import {
|
||||||
|
get_organization,
|
||||||
|
get_project,
|
||||||
|
get_project_v3_many,
|
||||||
|
get_team,
|
||||||
|
get_version_many,
|
||||||
|
} from '@/helpers/cache.js'
|
||||||
import { create_profile_and_install as packInstall } from '@/helpers/pack'
|
import { create_profile_and_install as packInstall } from '@/helpers/pack'
|
||||||
import {
|
import {
|
||||||
add_project_from_version,
|
add_project_from_version,
|
||||||
@@ -73,6 +80,7 @@ export interface ContentInstallContext {
|
|||||||
preferredLoader: Ref<string | null>
|
preferredLoader: Ref<string | null>
|
||||||
preferredGameVersion: Ref<string | null>
|
preferredGameVersion: Ref<string | null>
|
||||||
releaseGameVersions: Ref<Set<string>>
|
releaseGameVersions: Ref<Set<string>>
|
||||||
|
projectInfo: Ref<ContentInstallProjectInfo | null>
|
||||||
handleInstallToInstance: (instance: ContentInstallInstance) => Promise<void>
|
handleInstallToInstance: (instance: ContentInstallInstance) => Promise<void>
|
||||||
handleCreateAndInstall: (data: {
|
handleCreateAndInstall: (data: {
|
||||||
name: string
|
name: string
|
||||||
@@ -93,7 +101,7 @@ export interface ContentInstallContext {
|
|||||||
source?: string,
|
source?: string,
|
||||||
callback?: (versionId?: string) => void,
|
callback?: (versionId?: string) => void,
|
||||||
createInstanceCallback?: (profile: string) => void,
|
createInstanceCallback?: (profile: string) => void,
|
||||||
hints?: { preferredLoader?: string; preferredGameVersion?: string },
|
hints?: { preferredLoader?: string; preferredGameVersion?: string; showProjectInfo?: boolean },
|
||||||
) => Promise<void>
|
) => Promise<void>
|
||||||
installingItems: Ref<Map<string, ContentItem[]>>
|
installingItems: Ref<Map<string, ContentItem[]>>
|
||||||
}
|
}
|
||||||
@@ -116,6 +124,7 @@ export function createContentInstall(opts: {
|
|||||||
const preferredGameVersion = ref<string | null>(null)
|
const preferredGameVersion = ref<string | null>(null)
|
||||||
const releaseGameVersions = ref<Set<string>>(new Set())
|
const releaseGameVersions = ref<Set<string>>(new Set())
|
||||||
|
|
||||||
|
const projectInfo = ref<ContentInstallProjectInfo | null>(null)
|
||||||
const installingItems = ref<Map<string, ContentItem[]>>(new Map())
|
const installingItems = ref<Map<string, ContentItem[]>>(new Map())
|
||||||
|
|
||||||
function addInstallingItem(
|
function addInstallingItem(
|
||||||
@@ -194,6 +203,58 @@ export function createContentInstall(opts: {
|
|||||||
instances.value = []
|
instances.value = []
|
||||||
defaultTab.value = 'existing'
|
defaultTab.value = 'existing'
|
||||||
|
|
||||||
|
if (hints?.showProjectInfo) {
|
||||||
|
projectInfo.value = {
|
||||||
|
title: project.title,
|
||||||
|
iconUrl: project.icon_url,
|
||||||
|
link: `/project/${project.slug ?? project.id}`,
|
||||||
|
}
|
||||||
|
if (project.organization) {
|
||||||
|
get_organization(project.organization)
|
||||||
|
.then((org: { id: string; slug: string; name: string; icon_url?: string }) => {
|
||||||
|
if (projectInfo.value) {
|
||||||
|
const orgSlug = org.slug ?? org.id
|
||||||
|
projectInfo.value = {
|
||||||
|
...projectInfo.value,
|
||||||
|
owner: {
|
||||||
|
name: org.name,
|
||||||
|
iconUrl: org.icon_url,
|
||||||
|
circle: false,
|
||||||
|
link: () => openUrl(`https://modrinth.com/organization/${orgSlug}`),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
} else if (project.team) {
|
||||||
|
get_team(project.team)
|
||||||
|
.then(
|
||||||
|
(
|
||||||
|
members: {
|
||||||
|
user: { id: string; username: string; avatar_url?: string }
|
||||||
|
is_owner: boolean
|
||||||
|
}[],
|
||||||
|
) => {
|
||||||
|
const owner = members.find((m) => m.is_owner)
|
||||||
|
if (owner && projectInfo.value) {
|
||||||
|
projectInfo.value = {
|
||||||
|
...projectInfo.value,
|
||||||
|
owner: {
|
||||||
|
name: owner.user.username,
|
||||||
|
iconUrl: owner.user.avatar_url,
|
||||||
|
circle: true,
|
||||||
|
link: () => openUrl(`https://modrinth.com/user/${owner.user.username}`),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
projectInfo.value = null
|
||||||
|
}
|
||||||
|
|
||||||
const loaderSet = new Set<string>()
|
const loaderSet = new Set<string>()
|
||||||
const gameVersionSet = new Set<string>()
|
const gameVersionSet = new Set<string>()
|
||||||
for (const v of versions) {
|
for (const v of versions) {
|
||||||
@@ -402,7 +463,7 @@ export function createContentInstall(opts: {
|
|||||||
source: string = 'unknown',
|
source: string = 'unknown',
|
||||||
callback: (versionId?: string) => void = () => {},
|
callback: (versionId?: string) => void = () => {},
|
||||||
createInstanceCallback: (profile: string) => void = () => {},
|
createInstanceCallback: (profile: string) => void = () => {},
|
||||||
hints?: { preferredLoader?: string; preferredGameVersion?: string },
|
hints?: { preferredLoader?: string; preferredGameVersion?: string; showProjectInfo?: boolean },
|
||||||
) {
|
) {
|
||||||
const project: Labrinth.Projects.v2.Project = await get_project(projectId, 'must_revalidate')
|
const project: Labrinth.Projects.v2.Project = await get_project(projectId, 'must_revalidate')
|
||||||
|
|
||||||
@@ -508,6 +569,7 @@ export function createContentInstall(opts: {
|
|||||||
preferredLoader,
|
preferredLoader,
|
||||||
preferredGameVersion,
|
preferredGameVersion,
|
||||||
releaseGameVersions,
|
releaseGameVersions,
|
||||||
|
projectInfo,
|
||||||
handleInstallToInstance,
|
handleInstallToInstance,
|
||||||
handleCreateAndInstall,
|
handleCreateAndInstall,
|
||||||
handleNavigate,
|
handleNavigate,
|
||||||
|
|||||||
@@ -46,11 +46,24 @@ export interface ServerInstallContext {
|
|||||||
showAddServerToInstanceModal: (serverName: string, serverAddress: string) => void
|
showAddServerToInstanceModal: (serverName: string, serverAddress: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const [injectServerInstall, provideServerInstall] = createContext<ServerInstallContext>(
|
let _serverInstallSingleton: ServerInstallContext | null = null
|
||||||
|
|
||||||
|
const [_rawInjectServerInstall, provideServerInstall] = createContext<ServerInstallContext>(
|
||||||
'root',
|
'root',
|
||||||
'serverInstall',
|
'serverInstall',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export { provideServerInstall }
|
||||||
|
|
||||||
|
export function injectServerInstall(): ServerInstallContext {
|
||||||
|
try {
|
||||||
|
return _rawInjectServerInstall()
|
||||||
|
} catch {
|
||||||
|
if (_serverInstallSingleton) return _serverInstallSingleton
|
||||||
|
throw new Error('ServerInstall context not available')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function createServerInstall(opts: {
|
export function createServerInstall(opts: {
|
||||||
router: Router
|
router: Router
|
||||||
handleError: (err: unknown) => void
|
handleError: (err: unknown) => void
|
||||||
@@ -345,7 +358,7 @@ export function createServerInstall(opts: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const context: ServerInstallContext = {
|
||||||
installingServerProjects,
|
installingServerProjects,
|
||||||
startInstallingServer,
|
startInstallingServer,
|
||||||
stopInstallingServer,
|
stopInstallingServer,
|
||||||
@@ -365,4 +378,7 @@ export function createServerInstall(opts: {
|
|||||||
addServerToInstanceModalRef?.show(serverName, serverAddress)
|
addServerToInstanceModalRef?.show(serverName, serverAddress)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_serverInstallSingleton = context
|
||||||
|
return context
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,45 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="projectInfo"
|
||||||
|
class="flex items-center gap-2.5 rounded-[20px] bg-surface-2 mx-6 mt-6 p-3"
|
||||||
|
>
|
||||||
|
<AutoLink :to="projectInfo.link" class="shrink-0">
|
||||||
|
<div
|
||||||
|
class="size-14 shrink-0 overflow-hidden rounded-2xl border border-solid border-surface-5"
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
v-if="projectInfo.iconUrl"
|
||||||
|
:src="projectInfo.iconUrl"
|
||||||
|
:alt="projectInfo.title"
|
||||||
|
size="100%"
|
||||||
|
no-shadow
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</AutoLink>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<AutoLink :to="projectInfo.link" class="font-semibold text-contrast hover:underline">
|
||||||
|
{{ projectInfo.title }}
|
||||||
|
</AutoLink>
|
||||||
|
<div v-if="projectInfo.owner" class="flex items-center gap-2 text-sm text-secondary">
|
||||||
|
<AutoLink
|
||||||
|
:to="projectInfo.owner.link"
|
||||||
|
class="flex items-center gap-1.5 text-inherit no-underline hover:underline"
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
:src="projectInfo.owner.iconUrl"
|
||||||
|
:alt="projectInfo.owner.name"
|
||||||
|
size="1.25rem"
|
||||||
|
:circle="projectInfo.owner.circle"
|
||||||
|
no-shadow
|
||||||
|
/>
|
||||||
|
<span class="font-medium">{{ projectInfo.owner.name }}</span>
|
||||||
|
</AutoLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2.5 p-6">
|
<div class="flex flex-col gap-2.5 p-6">
|
||||||
<span class="font-semibold text-contrast">
|
<span class="font-semibold text-contrast">
|
||||||
{{ formatMessage(messages.instanceType) }}
|
{{ formatMessage(messages.instanceType) }}
|
||||||
@@ -34,8 +73,8 @@
|
|||||||
class="!border-surface-4 !border"
|
class="!border-surface-4 !border"
|
||||||
@click="hideUninstallable = !hideUninstallable"
|
@click="hideUninstallable = !hideUninstallable"
|
||||||
>
|
>
|
||||||
<EyeIcon v-if="hideUninstallable" />
|
<EyeOffIcon v-if="hideUninstallable" />
|
||||||
<EyeOffIcon v-else />
|
<EyeIcon v-else />
|
||||||
</button>
|
</button>
|
||||||
</ButtonStyled>
|
</ButtonStyled>
|
||||||
</div>
|
</div>
|
||||||
@@ -212,6 +251,7 @@ import {
|
|||||||
} from '@modrinth/assets'
|
} from '@modrinth/assets'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
import AutoLink from '#ui/components/base/AutoLink.vue'
|
||||||
import Avatar from '#ui/components/base/Avatar.vue'
|
import Avatar from '#ui/components/base/Avatar.vue'
|
||||||
import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
|
import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
|
||||||
import Chips from '#ui/components/base/Chips.vue'
|
import Chips from '#ui/components/base/Chips.vue'
|
||||||
@@ -314,6 +354,20 @@ export interface ContentInstallInstance {
|
|||||||
installing?: boolean
|
installing?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ContentInstallProjectOwner {
|
||||||
|
name: string
|
||||||
|
iconUrl?: string
|
||||||
|
circle?: boolean
|
||||||
|
link: string | (() => void)
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ContentInstallProjectInfo {
|
||||||
|
title: string
|
||||||
|
iconUrl?: string | null
|
||||||
|
link: string
|
||||||
|
owner?: ContentInstallProjectOwner | null
|
||||||
|
}
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
instances: ContentInstallInstance[]
|
instances: ContentInstallInstance[]
|
||||||
compatibleLoaders: string[]
|
compatibleLoaders: string[]
|
||||||
@@ -323,6 +377,7 @@ const props = defineProps<{
|
|||||||
defaultTab?: 'existing' | 'new'
|
defaultTab?: 'existing' | 'new'
|
||||||
preferredLoader?: string | null
|
preferredLoader?: string | null
|
||||||
preferredGameVersion?: string | null
|
preferredGameVersion?: string | null
|
||||||
|
projectInfo?: ContentInstallProjectInfo | null
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ export { default as ConfirmModpackUpdateModal } from './components/modals/Confir
|
|||||||
export { default as ConfirmReinstallModal } from './components/modals/ConfirmReinstallModal.vue'
|
export { default as ConfirmReinstallModal } from './components/modals/ConfirmReinstallModal.vue'
|
||||||
export { default as ConfirmRepairModal } from './components/modals/ConfirmRepairModal.vue'
|
export { default as ConfirmRepairModal } from './components/modals/ConfirmRepairModal.vue'
|
||||||
export { default as ConfirmUnlinkModal } from './components/modals/ConfirmUnlinkModal.vue'
|
export { default as ConfirmUnlinkModal } from './components/modals/ConfirmUnlinkModal.vue'
|
||||||
export type { ContentInstallInstance } from './components/modals/ContentInstallModal.vue'
|
export type {
|
||||||
|
ContentInstallInstance,
|
||||||
|
ContentInstallProjectInfo,
|
||||||
|
ContentInstallProjectOwner,
|
||||||
|
} from './components/modals/ContentInstallModal.vue'
|
||||||
export { default as ContentInstallModal } from './components/modals/ContentInstallModal.vue'
|
export { default as ContentInstallModal } from './components/modals/ContentInstallModal.vue'
|
||||||
export { default as ContentUpdaterModal } from './components/modals/ContentUpdaterModal.vue'
|
export { default as ContentUpdaterModal } from './components/modals/ContentUpdaterModal.vue'
|
||||||
export type { ModpackContentModalState } from './components/modals/ModpackContentModal.vue'
|
export type { ModpackContentModalState } from './components/modals/ModpackContentModal.vue'
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ export function createContext<ContextValue>(
|
|||||||
? `${providerComponentName}Context`
|
? `${providerComponentName}Context`
|
||||||
: contextName
|
: contextName
|
||||||
|
|
||||||
const injectionKey: InjectionKey<ContextValue | null> = Symbol(symbolDescription)
|
const injectionKey: InjectionKey<ContextValue | null> = Symbol.for(
|
||||||
|
`modrinth:${symbolDescription}`,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param fallback The context value to return if the injection fails.
|
* @param fallback The context value to return if the injection fails.
|
||||||
|
|||||||
Reference in New Issue
Block a user