mediaまわりの修正
This commit is contained in:
		@@ -14,6 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
			title: image.name,
 | 
			
		||||
			class: $style.imageContainer,
 | 
			
		||||
			href: image.url,
 | 
			
		||||
			target: '_blank',
 | 
			
		||||
			rel: 'noopener',
 | 
			
		||||
			style: 'cursor: zoom-in;'
 | 
			
		||||
		}"
 | 
			
		||||
	>
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
<div>
 | 
			
		||||
	<XBanner v-for="media in mediaList.filter(media => !previewable(media))" :key="media.id" :media="media"/>
 | 
			
		||||
	<div v-for="media in mediaList.filter(media => !previewable(media))" :key="media.id" :class="$style.banner">
 | 
			
		||||
		<XBanner :media="media"/>
 | 
			
		||||
		<a v-if="inEmbedPage && originalEntityUrl" :href="originalEntityUrl" target="_blank" rel="noopener" :class="$style.mediaLinkForEmbed"></a>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div v-if="mediaList.filter(media => previewable(media)).length > 0" :class="$style.container">
 | 
			
		||||
		<div
 | 
			
		||||
			ref="gallery"
 | 
			
		||||
@@ -18,17 +21,18 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
				}] : count === 2 ? $style.n2 : count === 3 ? $style.n3 : count === 4 ? $style.n4 : $style.nMany,
 | 
			
		||||
			]"
 | 
			
		||||
		>
 | 
			
		||||
			<template v-for="media in mediaList.filter(media => previewable(media))">
 | 
			
		||||
				<XVideo v-if="media.type.startsWith('video')" :key="`video:${media.id}`" :class="$style.media" :video="media"/>
 | 
			
		||||
				<XImage v-else-if="media.type.startsWith('image')" :key="`image:${media.id}`" :class="$style.media" class="image" :data-id="media.id" :image="media" :raw="raw"/>
 | 
			
		||||
			</template>
 | 
			
		||||
			<div v-for="media in mediaList.filter(media => previewable(media))" :class="$style.media">
 | 
			
		||||
				<XVideo v-if="media.type.startsWith('video')" :key="`video:${media.id}`" :video="media" :class="$style.mediaInner"/>
 | 
			
		||||
				<XImage v-else-if="media.type.startsWith('image')" :key="`image:${media.id}`" :class="$style.mediaInner" class="image" :data-id="media.id" :image="media" :raw="raw"/>
 | 
			
		||||
				<a v-if="inEmbedPage && originalEntityUrl" :href="originalEntityUrl" target="_blank" rel="noopener" :class="$style.mediaLinkForEmbed"></a>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { computed, onMounted, onUnmounted, shallowRef } from 'vue';
 | 
			
		||||
import { computed, onMounted, onUnmounted, shallowRef, inject } from 'vue';
 | 
			
		||||
import * as Misskey from 'misskey-js';
 | 
			
		||||
import PhotoSwipeLightbox from 'photoswipe/lightbox';
 | 
			
		||||
import PhotoSwipe from 'photoswipe';
 | 
			
		||||
@@ -43,8 +47,13 @@ import { defaultStore } from '@/store.js';
 | 
			
		||||
const props = defineProps<{
 | 
			
		||||
	mediaList: Misskey.entities.DriveFile[];
 | 
			
		||||
	raw?: boolean;
 | 
			
		||||
 | 
			
		||||
	/** 埋め込みページ用 親要素の正規URL */
 | 
			
		||||
	originalEntityUrl?: string;
 | 
			
		||||
}>();
 | 
			
		||||
 | 
			
		||||
const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
 | 
			
		||||
 | 
			
		||||
const gallery = shallowRef<HTMLDivElement>();
 | 
			
		||||
const pswpZIndex = os.claimZIndex('middle');
 | 
			
		||||
document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString());
 | 
			
		||||
