Skip to content
2 changes: 1 addition & 1 deletion apps/frontend/src/components/ui/auth/CreateAccount.vue
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ const messages = defineMessages({
defaultMessage: 'Please enter a valid date of birth. Year cannot be 0000.',
},
under13HelperText: {
id: 'auth.create-account.date-of-birth.under13-helper',
id: 'auth.create-account.date-of-birth.not-meet-age-requirement',
defaultMessage: 'You do not meet the age requirement to create an account at Modrinth.',
},
ageRequirementWarningTitle: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<script setup lang="ts">
import { Avatar } from '@modrinth/ui'

import ModerationOwnerLink, { type ModerationOwner } from './ModerationOwnerLink.vue'
export type { ModerationOwner }

defineProps<{
avatarUrl?: string | null
title: string
titleTo?: string | null
owner?: ModerationOwner | null
circle?: boolean
padTransparentCorners?: boolean
}>()
</script>

<template>
<div class="flex items-center gap-3">
<NuxtLink v-if="titleTo" :to="titleTo" target="_blank" tabindex="-1">
<Avatar
:src="avatarUrl"
:circle="circle"
:pad-transparent-corners="padTransparentCorners"
no-shadow
size="4rem"
/>
</NuxtLink>
<Avatar
v-else
:src="avatarUrl"
:circle="circle"
:pad-transparent-corners="padTransparentCorners"
no-shadow
size="4rem"
/>

<div class="flex flex-col gap-1.5">
<div class="flex flex-wrap items-center gap-2">
<NuxtLink
v-if="titleTo"
:to="titleTo"
target="_blank"
class="text-lg font-semibold text-contrast hover:underline focus-visible:underline"
>
{{ title }}
</NuxtLink>
<span v-else class="text-lg font-semibold text-contrast">
{{ title }}
</span>
<slot name="badges" />
</div>

<ModerationOwnerLink v-if="owner" :owner="owner" />
<slot name="subtitle" />
</div>
</div>
</template>
33 changes: 33 additions & 0 deletions apps/frontend/src/components/ui/moderation/ModerationOwnerLink.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup lang="ts">
import { Avatar, CopyCode } from '@modrinth/ui'

export type ModerationOwner = {
kind: 'user' | 'organization'
id: string
name: string
icon_url?: string | null
}

defineProps<{
owner: ModerationOwner
}>()
</script>

<template>
<div class="flex items-center gap-2">
<NuxtLink
:to="`/${owner.kind}/${owner.id}`"
target="_blank"
class="flex items-center gap-1 text-sm font-medium text-secondary hover:underline"
>
<Avatar :src="owner.icon_url" :circle="owner.kind === 'user'" size="1.5rem" no-shadow />
{{ owner.name }}
</NuxtLink>
<ClientOnly>
<CopyCode
v-tooltip="owner.kind === 'organization' ? 'Copy organization ID' : 'Copy user ID'"
:text="owner.id"
/>
</ClientOnly>
</div>
</template>
49 changes: 18 additions & 31 deletions apps/frontend/src/components/ui/moderation/ModerationQueueCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,20 @@
</span>

<div class="flex items-center gap-2">
<IconButton v-tooltip="'Copy ID'" :label="'Copy ID'" @click="copyId">
<ClipboardCopyIcon />
</IconButton>
<IconButton v-tooltip="'Copy link'" :label="'Copy link'" @click="copyLink">
<LinkIcon />
</IconButton>
<CopyCode v-tooltip="'Copy project ID'" :text="queueEntry.project.id" />
<CopyLinkButton
v-tooltip="'Copy project link'"
:url="`https://modrinth.com/project/${queueEntry.project.id}`"
/>
<ButtonLink
v-tooltip="'Open moderation thread'"
:href="`/project/${queueEntry.project.id}/moderation`"
target="_blank"
circular
icon-only
>
<ExternalIcon />
</ButtonLink>
<IconButton
v-tooltip="'Begin review'"
type="colored"
Expand All @@ -124,13 +132,15 @@
</template>

<script setup lang="ts">
import { ClipboardCopyIcon, FileIcon, LinkIcon, ScaleIcon } from '@modrinth/assets'
import { ExternalIcon, FileIcon, ScaleIcon } from '@modrinth/assets'
import {
Avatar,
Badge,
ButtonLink,
CopyCode,
CopyLinkButton,
getProjectTypeIcon,
IconButton,
injectNotificationManager,
useFormatDateTime,
useRelativeTime,
} from '@modrinth/ui'
Expand All @@ -140,7 +150,6 @@ import { computed } from 'vue'

import type { ModerationProject } from '~/helpers/moderation'

const { addNotification } = injectNotificationManager()
const formatRelativeTime = useRelativeTime()
const formatDateTimeFull = useFormatDateTime({
weekday: 'short',
Expand Down Expand Up @@ -199,28 +208,6 @@ const formattedDate = computed(() => {
}
})

function copyLink() {
const base = window.location.origin
const projectUrl = `${base}/project/${projectRouteParam.value}`
navigator.clipboard.writeText(projectUrl).then(() => {
addNotification({
type: 'success',
title: 'Project link copied',
text: 'The link to this project has been copied to your clipboard.',
})
})
}

function copyId() {
navigator.clipboard.writeText(props.queueEntry.project.id).then(() => {
addNotification({
type: 'success',
title: 'Project ID copied',
text: 'The ID of this project has been copied to your clipboard.',
})
})
}

function openProjectForReview() {
emit('startFromProject', props.queueEntry.project.id)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,28 @@
<slot name="actions" />
</div>
</div>

<div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
<div class="flex min-w-0 flex-wrap items-center gap-3">
<slot name="meta" />
<div v-if="loading" class="h-6 w-64 animate-pulse rounded-full bg-surface-3"></div>
<slot v-else name="meta" />
</div>
<div class="flex shrink-0 items-center justify-end gap-2 sm:ml-auto">
<slot name="pagination-extra" />
<Pagination
v-if="totalPages > 1"
:page="page"
:count="totalPages"
@switch-page="$emit('switch-page', $event)"
/>
<div v-if="loading && !(totalPages > 1)" class="flex items-center gap-2">
<div
v-for="i in 3"
:key="`loading-skeleton-${i}`"
class="h-9 w-9 animate-pulse rounded-full bg-surface-3"
></div>
</div>
<template v-else>
<slot name="pagination-extra" />
<Pagination
v-if="totalPages > 1"
:page="page"
:count="totalPages"
@switch-page="$emit('switch-page', $event)"
/>
</template>
</div>
</div>
</div>
Expand All @@ -45,6 +54,7 @@ const query = defineModel<string>({ required: true })
defineProps<{
page: number
totalPages: number
loading?: boolean
}>()

defineEmits<{
Expand Down
Loading
Loading