mirror of
https://github.com/modrinth/code.git
synced 2026-09-05 06:19:11 +00:00
feat: show avatar in install to play modal
This commit is contained in:
+48
-1
@@ -64,7 +64,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</Admonition>
|
</Admonition>
|
||||||
<p v-else class="m-0 text-primary">
|
<p v-else class="m-0 text-primary">
|
||||||
{{ formatMessage(messages.inviteWarning) }}
|
<IntlFormatted
|
||||||
|
v-if="creator"
|
||||||
|
:message-id="messages.inviteWarningWithCreator"
|
||||||
|
:values="{ username: creator.username }"
|
||||||
|
>
|
||||||
|
<template #creator="{ children }">
|
||||||
|
<AutoLink
|
||||||
|
:to="creatorProfileLink"
|
||||||
|
class="inline-flex items-center gap-1 align-middle font-medium text-contrast hover:underline"
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
:src="creator.avatarUrl"
|
||||||
|
:alt="creator.username"
|
||||||
|
:tint-by="creator.username"
|
||||||
|
size="24px"
|
||||||
|
circle
|
||||||
|
no-shadow
|
||||||
|
/>
|
||||||
|
<component :is="() => children" />
|
||||||
|
</AutoLink>
|
||||||
|
</template>
|
||||||
|
</IntlFormatted>
|
||||||
|
<template v-else>
|
||||||
|
{{ formatMessage(messages.inviteWarning) }}
|
||||||
|
</template>
|
||||||
</p>
|
</p>
|
||||||
<SharedInstanceInstallSummary
|
<SharedInstanceInstallSummary
|
||||||
:preview="preview"
|
:preview="preview"
|
||||||
@@ -226,6 +250,7 @@ import { BanIcon, DownloadIcon, ReportIcon, SendIcon, SpinnerIcon, XIcon } from
|
|||||||
import {
|
import {
|
||||||
Admonition,
|
Admonition,
|
||||||
AutoLink,
|
AutoLink,
|
||||||
|
Avatar,
|
||||||
ButtonStyled,
|
ButtonStyled,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Combobox,
|
Combobox,
|
||||||
@@ -243,8 +268,10 @@ import {
|
|||||||
useScrollIndicator,
|
useScrollIndicator,
|
||||||
useVIntl,
|
useVIntl,
|
||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
|
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||||
import { computed, nextTick, ref } from 'vue'
|
import { computed, nextTick, ref } from 'vue'
|
||||||
|
|
||||||
|
import { config } from '@/config'
|
||||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads'
|
import { hide_ads_window, show_ads_window } from '@/helpers/ads'
|
||||||
import { toError } from '@/helpers/errors'
|
import { toError } from '@/helpers/errors'
|
||||||
import type { SharedInstanceInstallPreview } from '@/helpers/install'
|
import type { SharedInstanceInstallPreview } from '@/helpers/install'
|
||||||
@@ -258,11 +285,16 @@ type ExternalFileRow = {
|
|||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
type SharedInstanceCreator = {
|
||||||
|
username: string
|
||||||
|
avatarUrl: string | null
|
||||||
|
}
|
||||||
|
|
||||||
const modal = ref<InstanceType<typeof NewModal>>()
|
const modal = ref<InstanceType<typeof NewModal>>()
|
||||||
const contentModal = ref<InstanceType<typeof ModpackContentModal>>()
|
const contentModal = ref<InstanceType<typeof ModpackContentModal>>()
|
||||||
const externalFileTable = ref<HTMLElement | null>(null)
|
const externalFileTable = ref<HTMLElement | null>(null)
|
||||||
const preview = ref<SharedInstanceInstallPreview | null>(null)
|
const preview = ref<SharedInstanceInstallPreview | null>(null)
|
||||||
|
const creator = ref<SharedInstanceCreator | null>(null)
|
||||||
const install = ref<() => void | Promise<void>>(() => {})
|
const install = ref<() => void | Promise<void>>(() => {})
|
||||||
const reportMode = ref(false)
|
const reportMode = ref(false)
|
||||||
const reportOnly = ref(false)
|
const reportOnly = ref(false)
|
||||||
@@ -302,6 +334,12 @@ const reportReasonOptions = computed<ComboboxOption<ReportReason>[]>(() => [
|
|||||||
const canSubmitReport = computed(
|
const canSubmitReport = computed(
|
||||||
() => Boolean(preview.value && additionalContext.value.trim()) && !submitLoading.value,
|
() => Boolean(preview.value && additionalContext.value.trim()) && !submitLoading.value,
|
||||||
)
|
)
|
||||||
|
const creatorProfileLink = computed(() => {
|
||||||
|
const username = creator.value?.username
|
||||||
|
return username
|
||||||
|
? () => openUrl(`${config.siteUrl}/user/${encodeURIComponent(username)}`)
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
|
|
||||||
async function accept() {
|
async function accept() {
|
||||||
hide()
|
hide()
|
||||||
@@ -381,6 +419,7 @@ function handleCancel() {
|
|||||||
}
|
}
|
||||||
function handleHide() {
|
function handleHide() {
|
||||||
resetReportState()
|
resetReportState()
|
||||||
|
creator.value = null
|
||||||
show_ads_window()
|
show_ads_window()
|
||||||
}
|
}
|
||||||
function resetReportState() {
|
function resetReportState() {
|
||||||
@@ -395,14 +434,17 @@ function resetReportState() {
|
|||||||
function show(
|
function show(
|
||||||
previewValue: SharedInstanceInstallPreview,
|
previewValue: SharedInstanceInstallPreview,
|
||||||
installValue: () => void | Promise<void>,
|
installValue: () => void | Promise<void>,
|
||||||
|
creatorValue?: SharedInstanceCreator,
|
||||||
event?: MouseEvent,
|
event?: MouseEvent,
|
||||||
) {
|
) {
|
||||||
resetReportState()
|
resetReportState()
|
||||||
|
creator.value = creatorValue ?? null
|
||||||
install.value = installValue
|
install.value = installValue
|
||||||
showPreview(previewValue, event)
|
showPreview(previewValue, event)
|
||||||
}
|
}
|
||||||
function showReport(previewValue: SharedInstanceInstallPreview, event?: MouseEvent) {
|
function showReport(previewValue: SharedInstanceInstallPreview, event?: MouseEvent) {
|
||||||
resetReportState()
|
resetReportState()
|
||||||
|
creator.value = null
|
||||||
reportMode.value = true
|
reportMode.value = true
|
||||||
reportOnly.value = true
|
reportOnly.value = true
|
||||||
install.value = () => {}
|
install.value = () => {}
|
||||||
@@ -437,6 +479,11 @@ const messages = defineMessages({
|
|||||||
defaultMessage:
|
defaultMessage:
|
||||||
'This invite was created by another Modrinth user, not Modrinth. Only accept invites from people you trust.',
|
'This invite was created by another Modrinth user, not Modrinth. Only accept invites from people you trust.',
|
||||||
},
|
},
|
||||||
|
inviteWarningWithCreator: {
|
||||||
|
id: 'app.modal.install-to-play.invite-warning-with-creator',
|
||||||
|
defaultMessage:
|
||||||
|
'This invite was created by <creator>{username}</creator>, not Modrinth. Only accept invites from people you trust.',
|
||||||
|
},
|
||||||
reportDescription: {
|
reportDescription: {
|
||||||
id: 'app.modal.install-to-play.report-description',
|
id: 'app.modal.install-to-play.report-description',
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
|
|||||||
+44
-15
@@ -29,9 +29,15 @@ type InstallModal = {
|
|||||||
show(
|
show(
|
||||||
preview: Awaited<ReturnType<typeof install_get_shared_instance_preview>>,
|
preview: Awaited<ReturnType<typeof install_get_shared_instance_preview>>,
|
||||||
install: () => Promise<void>,
|
install: () => Promise<void>,
|
||||||
|
creator?: SharedInstanceCreator,
|
||||||
): void
|
): void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SharedInstanceCreator = {
|
||||||
|
username: string
|
||||||
|
avatarUrl: string | null
|
||||||
|
}
|
||||||
|
|
||||||
type AccountRequiredModal = {
|
type AccountRequiredModal = {
|
||||||
show(event?: MouseEvent): Promise<boolean>
|
show(event?: MouseEvent): Promise<boolean>
|
||||||
}
|
}
|
||||||
@@ -63,6 +69,7 @@ export function useSharedInstanceInviteHandler(
|
|||||||
instanceId: string
|
instanceId: string
|
||||||
preview: Awaited<ReturnType<typeof install_get_shared_instance_preview>>
|
preview: Awaited<ReturnType<typeof install_get_shared_instance_preview>>
|
||||||
install: () => Promise<void>
|
install: () => Promise<void>
|
||||||
|
creator?: SharedInstanceCreator
|
||||||
onGoToInstance?: () => void | Promise<void>
|
onGoToInstance?: () => void | Promise<void>
|
||||||
}
|
}
|
||||||
| undefined
|
| undefined
|
||||||
@@ -78,7 +85,7 @@ export function useSharedInstanceInviteHandler(
|
|||||||
|
|
||||||
async function resolveInvite(invite: SharedInstanceInvite) {
|
async function resolveInvite(invite: SharedInstanceInvite) {
|
||||||
const [invitedBy, sharedInstance] = await Promise.all([
|
const [invitedBy, sharedInstance] = await Promise.all([
|
||||||
!invite.invitedByUsername && invite.invitedById
|
(!invite.invitedByUsername || !invite.invitedByAvatarUrl) && invite.invitedById
|
||||||
? get_user(invite.invitedById, 'bypass').catch(() => null)
|
? get_user(invite.invitedById, 'bypass').catch(() => null)
|
||||||
: null,
|
: null,
|
||||||
client.sharedinstances.instances_v1.get(invite.sharedInstanceId).catch(() => {
|
client.sharedinstances.instances_v1.get(invite.sharedInstanceId).catch(() => {
|
||||||
@@ -98,15 +105,17 @@ export function useSharedInstanceInviteHandler(
|
|||||||
function showInstall(
|
function showInstall(
|
||||||
preview: Awaited<ReturnType<typeof install_get_shared_instance_preview>>,
|
preview: Awaited<ReturnType<typeof install_get_shared_instance_preview>>,
|
||||||
install: () => Promise<void>,
|
install: () => Promise<void>,
|
||||||
|
creator?: SharedInstanceCreator,
|
||||||
) {
|
) {
|
||||||
if (!installModal.value) throw new Error('Shared instance install modal is not available.')
|
if (!installModal.value) throw new Error('Shared instance install modal is not available.')
|
||||||
installModal.value.show(preview, install)
|
installModal.value.show(preview, install, creator)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showInstallOrAlreadyInstalled(
|
async function showInstallOrAlreadyInstalled(
|
||||||
sharedInstanceId: string,
|
sharedInstanceId: string,
|
||||||
preview: Awaited<ReturnType<typeof install_get_shared_instance_preview>>,
|
preview: Awaited<ReturnType<typeof install_get_shared_instance_preview>>,
|
||||||
install: () => Promise<void>,
|
install: () => Promise<void>,
|
||||||
|
creator?: SharedInstanceCreator,
|
||||||
onGoToInstance?: () => void | Promise<void>,
|
onGoToInstance?: () => void | Promise<void>,
|
||||||
) {
|
) {
|
||||||
const existingInstance = (await list()).find(
|
const existingInstance = (await list()).find(
|
||||||
@@ -114,7 +123,7 @@ export function useSharedInstanceInviteHandler(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (!existingInstance || themeStore.getFeatureFlag('skip_non_essential_warnings')) {
|
if (!existingInstance || themeStore.getFeatureFlag('skip_non_essential_warnings')) {
|
||||||
showInstall(preview, install)
|
showInstall(preview, install, creator)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +135,7 @@ export function useSharedInstanceInviteHandler(
|
|||||||
instanceId: existingInstance.id,
|
instanceId: existingInstance.id,
|
||||||
preview,
|
preview,
|
||||||
install,
|
install,
|
||||||
|
creator,
|
||||||
onGoToInstance,
|
onGoToInstance,
|
||||||
}
|
}
|
||||||
alreadyInstalledModal.value.show(existingInstance.name)
|
alreadyInstalledModal.value.show(existingInstance.name)
|
||||||
@@ -154,7 +164,7 @@ export function useSharedInstanceInviteHandler(
|
|||||||
const pending = pendingAlreadyInstalled
|
const pending = pendingAlreadyInstalled
|
||||||
pendingAlreadyInstalled = undefined
|
pendingAlreadyInstalled = undefined
|
||||||
if (!pending) return
|
if (!pending) return
|
||||||
showInstall(pending.preview, pending.install)
|
showInstall(pending.preview, pending.install, pending.creator)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function acceptNotification(notification: AppNotification, invite: SharedInstanceInvite) {
|
async function acceptNotification(notification: AppNotification, invite: SharedInstanceInvite) {
|
||||||
@@ -180,6 +190,12 @@ export function useSharedInstanceInviteHandler(
|
|||||||
await markNotificationRead(notification)
|
await markNotificationRead(notification)
|
||||||
await queryClient.invalidateQueries({ queryKey: ['instances'] })
|
await queryClient.invalidateQueries({ queryKey: ['instances'] })
|
||||||
},
|
},
|
||||||
|
invite.invitedByUsername
|
||||||
|
? {
|
||||||
|
username: invite.invitedByUsername,
|
||||||
|
avatarUrl: invite.invitedByAvatarUrl,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
() => markNotificationRead(notification),
|
() => markNotificationRead(notification),
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -261,17 +277,30 @@ export function useSharedInstanceInviteHandler(
|
|||||||
try {
|
try {
|
||||||
if (!(await requireAccount())) return
|
if (!(await requireAccount())) return
|
||||||
const invite = await install_accept_shared_instance_invite(inviteId)
|
const invite = await install_accept_shared_instance_invite(inviteId)
|
||||||
await showInstallOrAlreadyInstalled(invite.sharedInstanceId, invite.preview, async () => {
|
const manager = invite.managerId
|
||||||
await install_shared_instance(
|
? await get_user(invite.managerId, 'bypass').catch(() => null)
|
||||||
invite.sharedInstanceId,
|
: null
|
||||||
invite.preview.name,
|
await showInstallOrAlreadyInstalled(
|
||||||
invite.managerId,
|
invite.sharedInstanceId,
|
||||||
invite.serverManagerName,
|
invite.preview,
|
||||||
invite.serverManagerIconUrl,
|
async () => {
|
||||||
invite.instanceIconUrl,
|
await install_shared_instance(
|
||||||
)
|
invite.sharedInstanceId,
|
||||||
await queryClient.invalidateQueries({ queryKey: ['instances'] })
|
invite.preview.name,
|
||||||
})
|
invite.managerId,
|
||||||
|
invite.serverManagerName,
|
||||||
|
invite.serverManagerIconUrl,
|
||||||
|
invite.instanceIconUrl,
|
||||||
|
)
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ['instances'] })
|
||||||
|
},
|
||||||
|
manager
|
||||||
|
? {
|
||||||
|
username: manager.username,
|
||||||
|
avatarUrl: manager.avatar_url ?? null,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifySharedInstanceError(error)
|
notifySharedInstanceError(error)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user