mediaまわりの修正
This commit is contained in:
parent
87c75af182
commit
1c35bf32bb
|
@ -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!);
|
||||
|
|
Loading…
Reference in New Issue