mediaまわりの修正

This commit is contained in:
kakkokari-gtyih 2024-06-03 19:05:17 +09:00
parent 87c75af182
commit 1c35bf32bb
11 changed files with 60 additions and 25 deletions

4
locales/index.d.ts vendored
View File

@ -4984,6 +4984,10 @@ export interface Locale extends ILocale {
*
*/
"inquiry": string;
/**
* {x}
*/
"fromX": ParameterizedString<"x">;
"_delivery": {
/**
*

View File

@ -1242,6 +1242,7 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ
noDescription: "説明文はありません"
alwaysConfirmFollow: "フォローの際常に確認する"
inquiry: "お問い合わせ"
fromX: "{x}から"
_delivery:
status: "配信状態"

View File

@ -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;'
}"
>

View File

@ -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) {

View File

@ -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;

View File

@ -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 {

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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!);