diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index 944c76d7dc..c52fa2299c 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -1,7 +1,7 @@ <template> -<div :class="[$style.root, { [$style.cover]: cover }]" :title="title"> - <canvas v-if="!loaded" ref="canvas" :class="$style.canvas" :width="size" :height="size" :title="title"/> - <img v-if="src" :class="$style.img" :src="src" :title="title" :alt="alt" @load="onLoad"/> +<div :class="[$style.root, { [$style.cover]: cover }]" :title="title ?? ''"> + <canvas v-if="!loaded" ref="canvas" :class="$style.canvas" :width="width" :height="height" :title="title ?? ''"/> + <img v-if="src" v-show="loaded" :class="$style.img" :src="src" :title="title ?? ''" :alt="alt ?? ''" @load="onLoad"/> </div> </template> @@ -12,15 +12,17 @@ import { decode } from 'blurhash'; const props = withDefaults(defineProps<{ src?: string | null; hash?: string; - alt?: string; + alt?: string | null; title?: string | null; - size?: number; + height?: number; + width?: number; cover?: boolean; }>(), { src: null, alt: '', title: null, - size: 64, + height: 64, + width: 64, cover: true, }); @@ -29,9 +31,9 @@ let loaded = $ref(false); function draw() { if (props.hash == null) return; - const pixels = decode(props.hash, props.size, props.size); + const pixels = decode(props.hash, props.width, props.height); const ctx = canvas.getContext('2d'); - const imageData = ctx!.createImageData(props.size, props.size); + const imageData = ctx!.createImageData(props.width, props.height); imageData.data.set(pixels); ctx!.putImageData(imageData, 0, 0); } @@ -52,6 +54,7 @@ onMounted(() => { height: 100%; &.cover { + > .canvas, > .img { object-fit: cover; } @@ -66,8 +69,7 @@ onMounted(() => { } .canvas { - position: absolute; - object-fit: cover; + object-fit: contain; } .img { diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index a4065dcd07..14a17eee70 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -1,6 +1,6 @@ <template> <div v-if="hide" :class="$style.hidden" @click="hide = false"> - <ImgWithBlurhash style="filter: brightness(0.5);" :hash="image.blurhash" :title="image.comment" :alt="image.comment"/> + <ImgWithBlurhash style="filter: brightness(0.5);" :hash="image.blurhash" :title="image.comment" :alt="image.comment" :width="width" :height="height"/> <div :class="$style.hiddenText"> <div :class="$style.hiddenTextWrapper"> <b style="display: block;"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.sensitive }}</b> @@ -14,7 +14,7 @@ :href="image.url" :title="image.name" > - <ImgWithBlurhash :hash="image.blurhash" :src="url" :alt="image.comment || image.name" :title="image.comment || image.name" :cover="false"/> + <ImgWithBlurhash :hash="image.blurhash" :src="url" :alt="image.comment || image.name" :title="image.comment || image.name" :width="width" :height="height" :cover="false"/> </a> <div :class="$style.indicators"> <div v-if="['image/gif', 'image/apng'].includes(image.type)" :class="$style.indicator">GIF</div> @@ -39,16 +39,30 @@ const props = defineProps<{ let hide = $ref(true); let darkMode = $ref(defaultStore.state.darkMode); +let width = $ref(64); +let height = $ref(64); -const url = (props.raw || defaultStore.state.loadRawImages) +const url = $computed(() => (props.raw || defaultStore.state.loadRawImages) ? props.image.url : defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(props.image.url) - : props.image.thumbnailUrl; + : props.image.thumbnailUrl +); // Plugin:register_note_view_interruptor を使って書き換えられる可能性があるためwatchする watch(() => props.image, () => { hide = (defaultStore.state.nsfw === 'force') ? true : props.image.isSensitive && (defaultStore.state.nsfw !== 'ignore'); + + if (props.image.properties.width && props.image.properties.height) { + const ratio = props.image.properties.width / props.image.properties.height; + if (ratio > 1) { + width = Math.round(64 * ratio); + height = 64; + } else { + width = 64; + height = Math.round(64 / ratio); + } + } }, { deep: true, immediate: true, diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue index d36cc2d26b..1e5307565e 100644 --- a/packages/frontend/src/components/MkMediaList.vue +++ b/packages/frontend/src/components/MkMediaList.vue @@ -4,8 +4,8 @@ <div v-if="mediaList.filter(media => previewable(media)).length > 0" :class="$style.container"> <div ref="gallery" :class="[$style.medias, count <= 4 ? $style['n' + count] : $style.nMany]"> <template v-for="media in mediaList.filter(media => previewable(media))"> - <XVideo v-if="media.type.startsWith('video')" :key="media.id" :class="$style.media" :video="media"/> - <XImage v-else-if="media.type.startsWith('image')" :key="media.id" :class="$style.media" class="image" :data-id="media.id" :image="media" :raw="raw"/> + <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> </div> @@ -155,12 +155,11 @@ const previewable = (file: misskey.entities.DriveFile): boolean => { display: grid; grid-gap: 8px; - // for webkit height: 100%; &.n1 { - aspect-ratio: 16/9; grid-template-rows: 1fr; + max-height: min(max(calc(var(--containerHeight, 100svh) * 0.5), 130px), 50svh); } &.n2 {