mirror of
https://github.com/modrinth/code.git
synced 2026-09-04 05:48:57 +00:00
Make "Open Image in New Tab" open raw image (when possible) (#7315)
* tell search engines not to index collections because bots keep spamming them and I can basically guarantee not a single human being is using collections in a way where this will be detrimental to them (besides the advertisement spam) * Index creator created collections * Open raw images from open image in new tab option in context menu
This commit is contained in:
@@ -3,7 +3,12 @@
|
|||||||
<template #title>
|
<template #title>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class="text-lg font-extrabold text-contrast">Transfer</span>
|
<span class="text-lg font-extrabold text-contrast">Transfer</span>
|
||||||
<Avatar :src="organization.icon_url" :alt="organization.name" size="xs" />
|
<Avatar
|
||||||
|
:src="organization.icon_url"
|
||||||
|
:raw-src="organization.raw_icon_url"
|
||||||
|
:alt="organization.name"
|
||||||
|
size="xs"
|
||||||
|
/>
|
||||||
<span class="text-lg font-extrabold text-contrast">{{ organization.name }}</span>
|
<span class="text-lg font-extrabold text-contrast">{{ organization.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -3,7 +3,12 @@
|
|||||||
<template #title>
|
<template #title>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class="text-lg font-extrabold text-contrast">Transfer</span>
|
<span class="text-lg font-extrabold text-contrast">Transfer</span>
|
||||||
<Avatar :src="project.icon_url" :alt="project.name" size="xs" />
|
<Avatar
|
||||||
|
:src="project.icon_url"
|
||||||
|
:raw-src="project.raw_icon_url"
|
||||||
|
:alt="project.name"
|
||||||
|
size="xs"
|
||||||
|
/>
|
||||||
<span class="text-lg font-extrabold text-contrast">{{ project.name }}</span>
|
<span class="text-lg font-extrabold text-contrast">{{ project.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<template #leading>
|
<template #leading>
|
||||||
<Avatar
|
<Avatar
|
||||||
:src="organization.icon_url"
|
:src="organization.icon_url"
|
||||||
|
:raw-src="organization.raw_icon_url"
|
||||||
:alt="organization.name"
|
:alt="organization.name"
|
||||||
:tint-by="organization.id"
|
:tint-by="organization.id"
|
||||||
size="96px"
|
size="96px"
|
||||||
|
|||||||
@@ -18,7 +18,12 @@
|
|||||||
>
|
>
|
||||||
<LeftArrowIcon />
|
<LeftArrowIcon />
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
<Avatar :src="project.icon_url" :tint-by="project.id" size="64px" />
|
<Avatar
|
||||||
|
:src="project.icon_url"
|
||||||
|
:raw-src="project.raw_icon_url"
|
||||||
|
:tint-by="project.id"
|
||||||
|
size="64px"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #metadata>
|
<template #metadata>
|
||||||
<PageHeaderMetadata>
|
<PageHeaderMetadata>
|
||||||
|
|||||||
@@ -216,6 +216,7 @@
|
|||||||
<img
|
<img
|
||||||
:src="item.url ? item.url : 'https://cdn.modrinth.com/placeholder-banner.svg'"
|
:src="item.url ? item.url : 'https://cdn.modrinth.com/placeholder-banner.svg'"
|
||||||
:alt="item.title ? item.title : 'gallery-image'"
|
:alt="item.title ? item.title : 'gallery-image'"
|
||||||
|
@contextmenu="onFullImageContextMenu($event, item.raw_url)"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<div class="gallery-body">
|
<div class="gallery-body">
|
||||||
@@ -308,6 +309,7 @@ import {
|
|||||||
NewModal as Modal,
|
NewModal as Modal,
|
||||||
Textarea,
|
Textarea,
|
||||||
useFormatDateTime,
|
useFormatDateTime,
|
||||||
|
useFullImageContextMenu,
|
||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
import { useEventListener } from '@vueuse/core'
|
import { useEventListener } from '@vueuse/core'
|
||||||
|
|
||||||
@@ -320,6 +322,7 @@ const formatDate = useFormatDateTime({
|
|||||||
month: 'long',
|
month: 'long',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
})
|
})
|
||||||
|
const onFullImageContextMenu = useFullImageContextMenu()
|
||||||
|
|
||||||
// Single DI injection
|
// Single DI injection
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -215,6 +215,7 @@
|
|||||||
<img
|
<img
|
||||||
:src="item.url ? item.url : 'https://cdn.modrinth.com/placeholder-banner.svg'"
|
:src="item.url ? item.url : 'https://cdn.modrinth.com/placeholder-banner.svg'"
|
||||||
:alt="item.title ? item.title : 'gallery-image'"
|
:alt="item.title ? item.title : 'gallery-image'"
|
||||||
|
@contextmenu="onFullImageContextMenu($event, item.raw_url)"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<div class="gallery-body">
|
<div class="gallery-body">
|
||||||
@@ -299,6 +300,7 @@ import {
|
|||||||
NewModal as Modal,
|
NewModal as Modal,
|
||||||
Textarea,
|
Textarea,
|
||||||
useFormatDateTime,
|
useFormatDateTime,
|
||||||
|
useFullImageContextMenu,
|
||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
|
|
||||||
import AiImageWarningModal from '~/components/ui/AiImageWarningModal.vue'
|
import AiImageWarningModal from '~/components/ui/AiImageWarningModal.vue'
|
||||||
@@ -310,6 +312,7 @@ const formatDate = useFormatDateTime({
|
|||||||
month: 'long',
|
month: 'long',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
})
|
})
|
||||||
|
const onFullImageContextMenu = useFullImageContextMenu()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
projectV2: project,
|
projectV2: project,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<div v-else-if="app && createdBy && authorizationData" class="flex flex-col gap-6">
|
<div v-else-if="app && createdBy && authorizationData" class="flex flex-col gap-6">
|
||||||
<div class="mt-4 flex items-center justify-center">
|
<div class="mt-4 flex items-center justify-center">
|
||||||
<div class="flex w-full flex-row items-center justify-evenly">
|
<div class="flex w-full flex-row items-center justify-evenly">
|
||||||
<Avatar size="md" :src="app.icon_url" />
|
<Avatar size="md" :src="app.icon_url" :raw-src="app.raw_icon_url" />
|
||||||
<!-- <img class="profile-pic" :src="app.icon_url" alt="User profile picture" /> -->
|
<!-- <img class="profile-pic" :src="app.icon_url" alt="User profile picture" /> -->
|
||||||
<div class="flex select-none items-center justify-center text-[2rem] text-primary">→</div>
|
<div class="flex select-none items-center justify-center text-[2rem] text-primary">→</div>
|
||||||
<Avatar size="md" circle :src="auth.user?.avatar_url" />
|
<Avatar size="md" circle :src="auth.user?.avatar_url" />
|
||||||
|
|||||||
@@ -150,7 +150,7 @@
|
|||||||
</nuxt-link>
|
</nuxt-link>
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
<div class="grid grid-cols-[auto_1fr] gap-4 sm:grid-cols-[auto_1fr_auto]">
|
<div class="grid grid-cols-[auto_1fr] gap-4 sm:grid-cols-[auto_1fr_auto]">
|
||||||
<Avatar :src="collection.icon_url" size="64px" />
|
<Avatar :src="collection.icon_url" :raw-src="collection.raw_icon_url" size="64px" />
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<h1 class="heading-2xl">
|
<h1 class="heading-2xl">
|
||||||
{{ collection.name }}
|
{{ collection.name }}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
class="bg-surface mb-4 flex flex-col rounded-xl border border-solid border-surface-4 p-4"
|
class="bg-surface mb-4 flex flex-col rounded-xl border border-solid border-surface-4 p-4"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<Avatar size="sm" :src="organization.icon_url" />
|
<Avatar size="sm" :src="organization.icon_url" :raw-src="organization.raw_icon_url" />
|
||||||
<div class="flex flex-col justify-center gap-1">
|
<div class="flex flex-col justify-center gap-1">
|
||||||
<h2 class="m-0 text-base">
|
<h2 class="m-0 text-base">
|
||||||
<nuxt-link :to="`/organization/${organization.slug}`">
|
<nuxt-link :to="`/organization/${organization.slug}`">
|
||||||
|
|||||||
@@ -181,7 +181,7 @@
|
|||||||
<div v-for="app in usersApps" :key="app.id" class="universal-card recessed token mt-4">
|
<div v-for="app in usersApps" :key="app.id" class="universal-card recessed token mt-4">
|
||||||
<div class="token-info">
|
<div class="token-info">
|
||||||
<div class="token-icon">
|
<div class="token-icon">
|
||||||
<Avatar size="sm" :src="app.icon_url" />
|
<Avatar size="sm" :src="app.icon_url" :raw-src="app.raw_icon_url" />
|
||||||
<div>
|
<div>
|
||||||
<h2 class="token-title">{{ app.name }}</h2>
|
<h2 class="token-title">{{ app.name }}</h2>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -869,6 +869,7 @@ export namespace Labrinth {
|
|||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
icon_url: string | null
|
icon_url: string | null
|
||||||
|
raw_icon_url: string | null
|
||||||
max_scopes: number
|
max_scopes: number
|
||||||
redirect_uris: OAuthRedirectUri[]
|
redirect_uris: OAuthRedirectUri[]
|
||||||
created_by: string
|
created_by: string
|
||||||
@@ -1002,6 +1003,7 @@ export namespace Labrinth {
|
|||||||
loaders: string[]
|
loaders: string[]
|
||||||
versions: string[]
|
versions: string[]
|
||||||
icon_url?: string
|
icon_url?: string
|
||||||
|
raw_icon_url?: string
|
||||||
issues_url?: string
|
issues_url?: string
|
||||||
source_url?: string
|
source_url?: string
|
||||||
wiki_url?: string
|
wiki_url?: string
|
||||||
@@ -1145,6 +1147,7 @@ export namespace Labrinth {
|
|||||||
mrpack_loaders: string[]
|
mrpack_loaders: string[]
|
||||||
versions: string[]
|
versions: string[]
|
||||||
icon_url?: string
|
icon_url?: string
|
||||||
|
raw_icon_url?: string
|
||||||
link_urls: Record<string, Link>
|
link_urls: Record<string, Link>
|
||||||
gallery: GalleryItem[]
|
gallery: GalleryItem[]
|
||||||
color?: number
|
color?: number
|
||||||
@@ -1264,6 +1267,7 @@ export namespace Labrinth {
|
|||||||
team_id: string
|
team_id: string
|
||||||
description: string
|
description: string
|
||||||
icon_url: string | null
|
icon_url: string | null
|
||||||
|
raw_icon_url: string | null
|
||||||
color: number | null
|
color: number | null
|
||||||
members: TeamMember[]
|
members: TeamMember[]
|
||||||
}
|
}
|
||||||
@@ -1387,6 +1391,7 @@ export namespace Labrinth {
|
|||||||
team_id: string
|
team_id: string
|
||||||
description: string
|
description: string
|
||||||
icon_url: string | null
|
icon_url: string | null
|
||||||
|
raw_icon_url: string | null
|
||||||
color: number | null
|
color: number | null
|
||||||
members: Projects.v3.TeamMember[]
|
members: Projects.v3.TeamMember[]
|
||||||
moderation_notes?: Users.Common.ModerationNote | null
|
moderation_notes?: Users.Common.ModerationNote | null
|
||||||
@@ -2297,6 +2302,7 @@ export namespace Labrinth {
|
|||||||
name: string
|
name: string
|
||||||
description: string | null
|
description: string | null
|
||||||
icon_url: string | null
|
icon_url: string | null
|
||||||
|
raw_icon_url: string | null
|
||||||
color: number | null
|
color: number | null
|
||||||
status: CollectionStatus
|
status: CollectionStatus
|
||||||
created: string
|
created: string
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
:loading="loading"
|
:loading="loading"
|
||||||
@load="onLoad"
|
@load="onLoad"
|
||||||
@error="onError"
|
@error="onError"
|
||||||
|
@contextmenu="onFullImageContextMenu($event, rawSrc)"
|
||||||
/>
|
/>
|
||||||
<svg
|
<svg
|
||||||
v-else
|
v-else
|
||||||
@@ -50,6 +51,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'
|
import { computed, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'
|
||||||
|
|
||||||
|
import { useFullImageContextMenu } from '../../composables'
|
||||||
|
|
||||||
|
const onFullImageContextMenu = useFullImageContextMenu()
|
||||||
|
|
||||||
const pixelated = ref(false)
|
const pixelated = ref(false)
|
||||||
const hasTransparentCorners = ref(false)
|
const hasTransparentCorners = ref(false)
|
||||||
const hasDetectedCorners = ref(false)
|
const hasDetectedCorners = ref(false)
|
||||||
@@ -68,6 +73,7 @@ defineExpose({
|
|||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
src?: string | null
|
src?: string | null
|
||||||
|
rawSrc?: string | null
|
||||||
alt?: string
|
alt?: string
|
||||||
size?: string
|
size?: string
|
||||||
circle?: boolean
|
circle?: boolean
|
||||||
@@ -79,6 +85,7 @@ const props = withDefaults(
|
|||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
src: null,
|
src: null,
|
||||||
|
rawSrc: null,
|
||||||
alt: '',
|
alt: '',
|
||||||
size: '2rem',
|
size: '2rem',
|
||||||
circle: false,
|
circle: false,
|
||||||
|
|||||||
@@ -5,7 +5,13 @@
|
|||||||
@contextmenu="emit('contextmenu', $event)"
|
@contextmenu="emit('contextmenu', $event)"
|
||||||
>
|
>
|
||||||
<template #leading>
|
<template #leading>
|
||||||
<Avatar :src="project.icon_url" :alt="project.title" :tint-by="project.id" size="96px" />
|
<Avatar
|
||||||
|
:src="project.icon_url"
|
||||||
|
:raw-src="project.raw_icon_url"
|
||||||
|
:alt="project.title"
|
||||||
|
:tint-by="project.id"
|
||||||
|
size="96px"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="showStatusBadge" #badges>
|
<template v-if="showStatusBadge" #badges>
|
||||||
|
|||||||
@@ -5,7 +5,14 @@
|
|||||||
:header="project.license.name ? project.license.name : formatMessage(messages.licenseTitle)"
|
:header="project.license.name ? project.license.name : formatMessage(messages.licenseTitle)"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<Avatar :src="project.icon_url" :alt="project.title" class="icon" size="32px" no-shadow />
|
<Avatar
|
||||||
|
:src="project.icon_url"
|
||||||
|
:raw-src="project.raw_icon_url"
|
||||||
|
:alt="project.title"
|
||||||
|
class="icon"
|
||||||
|
size="32px"
|
||||||
|
no-shadow
|
||||||
|
/>
|
||||||
<span class="text-lg font-extrabold text-contrast">
|
<span class="text-lg font-extrabold text-contrast">
|
||||||
{{ project.license.name ? project.license.name : formatMessage(messages.licenseTitle) }}
|
{{ project.license.name ? project.license.name : formatMessage(messages.licenseTitle) }}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export function useFullImageContextMenu() {
|
||||||
|
return function onFullImageContextMenu(event: MouseEvent, fullUrl: string | null | undefined) {
|
||||||
|
if (!fullUrl) return
|
||||||
|
|
||||||
|
const img = event.currentTarget as HTMLImageElement
|
||||||
|
const originalSrc = img.src
|
||||||
|
if (originalSrc === fullUrl) return
|
||||||
|
|
||||||
|
img.src = fullUrl
|
||||||
|
window.addEventListener(
|
||||||
|
'focus',
|
||||||
|
() => {
|
||||||
|
img.src = originalSrc
|
||||||
|
},
|
||||||
|
{ once: true },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ export * from './format-bytes'
|
|||||||
export * from './format-date-time'
|
export * from './format-date-time'
|
||||||
export * from './format-money'
|
export * from './format-money'
|
||||||
export * from './format-number'
|
export * from './format-number'
|
||||||
|
export * from './full-image-context-menu'
|
||||||
export * from './hosting-intercom'
|
export * from './hosting-intercom'
|
||||||
export * from './how-ago'
|
export * from './how-ago'
|
||||||
export * from './i18n'
|
export * from './i18n'
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ export interface ProjectV3 {
|
|||||||
|
|
||||||
versions: ModrinthId[]
|
versions: ModrinthId[]
|
||||||
icon_url?: string
|
icon_url?: string
|
||||||
|
raw_icon_url?: string
|
||||||
|
|
||||||
link_urls: Record<
|
link_urls: Record<
|
||||||
string,
|
string,
|
||||||
@@ -129,6 +130,7 @@ export interface Project {
|
|||||||
|
|
||||||
body: string
|
body: string
|
||||||
icon_url?: string
|
icon_url?: string
|
||||||
|
raw_icon_url?: string
|
||||||
color?: number
|
color?: number
|
||||||
|
|
||||||
categories: Category[]
|
categories: Category[]
|
||||||
@@ -230,6 +232,7 @@ export type Organization = {
|
|||||||
team_id: ModrinthId
|
team_id: ModrinthId
|
||||||
description: string
|
description: string
|
||||||
icon_url: string
|
icon_url: string
|
||||||
|
raw_icon_url: string | null
|
||||||
color: number
|
color: number
|
||||||
members: OrganizationMember[]
|
members: OrganizationMember[]
|
||||||
}
|
}
|
||||||
@@ -254,6 +257,7 @@ export type Collection = {
|
|||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
icon_url: string
|
icon_url: string
|
||||||
|
raw_icon_url: string | null
|
||||||
color: number
|
color: number
|
||||||
status: CollectionStatus
|
status: CollectionStatus
|
||||||
created: string
|
created: string
|
||||||
|
|||||||
Reference in New Issue
Block a user