@@ -90,6 +99,7 @@ async function calcAspectRatio() {
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
	calcAspectRatio();
 | 
			
		||||
	if (defaultStore.state.imageNewTab || inEmbedPage) return;
 | 
			
		||||
 | 
			
		||||
	lightbox = new PhotoSwipeLightbox({
 | 
			
		||||
		dataSource: props.mediaList
 | 
			
		||||
@@ -284,6 +294,26 @@ const previewable = (file: Misskey.entities.DriveFile): boolean => {
 | 
			
		||||
.media {
 | 
			
		||||
	overflow: hidden; // clipにするとバグる
 | 
			
		||||
	border-radius: 8px;
 | 
			
		||||
	position: relative;
 | 
			
		||||
 | 
			
		||||
	>.mediaInner {
 | 
			
		||||
		width: 100%;
 | 
			
		||||
		height: 100%;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.banner {
 | 
			
		||||
	position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mediaLinkForEmbed::after {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	top: 0;
 | 
			
		||||
	left: 0;
 | 
			
		||||
	right: 0;
 | 
			
		||||
	bottom: 0;
 | 
			
		||||
	z-index: 1;
 | 
			
		||||
	content: '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:global(.pswp) {
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div v-if="appearNote.files && appearNote.files.length > 0">
 | 
			
		||||
						<MkMediaList :mediaList="appearNote.files"/>
 | 
			
		||||
						<MkMediaList :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/>
 | 
			
		||||
					</div>
 | 
			
		||||
					<MkPoll v-if="appearNote.poll" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
 | 
			
		||||
					<div v-if="isEnabledUrlPreview">
 | 
			
		||||
@@ -216,6 +216,7 @@ import MkRippleEffect from '@/components/MkRippleEffect.vue';
 | 
			
		||||
import { showMovedDialog } from '@/scripts/show-moved-dialog.js';
 | 
			
		||||
import { shouldCollapsed } from '@/scripts/collapsed.js';
 | 
			
		||||
import { isEnabledUrlPreview } from '@/instance.js';
 | 
			
		||||
import { url } from '@/config.js';
 | 
			
		||||
 | 
			
		||||
const props = withDefaults(defineProps<{
 | 
			
		||||
	note: Misskey.entities.Note;
 | 
			
		||||
 
 | 
			
		||||
@@ -101,7 +101,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div v-if="appearNote.files && appearNote.files.length > 0">
 | 
			
		||||
					<MkMediaList :mediaList="appearNote.files"/>
 | 
			
		||||
					<MkMediaList :mediaList="appearNote.files" :originalEntityUrl="`${url}/notes/${appearNote.id}`"/>
 | 
			
		||||
				</div>
 | 
			
		||||
				<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
 | 
			
		||||
				<div v-if="isEnabledUrlPreview">
 | 
			
		||||
@@ -645,7 +645,7 @@ function loadConversation() {
 | 
			
		||||
	font-size: 1.2em;
 | 
			
		||||
 | 
			
		||||
	&.embeddedNote {
 | 
			
		||||
		padding: 16px 32px;
 | 
			
		||||
		padding: 24px 32px 16px;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	&:hover > .main > .footer > .button {
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ const props = defineProps<{
 | 
			
		||||
}>();
 | 
			
		||||
 | 
			
		||||
const mock = inject<boolean>('mock', false);
 | 
			
		||||
const inEmbedPage = inject<boolean>('EMBED_PAGE', false);
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits<{
 | 
			
		||||
	(ev: 'reactionToggled', emoji: string, newCount: number): void;
 | 
			
		||||
@@ -140,7 +141,7 @@ onMounted(() => {
 | 
			
		||||
	if (!props.isInitial) anime();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
if (!mock) {
 | 
			
		||||
if (!mock && !inEmbedPage) {
 | 
			
		||||
	useTooltip(buttonEl, async (showing) => {
 | 
			
		||||
		const reactions = await misskeyApiGet('notes/reactions', {
 | 
			
		||||
			noteId: props.note.id,
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
	</div>
 | 
			
		||||
	<details v-if="note.files && note.files.length > 0">
 | 
			
		||||
		<summary>({{ i18n.tsx.withNFiles({ n: note.files.length }) }})</summary>
 | 
			
		||||
		<MkMediaList :mediaList="note.files"/>
 | 
			
		||||
		<MkMediaList :mediaList="note.files" :originalEntityUrl="`${url}/notes/${note.id}`"/>
 | 
			
		||||
	</details>
 | 
			
		||||
	<details v-if="note.poll">
 | 
			
		||||
		<summary>{{ i18n.ts.poll }}</summary>
 | 
			
		||||
@@ -36,6 +36,7 @@ import MkMediaList from '@/components/MkMediaList.vue';
 | 
			
		||||
import MkPoll from '@/components/MkPoll.vue';
 | 
			
		||||
import { i18n } from '@/i18n.js';
 | 
			
		||||
import { shouldCollapsed } from '@/scripts/collapsed.js';
 | 
			
		||||
import { url } from '@/config.js';
 | 
			
		||||
 | 
			
		||||
const props = defineProps<{
 | 
			
		||||
	note: Misskey.entities.Note;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,16 +12,19 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref } from 'vue';
 | 
			
		||||
import { ref, provide } from 'vue';
 | 
			
		||||
import * as Misskey from 'misskey-js';
 | 
			
		||||
import MkNoteDetailed from '@/components/MkNoteDetailed.vue';
 | 
			
		||||
import XNotFound from '@/pages/not-found.vue';
 | 
			
		||||
import { misskeyApi } from '@/scripts/misskey-api.js';
 | 
			
		||||
import { url } from '@/config.js';
 | 
			
		||||
 | 
			
		||||
const props = defineProps<{
 | 
			
		||||
	noteId: string;
 | 
			
		||||
}>();
 | 
			
		||||
 | 
			
		||||
provide('EMBED_ORIGINAL_ENTITY_URL', `${url}/notes/${props.noteId}`);
 | 
			
		||||
 | 
			
		||||
const note = ref<Misskey.entities.Note | null>(null);
 | 
			
		||||
const loading = ref(true);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
							</a>
 | 
			
		||||
						</template>
 | 
			
		||||
					</I18n>
 | 
			
		||||
					<div :class="$style.sub"></div>
 | 
			
		||||
					<div :class="$style.sub">{{ i18n.tsx.fromX({ x: instanceName }) }}</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<a :href="url" :class="$style.instanceIconLink" target="_blank" rel="noopener noreferrer">
 | 
			
		||||
					<img
 | 
			
		||||
@@ -48,7 +48,7 @@ import type { Paging } from '@/components/MkPagination.vue';
 | 
			
		||||
import { misskeyApi } from '@/scripts/misskey-api.js';
 | 
			
		||||
import { i18n } from '@/i18n.js';
 | 
			
		||||
import { instance } from '@/instance.js';
 | 
			
		||||
import { url } from '@/config.js';
 | 
			
		||||
import { url, instanceName } from '@/config.js';
 | 
			
		||||
 | 
			
		||||
const props = defineProps<{
 | 
			
		||||
	username: string;
 | 
			
		||||
@@ -101,6 +101,7 @@ misskeyApi('users/show', {
 | 
			
		||||
 | 
			
		||||
	.headerTitle {
 | 
			
		||||
		font-weight: 700;
 | 
			
		||||
		line-height: 1.1;
 | 
			
		||||
 | 
			
		||||
		.sub {
 | 
			
		||||
			font-size: 0.8em;
 | 
			
		||||
@@ -112,6 +113,7 @@ misskeyApi('users/show', {
 | 
			
		||||
	.instanceIconLink {
 | 
			
		||||
		display: block;
 | 
			
		||||
		margin-left: auto;
 | 
			
		||||
		height: 24px;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.instanceIcon {
 | 
			
		||||
 
 | 
			
		||||
@@ -71,24 +71,14 @@ const maxHeight = ref(params.get('maxHeight') ? parseInt(params.get('maxHeight')
 | 
			
		||||
//#region Embed Resizer
 | 
			
		||||
const rootEl = shallowRef<HTMLElement | null>(null);
 | 
			
		||||
 | 
			
		||||
let resizeMessageThrottleTimer: number | null = null;
 | 
			
		||||
let resizeMessageThrottleFlag = false;
 | 
			
		||||
let previousHeight = 0;
 | 
			
		||||
const resizeObserver = new ResizeObserver(async () => {
 | 
			
		||||
	const height = rootEl.value!.scrollHeight + 2; // border 上下1px
 | 
			
		||||
	if (resizeMessageThrottleFlag && Math.abs(previousHeight - height) < 30) return; // プラマイ30px未満の変化は無視
 | 
			
		||||
	if (resizeMessageThrottleTimer) window.clearTimeout(resizeMessageThrottleTimer);
 | 
			
		||||
 | 
			
		||||
	if (Math.abs(previousHeight - height) < 1) return; // 1px未満の変化は無視
 | 
			
		||||
	postMessageToParentWindow('misskey:embed:changeHeight', {
 | 
			
		||||
		height: (maxHeight.value > 0 && height > maxHeight.value) ? maxHeight.value : height,
 | 
			
		||||
	});
 | 
			
		||||
	previousHeight = height;
 | 
			
		||||
 | 
			
		||||
	resizeMessageThrottleFlag = true;
 | 
			
		||||
 | 
			
		||||
	resizeMessageThrottleTimer = window.setTimeout(() => {
 | 
			
		||||
		resizeMessageThrottleFlag = false; // 収縮をやりすぎるとチカチカする
 | 
			
		||||
	}, 500);
 | 
			
		||||
});
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
	resizeObserver.observe(rootEl.value!);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user