enhance(frontend): ユーザーページに「ファイル」タブを新設 (#15130)
* 投稿したファイルの一覧をプロフィールページ内のタブで見れるようにしてみた (Otaku-Social#14) * ギャラリー(ノート)の取得方法を変更、ページネーションに対応 * ギャラリー(ノート)が動作しない問題を修正 * ギャラリー(ノート)の名称変更 * styles * GalleryFromPosts -> Files * fix * enhance: 既存のファイルコンテナの「もっと見る」をクリックしたらファイルタブに飛べるように * Update Changelog * 共通化 * spdx * その他のメディアがちゃんとプレビューされるように * fix(frontend): リストがセンシティブ設定を考慮するように * arrayをsetに変更 * remove unused imports * 🎨 * 🎨 * 画像以外のファイルのプレビューに対応したのでコメントを削除 * サムネイルをMkDriveFileThumbnailに統一 * v-panelに置き換え * lint --------- Co-authored-by: tmorio <morikapusan@morikapu-denki.com> Co-authored-by: tmorio <20278135+tmorio@users.noreply.github.com> Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
@@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
>
|
||||
<div v-show="showBody" ref="contentEl" :class="[$style.content, { [$style.omitted]: omitted }]">
|
||||
<slot></slot>
|
||||
<button v-if="omitted" :class="$style.fade" class="_button" @click="() => { ignoreOmit = true; omitted = false; }">
|
||||
<button v-if="omitted" :class="$style.fade" class="_button" @click="showMore">
|
||||
<span :class="$style.fadeLabel">{{ i18n.ts.showMore }}</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -48,6 +48,7 @@ const props = withDefaults(defineProps<{
|
||||
thin?: boolean;
|
||||
naked?: boolean;
|
||||
foldable?: boolean;
|
||||
onUnfold?: () => boolean; // return false to prevent unfolding
|
||||
scrollable?: boolean;
|
||||
expanded?: boolean;
|
||||
maxHeight?: number | null;
|
||||
@@ -101,6 +102,13 @@ const omitObserver = new ResizeObserver((entries, observer) => {
|
||||
calcOmit();
|
||||
});
|
||||
|
||||
function showMore() {
|
||||
if (props.onUnfold && !props.onUnfold()) return;
|
||||
|
||||
ignoreOmit.value = true;
|
||||
omitted.value = false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
watch(showBody, v => {
|
||||
if (!rootEl.value) return;
|
||||
|
@@ -5,13 +5,21 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="thumbnail"
|
||||
:class="[
|
||||
$style.root,
|
||||
{ [$style.sensitiveHighlight]: highlightWhenSensitive && file.isSensitive },
|
||||
]"
|
||||
v-panel
|
||||
:class="[$style.root, {
|
||||
[$style.sensitiveHighlight]: highlightWhenSensitive && file.isSensitive,
|
||||
[$style.large]: large,
|
||||
}]"
|
||||
>
|
||||
<ImgWithBlurhash v-if="isThumbnailAvailable" :hash="file.blurhash" :src="file.thumbnailUrl" :alt="file.name" :title="file.name" :cover="fit !== 'contain'"/>
|
||||
<ImgWithBlurhash
|
||||
v-if="isThumbnailAvailable"
|
||||
:hash="file.blurhash"
|
||||
:src="file.thumbnailUrl"
|
||||
:alt="file.name"
|
||||
:title="file.name"
|
||||
:cover="fit !== 'contain'"
|
||||
:forceBlurHash="forceBlurhash"
|
||||
/>
|
||||
<i v-else-if="is === 'image'" class="ti ti-photo" :class="$style.icon"></i>
|
||||
<i v-else-if="is === 'video'" class="ti ti-video" :class="$style.icon"></i>
|
||||
<i v-else-if="is === 'audio' || is === 'midi'" class="ti ti-file-music" :class="$style.icon"></i>
|
||||
@@ -34,6 +42,8 @@ const props = defineProps<{
|
||||
file: Misskey.entities.DriveFile;
|
||||
fit: 'cover' | 'contain';
|
||||
highlightWhenSensitive?: boolean;
|
||||
forceBlurhash?: boolean;
|
||||
large?: boolean;
|
||||
}>();
|
||||
|
||||
const is = computed(() => {
|
||||
@@ -60,7 +70,7 @@ const is = computed(() => {
|
||||
|
||||
const isThumbnailAvailable = computed(() => {
|
||||
return props.file.thumbnailUrl
|
||||
? (is.value === 'image' as const || is.value === 'video')
|
||||
? (is.value === 'image' || is.value === 'video')
|
||||
: false;
|
||||
});
|
||||
</script>
|
||||
@@ -101,4 +111,8 @@ const isThumbnailAvailable = computed(() => {
|
||||
font-size: 32px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.large .icon {
|
||||
font-size: 40px;
|
||||
}
|
||||
</style>
|
||||
|
99
packages/frontend/src/components/MkNoteMediaGrid.vue
Normal file
99
packages/frontend/src/components/MkNoteMediaGrid.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<template v-for="file in note.files">
|
||||
<div
|
||||
v-if="(defaultStore.state.nsfw === 'force' || file.isSensitive) && defaultStore.state.nsfw !== 'ignore' && !showingFiles.has(file.id)"
|
||||
:class="[$style.filePreview, { [$style.square]: square }]"
|
||||
@click="showingFiles.add(file.id)"
|
||||
>
|
||||
<MkDriveFileThumbnail
|
||||
:file="file"
|
||||
fit="cover"
|
||||
:highlightWhenSensitive="defaultStore.state.highlightSensitiveMedia"
|
||||
:forceBlurhash="true"
|
||||
:large="true"
|
||||
:class="$style.file"
|
||||
/>
|
||||
<div :class="$style.sensitive">
|
||||
<div>
|
||||
<div><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}</div>
|
||||
<div>{{ i18n.ts.clickToShow }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<MkA v-else :class="[$style.filePreview, { [$style.square]: square }]" :to="notePage(note)">
|
||||
<MkDriveFileThumbnail
|
||||
:file="file"
|
||||
fit="cover"
|
||||
:highlightWhenSensitive="defaultStore.state.highlightSensitiveMedia"
|
||||
:large="true"
|
||||
:class="$style.file"
|
||||
/>
|
||||
</MkA>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { notePage } from '@/filters/note.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
||||
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
||||
|
||||
defineProps<{
|
||||
note: Misskey.entities.Note;
|
||||
square?: boolean;
|
||||
}>();
|
||||
|
||||
const showingFiles = ref<Set<string>>(new Set());
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.square {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.filePreview {
|
||||
position: relative;
|
||||
height: 128px;
|
||||
border-radius: calc(var(--MI-radius) / 2);
|
||||
overflow: clip;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.square {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.file {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: calc(var(--MI-radius) / 2);
|
||||
}
|
||||
|
||||
.sensitive {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-size: 0.8em;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(5px);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user