diff --git a/packages/ui/src/layouts/shared/user-profile/layout.vue b/packages/ui/src/layouts/shared/user-profile/layout.vue
index be4f1644b9..9c3b008a6b 100644
--- a/packages/ui/src/layouts/shared/user-profile/layout.vue
+++ b/packages/ui/src/layouts/shared/user-profile/layout.vue
@@ -111,7 +111,33 @@
{{ formatMessage(messages.authProvidersLabel) }}
- {{ user.auth_providers?.join(', ') || '—' }}
+
+ -
+ {{ authProviderNames[provider] ?? provider }}
+
+ ({{ user.discord_id }})
+
+
+ (
+
+ )
+
+
+ ({{ user.steam_id }})
+
+
+
@@ -460,7 +486,13 @@ import ProjectCardList from '#ui/components/project/ProjectCardList.vue'
import UserBadges from '#ui/components/user/UserBadges.vue'
import UserPageHeader from '#ui/components/user/UserPageHeader.vue'
import { defineMessages, useVIntl } from '#ui/composables'
-import { injectAuth, injectNotificationManager, injectPageContext, injectTags } from '#ui/providers'
+import {
+ injectAuth,
+ injectModrinthClient,
+ injectNotificationManager,
+ injectPageContext,
+ injectTags,
+} from '#ui/providers'
import { commonMessages, getProjectTypeTitleMessage } from '#ui/utils'
import { blockedUsersQueryKey, injectUserProfile } from './providers'
@@ -520,6 +552,7 @@ const auth = injectAuth()
const tags = injectTags(null)
const pageContext = injectPageContext()
const notificationManager = injectNotificationManager()
+const client = injectModrinthClient()
const queryClient = useQueryClient()
const route = useRoute()
const router = useRouter()
@@ -567,6 +600,26 @@ const messages = defineMessages({
id: 'profile.details.label.auth-providers',
defaultMessage: 'Auth providers',
},
+ viewGithubProfileLabel: {
+ id: 'profile.details.label.view-github-profile',
+ defaultMessage: 'View profile',
+ },
+ loadingGithubProfileLabel: {
+ id: 'profile.details.label.loading-github-profile',
+ defaultMessage: 'Loading...',
+ },
+ githubProfileErrorTitle: {
+ id: 'profile.details.error.github-profile-title',
+ defaultMessage: 'Unable to open GitHub profile',
+ },
+ githubProfileErrorMessage: {
+ id: 'profile.details.error.github-profile-message',
+ defaultMessage: 'The GitHub profile could not be retrieved. Please try again.',
+ },
+ githubPopupBlockedMessage: {
+ id: 'profile.details.error.github-popup-blocked',
+ defaultMessage: 'Allow pop-ups for Modrinth, then try again.',
+ },
paymentMethodsLabel: {
id: 'profile.details.label.payment-methods',
defaultMessage: 'Payment methods',
@@ -853,6 +906,17 @@ const showCollectionsEmptyState = computed(
const normalizedSiteUrl = computed(() => props.siteUrl.replace(/\/$/, ''))
const editProfileLink = computed(() => props.editProfileLink ?? linkTarget('/settings/profile'))
+const authProviderNames = {
+ github: 'GitHub',
+ discord: 'Discord',
+ microsoft: 'Microsoft',
+ gitlab: 'GitLab',
+ google: 'Google',
+ steam: 'Steam',
+ paypal: 'PayPal',
+}
+const isLoadingGithubProfile = ref(false)
+
function externalUrl(path: string): string {
return `${normalizedSiteUrl.value}${path.startsWith('/') ? path : `/${path}`}`
}
@@ -896,6 +960,50 @@ async function copyPermalink(): Promise {
}
}
+async function openGithubProfile() {
+ const githubId = user.value?.github_id
+ if (!githubId || isLoadingGithubProfile.value) return
+
+ const profileWindow = window.open('about:blank', '_blank')
+ if (!profileWindow) {
+ notificationManager.addNotification({
+ type: 'error',
+ title: formatMessage(messages.githubProfileErrorTitle),
+ text: formatMessage(messages.githubPopupBlockedMessage),
+ })
+ return
+ }
+
+ profileWindow.opener = null
+ isLoadingGithubProfile.value = true
+
+ try {
+ const githubUser = await client.request<{ login?: string }>(`/${githubId}`, {
+ api: 'https://api.github.com',
+ version: 'user',
+ method: 'GET',
+ headers: { 'Content-Type': '' },
+ skipAuth: true,
+ })
+
+ if (!githubUser?.login) {
+ throw new Error('GitHub user response did not include a login')
+ }
+
+ profileWindow.location.replace(`https://github.com/${encodeURIComponent(githubUser.login)}`)
+ } catch (error) {
+ profileWindow.close()
+ console.error('Failed to retrieve GitHub profile:', error)
+ notificationManager.addNotification({
+ type: 'error',
+ title: formatMessage(messages.githubProfileErrorTitle),
+ text: formatMessage(messages.githubProfileErrorMessage),
+ })
+ } finally {
+ isLoadingGithubProfile.value = false
+ }
+}
+
function reportProfile(): void {
if (!user.value) return
const reportPath = `/report?item=user&itemID=${encodeURIComponent(user.value.id)}`
diff --git a/packages/ui/src/locales/en-US/index.json b/packages/ui/src/locales/en-US/index.json
index e1c3941001..f842c47c3d 100644
--- a/packages/ui/src/locales/en-US/index.json
+++ b/packages/ui/src/locales/en-US/index.json
@@ -2921,6 +2921,15 @@
"profile.collection.projects-count": {
"defaultMessage": "{count, plural, one {# project} other {# projects}}"
},
+ "profile.details.error.github-popup-blocked": {
+ "defaultMessage": "Allow pop-ups for Modrinth, then try again."
+ },
+ "profile.details.error.github-profile-message": {
+ "defaultMessage": "The GitHub profile could not be retrieved. Please try again."
+ },
+ "profile.details.error.github-profile-title": {
+ "defaultMessage": "Unable to open GitHub profile"
+ },
"profile.details.label.auth-providers": {
"defaultMessage": "Auth providers"
},
@@ -2933,9 +2942,15 @@
"profile.details.label.has-totp": {
"defaultMessage": "Has TOTP"
},
+ "profile.details.label.loading-github-profile": {
+ "defaultMessage": "Loading..."
+ },
"profile.details.label.payment-methods": {
"defaultMessage": "Payment methods"
},
+ "profile.details.label.view-github-profile": {
+ "defaultMessage": "View profile"
+ },
"profile.details.title": {
"defaultMessage": "User details"
},