mediaまわりの修正
This commit is contained in:
		
							
								
								
									
										4
									
								
								locales/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								locales/index.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4984,6 +4984,10 @@ export interface Locale extends ILocale { | ||||
|      * お問い合わせ | ||||
|      */ | ||||
|     "inquiry": string; | ||||
|     /** | ||||
|      * {x}から | ||||
|      */ | ||||
|     "fromX": ParameterizedString<"x">; | ||||
|     "_delivery": { | ||||
|         /** | ||||
|          * 配信状態 | ||||
|   | ||||
| @@ -1242,6 +1242,7 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ | ||||
| noDescription: "説明文はありません" | ||||
| alwaysConfirmFollow: "フォローの際常に確認する" | ||||
| inquiry: "お問い合わせ" | ||||
| fromX: "{x}から" | ||||
|  | ||||
| _delivery: | ||||
|   status: "配信状態" | ||||
|   | ||||
| @@ -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
	 kakkokari-gtyih
					kakkokari-gtyih