diff options
| author | Hazelnoot <acomputerdog@gmail.com> | 2025-02-03 14:31:26 -0500 |
|---|---|---|
| committer | Hazelnoot <acomputerdog@gmail.com> | 2025-02-03 14:36:09 -0500 |
| commit | a4e86758c1c53f4e623b6e8f613d4a6e34e96156 (patch) | |
| tree | d09bf325b7f52512a1fe2a9d35f1953d2b310309 /packages/frontend/src/pages/user | |
| parent | merge: Use package manager version from package.json (!883) (diff) | |
| parent | fix(build): corepackのバグの回避 (#15387) (diff) | |
| download | sharkey-a4e86758c1c53f4e623b6e8f613d4a6e34e96156.tar.gz sharkey-a4e86758c1c53f4e623b6e8f613d4a6e34e96156.tar.bz2 sharkey-a4e86758c1c53f4e623b6e8f613d4a6e34e96156.zip | |
merge upstream 2025-02-03
Diffstat (limited to 'packages/frontend/src/pages/user')
| -rw-r--r-- | packages/frontend/src/pages/user/files.vue | 56 | ||||
| -rw-r--r-- | packages/frontend/src/pages/user/home.vue | 9 | ||||
| -rw-r--r-- | packages/frontend/src/pages/user/index.files.vue | 58 | ||||
| -rw-r--r-- | packages/frontend/src/pages/user/index.vue | 13 |
4 files changed, 88 insertions, 48 deletions
diff --git a/packages/frontend/src/pages/user/files.vue b/packages/frontend/src/pages/user/files.vue new file mode 100644 index 0000000000..b6c7c1c777 --- /dev/null +++ b/packages/frontend/src/pages/user/files.vue @@ -0,0 +1,56 @@ +<!-- +SPDX-FileCopyrightText: syuilo and misskey-project +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> + <MkSpacer :contentMax="1100"> + <div :class="$style.root"> + <MkPagination v-slot="{items}" :pagination="pagination"> + <div :class="$style.stream"> + <MkNoteMediaGrid v-for="note in items" :note="note" square/> + </div> + </MkPagination> + </div> + </MkSpacer> +</template> + +<script lang="ts" setup> +import { computed } from 'vue'; +import * as Misskey from 'misskey-js'; + +import MkNoteMediaGrid from '@/components/MkNoteMediaGrid.vue'; +import MkPagination from '@/components/MkPagination.vue'; + +const props = defineProps<{ + user: Misskey.entities.UserDetailed; +}>(); + +const pagination = { + endpoint: 'users/notes' as const, + limit: 15, + params: computed(() => ({ + userId: props.user.id, + withFiles: true, + })), +}; +</script> + +<style lang="scss" module> +.root { + padding: 8px; +} + +.stream { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); + gap: var(--MI-marginHalf); +} + +@media screen and (min-width: 600px) { + .stream { + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + } + +} +</style> diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index 5565555ca4..645c3b3c3c 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -138,7 +138,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkInfo v-if="user.pinnedNotes.length === 0 && $i?.id === user.id">{{ i18n.ts.userPagePinTip }}</MkInfo> <template v-if="narrow"> <MkLazy> - <XFiles :key="user.id" :user="user" :collapsed="true"/> + <XFiles :key="user.id" :user="user" :collapsed="true" @unfold="emit('unfoldFiles')"/> </MkLazy> <MkLazy> <XActivity :key="user.id" :user="user" :collapsed="true"/> @@ -180,7 +180,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </div> <div v-if="!narrow" class="sub _gaps" style="container-type: inline-size;"> - <XFiles :key="user.id" :user="user"/> + <XFiles :key="user.id" :user="user" @unfold="emit('unfoldFiles')"/> <XActivity :key="user.id" :user="user"/> <XListenBrainz v-if="user.listenbrainz && listenbrainzdata" :key="user.id" :user="user"/> </div> @@ -242,7 +242,6 @@ function calcAge(birthdate: string): number { const XFiles = defineAsyncComponent(() => import('./index.files.vue')); const XActivity = defineAsyncComponent(() => import('./index.activity.vue')); const XListenBrainz = defineAsyncComponent(() => import('./index.listenbrainz.vue')); -//const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue')); const props = withDefaults(defineProps<{ user: Misskey.entities.UserDetailed; @@ -252,6 +251,10 @@ const props = withDefaults(defineProps<{ disableNotes: false, }); +const emit = defineEmits<{ + (ev: 'unfoldFiles'): void; +}>(); + const router = useRouter(); const user = ref(props.user); diff --git a/packages/frontend/src/pages/user/index.files.vue b/packages/frontend/src/pages/user/index.files.vue index 7fe90da865..44e35e3479 100644 --- a/packages/frontend/src/pages/user/index.files.vue +++ b/packages/frontend/src/pages/user/index.files.vue @@ -4,30 +4,15 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<MkContainer :max-height="300" :foldable="true" :expanded="!collapsed"> +<MkContainer :max-height="300" :foldable="true" :expanded="!collapsed" :onUnfold="unfoldContainer"> <template #icon><i class="ti ti-photo"></i></template> <template #header>{{ i18n.ts.files }}</template> <div :class="$style.root"> <MkLoading v-if="fetching"/> - <div v-if="!fetching && files.length > 0" :class="$style.stream"> - <template v-for="file in files" :key="file.note.id + file.file.id"> - <div v-if="file.file.isSensitive && !showingFiles.includes(file.file.id)" :class="$style.img" @click="showingFiles.push(file.file.id)"> - <!-- TODO: 画像以外のファイルに対応 --> - <ImgWithBlurhash :class="$style.sensitiveImg" :hash="file.file.blurhash" :src="thumbnail(file.file)" :title="file.file.name" :forceBlurhash="true"/> - <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.img" :to="notePage(file.note)"> - <!-- TODO: 画像以外のファイルに対応 --> - <ImgWithBlurhash :hash="file.file.blurhash" :src="thumbnail(file.file)" :title="file.file.name"/> - </MkA> - </template> + <div v-if="!fetching && notes.length > 0" :class="$style.stream"> + <MkNoteMediaGrid v-for="note in notes" :note="note"/> </div> - <p v-if="!fetching && files.length == 0" :class="$style.empty">{{ i18n.ts.nothing }}</p> + <p v-if="!fetching && notes.length == 0" :class="$style.empty">{{ i18n.ts.nothing }}</p> </div> </MkContainer> </template> @@ -35,13 +20,10 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onMounted, ref } from 'vue'; import * as Misskey from 'misskey-js'; -import { getStaticImageUrl } from '@/scripts/media-proxy.js'; -import { notePage } from '@/filters/note.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import MkContainer from '@/components/MkContainer.vue'; -import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue'; -import { defaultStore } from '@/store.js'; import { i18n } from '@/i18n.js'; +import MkNoteMediaGrid from '@/components/MkNoteMediaGrid.vue'; const props = withDefaults(defineProps<{ user: Misskey.entities.UserDetailed; @@ -50,33 +32,25 @@ const props = withDefaults(defineProps<{ collapsed: false, }); +const emit = defineEmits<{ + (ev: 'unfold'): void; +}>(); + const fetching = ref(true); -const files = ref<{ - note: Misskey.entities.Note; - file: Misskey.entities.DriveFile; -}[]>([]); -const showingFiles = ref<string[]>([]); +const notes = ref<Misskey.entities.Note[]>([]); -function thumbnail(image: Misskey.entities.DriveFile): string { - return defaultStore.state.disableShowingAnimatedImages - ? getStaticImageUrl(image.url) - : image.thumbnailUrl; +function unfoldContainer(): boolean { + emit('unfold'); + return false; } onMounted(() => { misskeyApi('users/notes', { userId: props.user.id, withFiles: true, - limit: 15, - }).then(notes => { - for (const note of notes) { - for (const file of note.files) { - files.value.push({ - note, - file, - }); - } - } + limit: 10, + }).then(_notes => { + notes.value = _notes; fetching.value = false; }); }); diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue index a35250bf5f..ba02559d68 100644 --- a/packages/frontend/src/pages/user/index.vue +++ b/packages/frontend/src/pages/user/index.vue @@ -9,10 +9,11 @@ SPDX-License-Identifier: AGPL-3.0-only <div> <div v-if="user"> <MkHorizontalSwipe v-model:tab="tab" :tabs="headerTabs"> - <XHome v-if="tab === 'home'" key="home" :user="user"/> + <XHome v-if="tab === 'home'" key="home" :user="user" @unfoldFiles="() => { tab = 'files'; }"/> <MkSpacer v-else-if="tab === 'notes'" key="notes" :contentMax="800" style="padding-top: 0"> <XTimeline :user="user"/> </MkSpacer> + <XFiles v-else-if="tab === 'files'" :user="user"/> <XActivity v-else-if="tab === 'activity'" key="activity" :user="user"/> <XAchievements v-else-if="tab === 'achievements'" key="achievements" :user="user"/> <XReactions v-else-if="tab === 'reactions'" key="reactions" :user="user"/> @@ -39,10 +40,11 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; -import { getServerContext } from '@/server-context.js'; +import { serverContext, assertServerContext } from '@/server-context.js'; const XHome = defineAsyncComponent(() => import('./home.vue')); const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue')); +const XFiles = defineAsyncComponent(() => import('./files.vue')); const XActivity = defineAsyncComponent(() => import('./activity.vue')); const XAchievements = defineAsyncComponent(() => import('./achievements.vue')); const XReactions = defineAsyncComponent(() => import('./reactions.vue')); @@ -53,7 +55,8 @@ const XFlashs = defineAsyncComponent(() => import('./flashs.vue')); const XGallery = defineAsyncComponent(() => import('./gallery.vue')); const XRaw = defineAsyncComponent(() => import('./raw.vue')); -const CTX_USER = getServerContext('user'); +// contextは非ログイン状態の情報しかないためログイン時は利用できない +const CTX_USER = !$i && assertServerContext(serverContext, 'user') ? serverContext.user : null; const props = withDefaults(defineProps<{ acct: string; @@ -103,6 +106,10 @@ const headerTabs = computed(() => user.value ? [{ title: i18n.ts.notes, icon: 'ti ti-pencil', }, { + key: 'files', + title: i18n.ts.files, + icon: 'ti ti-photo', +}, { key: 'activity', title: i18n.ts.activity, icon: 'ti ti-chart-line', |