diff options
| author | syuilo <4439005+syuilo@users.noreply.github.com> | 2025-05-09 17:40:08 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-09 17:40:08 +0900 |
| commit | 8c2ab25e5f2040fcbc81bc2a02a279fed40e1c11 (patch) | |
| tree | ae0d3573bd5a3175bc6174d33129dc64205a1436 /packages/frontend/src/pages/user | |
| parent | refactor (diff) | |
| download | misskey-8c2ab25e5f2040fcbc81bc2a02a279fed40e1c11.tar.gz misskey-8c2ab25e5f2040fcbc81bc2a02a279fed40e1c11.tar.bz2 misskey-8c2ab25e5f2040fcbc81bc2a02a279fed40e1c11.zip | |
Feat: No websocket mode (#15851)
* wip
* wip
* wip
* wip
* Update MkTimeline.vue
* wip
* wip
* wip
* Update MkTimeline.vue
* Update use-pagination.ts
* wip
* wip
* Update MkTimeline.vue
* Update MkTimeline.vue
* wip
* wip
* Update MkTimeline.vue
* Update MkTimeline.vue
* Update MkTimeline.vue
* wip
* Update use-pagination.ts
* wip
* Update use-pagination.ts
* Update MkNotifications.vue
* Update MkNotifications.vue
* wip
* wip
* wip
* Update use-note-capture.ts
* Update use-note-capture.ts
* Update use-note-capture.ts
* wip
* wip
* wip
* wip
* Update MkNoteDetailed.vue
* wip
* wip
* Update MkTimeline.vue
* wip
* fix
* Update MkTimeline.vue
* wip
* test
* Revert "test"
This reverts commit 3375619396c54dcda5e564eb1da444c2391208c9.
* Update use-pagination.ts
* test
* Revert "test"
This reverts commit 42c53c830e28485d2fb49061fa7cdeee31bc6a22.
* test
* Revert "test"
This reverts commit c4f8cda4aa1cec9d1eb97557145f3ad3d2d0e469.
* Update style.scss
* Update MkTimeline.vue
* Update MkTimeline.vue
* Update MkTimeline.vue
* ✌️
* Update MkTimeline.vue
* wip
* wip
* test
* Update MkPullToRefresh.vue
* Update MkPullToRefresh.vue
* Update MkPullToRefresh.vue
* Update MkPullToRefresh.vue
* Update MkTimeline.vue
* wip
* tweak navbar
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* Update home.vue
* wip
* refactor
* wip
* wip
* Update note.vue
* Update navbar.vue
* Update MkPullToRefresh.vue
* Update MkPullToRefresh.vue
* Update MkPullToRefresh.vue
* wip
* Update MkStreamingNotificationsTimeline.vue
* Update use-pagination.ts
* wip
* improve perf
* wip
* Update MkNotesTimeline.vue
* wip
* megre
* Update use-pagination.ts
* Update use-pagination.ts
* Update MkStreamingNotesTimeline.vue
* Update use-pagination.ts
* Update CHANGELOG.md
* Update CHANGELOG.md
* Update CHANGELOG.md
Diffstat (limited to 'packages/frontend/src/pages/user')
| -rw-r--r-- | packages/frontend/src/pages/user/files.vue | 16 | ||||
| -rw-r--r-- | packages/frontend/src/pages/user/home.vue | 269 | ||||
| -rw-r--r-- | packages/frontend/src/pages/user/index.timeline.vue | 8 | ||||
| -rw-r--r-- | packages/frontend/src/pages/user/index.vue | 6 | ||||
| -rw-r--r-- | packages/frontend/src/pages/user/notes.vue | 67 |
5 files changed, 219 insertions, 147 deletions
diff --git a/packages/frontend/src/pages/user/files.vue b/packages/frontend/src/pages/user/files.vue index 91ebcad0b2..51ae809aac 100644 --- a/packages/frontend/src/pages/user/files.vue +++ b/packages/frontend/src/pages/user/files.vue @@ -4,15 +4,15 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> - <div class="_spacer" style="--MI_SPACER-w: 1100px;"> - <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> +<div class="_spacer" style="--MI_SPACER-w: 1100px;"> + <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> +</div> </template> <script lang="ts" setup> diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index 50bb1de24f..23f740ddd0 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -4,158 +4,160 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<div class="_spacer" :style="{ '--MI_SPACER-w': narrow ? '800px' : '1100px' }"> - <div ref="rootEl" class="ftskorzw" :class="{ wide: !narrow }" style="container-type: inline-size;"> - <div class="main _gaps"> - <!-- TODO --> - <!-- <div class="punished" v-if="user.isSuspended"><i class="ti ti-alert-triangle" style="margin-right: 8px;"></i> {{ i18n.ts.userSuspended }}</div> --> - <!-- <div class="punished" v-if="user.isSilenced"><i class="ti ti-alert-triangle" style="margin-right: 8px;"></i> {{ i18n.ts.userSilenced }}</div> --> +<component :is="prefer.s.enablePullToRefresh ? MkPullToRefresh : 'div'" :refresher="() => reload()"> + <div class="_spacer" :style="{ '--MI_SPACER-w': narrow ? '800px' : '1100px' }"> + <div ref="rootEl" class="ftskorzw" :class="{ wide: !narrow }" style="container-type: inline-size;"> + <div class="main _gaps"> + <!-- TODO --> + <!-- <div class="punished" v-if="user.isSuspended"><i class="ti ti-alert-triangle" style="margin-right: 8px;"></i> {{ i18n.ts.userSuspended }}</div> --> + <!-- <div class="punished" v-if="user.isSilenced"><i class="ti ti-alert-triangle" style="margin-right: 8px;"></i> {{ i18n.ts.userSilenced }}</div> --> - <div class="profile _gaps"> - <MkAccountMoved v-if="user.movedTo" :movedTo="user.movedTo"/> - <MkRemoteCaution v-if="user.host != null" :href="user.url ?? user.uri!"/> - <MkInfo v-if="user.host == null && user.username.includes('.')">{{ i18n.ts.isSystemAccount }}</MkInfo> + <div class="profile _gaps"> + <MkAccountMoved v-if="user.movedTo" :movedTo="user.movedTo"/> + <MkRemoteCaution v-if="user.host != null" :href="user.url ?? user.uri!"/> + <MkInfo v-if="user.host == null && user.username.includes('.')">{{ i18n.ts.isSystemAccount }}</MkInfo> - <div :key="user.id" class="main _panel"> - <div class="banner-container" :style="style"> - <div ref="bannerEl" class="banner" :style="style"></div> - <div class="fade"></div> + <div :key="user.id" class="main _panel"> + <div class="banner-container" :style="style"> + <div ref="bannerEl" class="banner" :style="style"></div> + <div class="fade"></div> + <div class="title"> + <MkUserName class="name" :user="user" :nowrap="true"/> + <div class="bottom"> + <span class="username"><MkAcct :user="user" :detail="true"/></span> + <span v-if="user.isAdmin" :title="i18n.ts.isAdmin" style="color: var(--MI_THEME-badge);"><i class="ti ti-shield"></i></span> + <span v-if="user.isLocked" :title="i18n.ts.isLocked"><i class="ti ti-lock"></i></span> + <span v-if="user.isBot" :title="i18n.ts.isBot"><i class="ti ti-robot"></i></span> + <button v-if="$i && !isEditingMemo && !memoDraft" class="_button add-note-button" @click="showMemoTextarea"> + <i class="ti ti-edit"/> {{ i18n.ts.addMemo }} + </button> + </div> + </div> + <span v-if="$i && $i.id != user.id && user.isFollowed" class="followed">{{ i18n.ts.followsYou }}</span> + <div class="actions"> + <button class="menu _button" @click="menu"><i class="ti ti-dots"></i></button> + <MkFollowButton v-if="$i?.id != user.id" v-model:user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/> + </div> + </div> + <MkAvatar class="avatar" :user="user" indicator/> <div class="title"> - <MkUserName class="name" :user="user" :nowrap="true"/> + <MkUserName :user="user" :nowrap="false" class="name"/> <div class="bottom"> <span class="username"><MkAcct :user="user" :detail="true"/></span> <span v-if="user.isAdmin" :title="i18n.ts.isAdmin" style="color: var(--MI_THEME-badge);"><i class="ti ti-shield"></i></span> <span v-if="user.isLocked" :title="i18n.ts.isLocked"><i class="ti ti-lock"></i></span> <span v-if="user.isBot" :title="i18n.ts.isBot"><i class="ti ti-robot"></i></span> - <button v-if="$i && !isEditingMemo && !memoDraft" class="_button add-note-button" @click="showMemoTextarea"> - <i class="ti ti-edit"/> {{ i18n.ts.addMemo }} - </button> </div> </div> - <span v-if="$i && $i.id != user.id && user.isFollowed" class="followed">{{ i18n.ts.followsYou }}</span> - <div class="actions"> - <button class="menu _button" @click="menu"><i class="ti ti-dots"></i></button> - <MkFollowButton v-if="$i?.id != user.id" v-model:user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/> + <div v-if="user.followedMessage != null" class="followedMessage"> + <MkFukidashi class="fukidashi" :tail="narrow ? 'none' : 'left'" negativeMargin> + <div class="messageHeader">{{ i18n.ts.messageToFollower }}</div> + <div><MkSparkle><Mfm :plain="true" :text="user.followedMessage" :author="user" class="_selectable"/></MkSparkle></div> + </MkFukidashi> </div> - </div> - <MkAvatar class="avatar" :user="user" indicator/> - <div class="title"> - <MkUserName :user="user" :nowrap="false" class="name"/> - <div class="bottom"> - <span class="username"><MkAcct :user="user" :detail="true"/></span> - <span v-if="user.isAdmin" :title="i18n.ts.isAdmin" style="color: var(--MI_THEME-badge);"><i class="ti ti-shield"></i></span> - <span v-if="user.isLocked" :title="i18n.ts.isLocked"><i class="ti ti-lock"></i></span> - <span v-if="user.isBot" :title="i18n.ts.isBot"><i class="ti ti-robot"></i></span> + <div v-if="user.roles.length > 0" class="roles"> + <span v-for="role in user.roles" :key="role.id" v-tooltip="role.description" class="role" :style="{ '--color': role.color }"> + <MkA v-adaptive-bg :to="`/roles/${role.id}`"> + <img v-if="role.iconUrl" style="height: 1.3em; vertical-align: -22%;" :src="role.iconUrl"/> + {{ role.name }} + </MkA> + </span> </div> - </div> - <div v-if="user.followedMessage != null" class="followedMessage"> - <MkFukidashi class="fukidashi" :tail="narrow ? 'none' : 'left'" negativeMargin> - <div class="messageHeader">{{ i18n.ts.messageToFollower }}</div> - <div><MkSparkle><Mfm :plain="true" :text="user.followedMessage" :author="user" class="_selectable"/></MkSparkle></div> - </MkFukidashi> - </div> - <div v-if="user.roles.length > 0" class="roles"> - <span v-for="role in user.roles" :key="role.id" v-tooltip="role.description" class="role" :style="{ '--color': role.color }"> - <MkA v-adaptive-bg :to="`/roles/${role.id}`"> - <img v-if="role.iconUrl" style="height: 1.3em; vertical-align: -22%;" :src="role.iconUrl"/> - {{ role.name }} + <div v-if="iAmModerator" class="moderationNote"> + <MkTextarea v-if="editModerationNote || (moderationNote != null && moderationNote !== '')" v-model="moderationNote" manualSave> + <template #label>{{ i18n.ts.moderationNote }}</template> + <template #caption>{{ i18n.ts.moderationNoteDescription }}</template> + </MkTextarea> + <div v-else> + <MkButton small @click="editModerationNote = true">{{ i18n.ts.addModerationNote }}</MkButton> + </div> + </div> + <div v-if="isEditingMemo || memoDraft" class="memo" :class="{'no-memo': !memoDraft}"> + <div class="heading" v-text="i18n.ts.memo"/> + <textarea + ref="memoTextareaEl" + v-model="memoDraft" + rows="1" + @focus="isEditingMemo = true" + @blur="updateMemo" + @input="adjustMemoTextarea" + /> + </div> + <div class="description"> + <MkOmit> + <Mfm v-if="user.description" :text="user.description" :isNote="false" :author="user" class="_selectable"/> + <p v-else class="empty">{{ i18n.ts.noAccountDescription }}</p> + </MkOmit> + </div> + <div class="fields system"> + <dl v-if="user.location" class="field"> + <dt class="name"><i class="ti ti-map-pin ti-fw"></i> {{ i18n.ts.location }}</dt> + <dd class="value">{{ user.location }}</dd> + </dl> + <dl v-if="user.birthday" class="field"> + <dt class="name"><i class="ti ti-cake ti-fw"></i> {{ i18n.ts.birthday }}</dt> + <dd class="value">{{ user.birthday.replace('-', '/').replace('-', '/') }} ({{ i18n.tsx.yearsOld({ age }) }})</dd> + </dl> + <dl class="field"> + <dt class="name"><i class="ti ti-calendar ti-fw"></i> {{ i18n.ts.registeredDate }}</dt> + <dd class="value">{{ dateString(user.createdAt) }} (<MkTime :time="user.createdAt"/>)</dd> + </dl> + </div> + <div v-if="user.fields.length > 0" class="fields"> + <dl v-for="(field, i) in user.fields" :key="i" class="field"> + <dt class="name"> + <Mfm :text="field.name" :author="user" :plain="true" :colored="false" class="_selectable"/> + </dt> + <dd class="value"> + <Mfm :text="field.value" :author="user" :colored="false" class="_selectable"/> + <i v-if="user.verifiedLinks.includes(field.value)" v-tooltip:dialog="i18n.ts.verifiedLink" class="ti ti-circle-check" :class="$style.verifiedLink"></i> + </dd> + </dl> + </div> + <div class="status"> + <MkA :to="userPage(user)"> + <b>{{ number(user.notesCount) }}</b> + <span>{{ i18n.ts.notes }}</span> + </MkA> + <MkA v-if="isFollowingVisibleForMe(user)" :to="userPage(user, 'following')"> + <b>{{ number(user.followingCount) }}</b> + <span>{{ i18n.ts.following }}</span> + </MkA> + <MkA v-if="isFollowersVisibleForMe(user)" :to="userPage(user, 'followers')"> + <b>{{ number(user.followersCount) }}</b> + <span>{{ i18n.ts.followers }}</span> </MkA> - </span> - </div> - <div v-if="iAmModerator" class="moderationNote"> - <MkTextarea v-if="editModerationNote || (moderationNote != null && moderationNote !== '')" v-model="moderationNote" manualSave> - <template #label>{{ i18n.ts.moderationNote }}</template> - <template #caption>{{ i18n.ts.moderationNoteDescription }}</template> - </MkTextarea> - <div v-else> - <MkButton small @click="editModerationNote = true">{{ i18n.ts.addModerationNote }}</MkButton> </div> </div> - <div v-if="isEditingMemo || memoDraft" class="memo" :class="{'no-memo': !memoDraft}"> - <div class="heading" v-text="i18n.ts.memo"/> - <textarea - ref="memoTextareaEl" - v-model="memoDraft" - rows="1" - @focus="isEditingMemo = true" - @blur="updateMemo" - @input="adjustMemoTextarea" - /> - </div> - <div class="description"> - <MkOmit> - <Mfm v-if="user.description" :text="user.description" :isNote="false" :author="user" class="_selectable"/> - <p v-else class="empty">{{ i18n.ts.noAccountDescription }}</p> - </MkOmit> - </div> - <div class="fields system"> - <dl v-if="user.location" class="field"> - <dt class="name"><i class="ti ti-map-pin ti-fw"></i> {{ i18n.ts.location }}</dt> - <dd class="value">{{ user.location }}</dd> - </dl> - <dl v-if="user.birthday" class="field"> - <dt class="name"><i class="ti ti-cake ti-fw"></i> {{ i18n.ts.birthday }}</dt> - <dd class="value">{{ user.birthday.replace('-', '/').replace('-', '/') }} ({{ i18n.tsx.yearsOld({ age }) }})</dd> - </dl> - <dl class="field"> - <dt class="name"><i class="ti ti-calendar ti-fw"></i> {{ i18n.ts.registeredDate }}</dt> - <dd class="value">{{ dateString(user.createdAt) }} (<MkTime :time="user.createdAt"/>)</dd> - </dl> - </div> - <div v-if="user.fields.length > 0" class="fields"> - <dl v-for="(field, i) in user.fields" :key="i" class="field"> - <dt class="name"> - <Mfm :text="field.name" :author="user" :plain="true" :colored="false" class="_selectable"/> - </dt> - <dd class="value"> - <Mfm :text="field.value" :author="user" :colored="false" class="_selectable"/> - <i v-if="user.verifiedLinks.includes(field.value)" v-tooltip:dialog="i18n.ts.verifiedLink" class="ti ti-circle-check" :class="$style.verifiedLink"></i> - </dd> - </dl> + </div> + + <div class="contents _gaps"> + <div v-if="user.pinnedNotes.length > 0" class="_gaps"> + <MkNote v-for="note in user.pinnedNotes" :key="note.id" class="note _panel" :note="note" :pinned="true"/> </div> - <div class="status"> - <MkA :to="userPage(user)"> - <b>{{ number(user.notesCount) }}</b> - <span>{{ i18n.ts.notes }}</span> - </MkA> - <MkA v-if="isFollowingVisibleForMe(user)" :to="userPage(user, 'following')"> - <b>{{ number(user.followingCount) }}</b> - <span>{{ i18n.ts.following }}</span> - </MkA> - <MkA v-if="isFollowersVisibleForMe(user)" :to="userPage(user, 'followers')"> - <b>{{ number(user.followersCount) }}</b> - <span>{{ i18n.ts.followers }}</span> - </MkA> + <MkInfo v-else-if="$i && $i.id === user.id">{{ i18n.ts.userPagePinTip }}</MkInfo> + <template v-if="narrow"> + <MkLazy> + <XFiles :key="user.id" :user="user" @unfold="emit('unfoldFiles')"/> + </MkLazy> + <MkLazy> + <XActivity :key="user.id" :user="user"/> + </MkLazy> + </template> + <div v-if="!disableNotes"> + <MkLazy> + <XTimeline :user="user"/> + </MkLazy> </div> </div> </div> - - <div class="contents _gaps"> - <div v-if="user.pinnedNotes.length > 0" class="_gaps"> - <MkNote v-for="note in user.pinnedNotes" :key="note.id" class="note _panel" :note="note" :pinned="true"/> - </div> - <MkInfo v-else-if="$i && $i.id === user.id">{{ i18n.ts.userPagePinTip }}</MkInfo> - <template v-if="narrow"> - <MkLazy> - <XFiles :key="user.id" :user="user" @unfold="emit('unfoldFiles')"/> - </MkLazy> - <MkLazy> - <XActivity :key="user.id" :user="user"/> - </MkLazy> - </template> - <div v-if="!disableNotes"> - <MkLazy> - <XTimeline :user="user"/> - </MkLazy> - </div> + <div v-if="!narrow" class="sub _gaps" style="container-type: inline-size;"> + <XFiles :key="user.id" :user="user" @unfold="emit('unfoldFiles')"/> + <XActivity :key="user.id" :user="user"/> </div> </div> - <div v-if="!narrow" class="sub _gaps" style="container-type: inline-size;"> - <XFiles :key="user.id" :user="user" @unfold="emit('unfoldFiles')"/> - <XActivity :key="user.id" :user="user"/> - </div> </div> -</div> +</component> </template> <script lang="ts" setup> @@ -185,6 +187,7 @@ import { useRouter } from '@/router.js'; import { getStaticImageUrl } from '@/utility/media-proxy.js'; import MkSparkle from '@/components/MkSparkle.vue'; import { prefer } from '@/preferences.js'; +import MkPullToRefresh from '@/components/MkPullToRefresh.vue'; function calcAge(birthdate: string): number { const date = new Date(birthdate); @@ -207,7 +210,7 @@ const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue')); const props = withDefaults(defineProps<{ user: Misskey.entities.UserDetailed; - /** Test only; MkNotes currently causes problems in vitest */ + /** Test only; MkNotesTimeline currently causes problems in vitest */ disableNotes: boolean; }>(), { disableNotes: false, @@ -299,6 +302,10 @@ watch([props.user], () => { memoDraft.value = props.user.memo; }); +async function reload() { + // TODO +} + onMounted(() => { window.requestAnimationFrame(parallaxLoop); narrow.value = rootEl.value!.clientWidth < 1000; diff --git a/packages/frontend/src/pages/user/index.timeline.vue b/packages/frontend/src/pages/user/index.timeline.vue index 49d015a530..d8eca07a42 100644 --- a/packages/frontend/src/pages/user/index.timeline.vue +++ b/packages/frontend/src/pages/user/index.timeline.vue @@ -8,19 +8,19 @@ SPDX-License-Identifier: AGPL-3.0-only <template #header> <MkTab v-model="tab" :class="$style.tab"> <option value="featured">{{ i18n.ts.featured }}</option> - <option :value="null">{{ i18n.ts.notes }}</option> + <option value="notes">{{ i18n.ts.notes }}</option> <option value="all">{{ i18n.ts.all }}</option> <option value="files">{{ i18n.ts.withFiles }}</option> </MkTab> </template> - <MkNotes :noGap="true" :pagination="pagination" :class="$style.tl"/> + <MkNotesTimeline :key="tab" :noGap="true" :pagination="pagination" :pullToRefresh="false" :class="$style.tl"/> </MkStickyContainer> </template> <script lang="ts" setup> import { ref, computed } from 'vue'; import * as Misskey from 'misskey-js'; -import MkNotes from '@/components/MkNotes.vue'; +import MkNotesTimeline from '@/components/MkNotesTimeline.vue'; import MkTab from '@/components/MkTab.vue'; import { i18n } from '@/i18n.js'; @@ -28,7 +28,7 @@ const props = defineProps<{ user: Misskey.entities.UserDetailed; }>(); -const tab = ref<string | null>('all'); +const tab = ref<string>('all'); const pagination = computed(() => tab.value === 'featured' ? { endpoint: 'users/featured-notes' as const, diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue index d6e477d0ae..d4f36271ad 100644 --- a/packages/frontend/src/pages/user/index.vue +++ b/packages/frontend/src/pages/user/index.vue @@ -7,9 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only <PageWithHeader v-model:tab="tab" :tabs="headerTabs" :actions="headerActions" :swipable="true"> <div v-if="user"> <XHome v-if="tab === 'home'" :user="user" @unfoldFiles="() => { tab = 'files'; }"/> - <div v-else-if="tab === 'notes'" class="_spacer" style="--MI_SPACER-w: 800px;"> - <XTimeline :user="user"/> - </div> + <XNotes v-else-if="tab === 'notes'" :user="user"/> <XFiles v-else-if="tab === 'files'" :user="user"/> <XActivity v-else-if="tab === 'activity'" :user="user"/> <XAchievements v-else-if="tab === 'achievements'" :user="user"/> @@ -37,7 +35,7 @@ import { $i } from '@/i.js'; import { serverContext, assertServerContext } from '@/server-context.js'; const XHome = defineAsyncComponent(() => import('./home.vue')); -const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue')); +const XNotes = defineAsyncComponent(() => import('./notes.vue')); const XFiles = defineAsyncComponent(() => import('./files.vue')); const XActivity = defineAsyncComponent(() => import('./activity.vue')); const XAchievements = defineAsyncComponent(() => import('./achievements.vue')); diff --git a/packages/frontend/src/pages/user/notes.vue b/packages/frontend/src/pages/user/notes.vue new file mode 100644 index 0000000000..c97177b6a5 --- /dev/null +++ b/packages/frontend/src/pages/user/notes.vue @@ -0,0 +1,67 @@ +<!-- +SPDX-FileCopyrightText: syuilo and misskey-project +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div class="_spacer" style="--MI_SPACER-w: 800px;"> + <div :class="$style.root"> + <MkStickyContainer> + <template #header> + <MkTab v-model="tab" :class="$style.tab"> + <option value="featured">{{ i18n.ts.featured }}</option> + <option value="notes">{{ i18n.ts.notes }}</option> + <option value="all">{{ i18n.ts.all }}</option> + <option value="files">{{ i18n.ts.withFiles }}</option> + </MkTab> + </template> + <MkNotesTimeline :key="tab" :noGap="true" :pagination="pagination" :class="$style.tl"/> + </MkStickyContainer> + </div> +</div> +</template> + +<script lang="ts" setup> +import { ref, computed } from 'vue'; +import * as Misskey from 'misskey-js'; +import MkNotesTimeline from '@/components/MkNotesTimeline.vue'; +import MkTab from '@/components/MkTab.vue'; +import { i18n } from '@/i18n.js'; + +const props = defineProps<{ + user: Misskey.entities.UserDetailed; +}>(); + +const tab = ref<string>('all'); + +const pagination = computed(() => tab.value === 'featured' ? { + endpoint: 'users/featured-notes' as const, + limit: 10, + params: { + userId: props.user.id, + }, +} : { + endpoint: 'users/notes' as const, + limit: 10, + params: { + userId: props.user.id, + withRenotes: tab.value === 'all', + withReplies: tab.value === 'all', + withChannelNotes: tab.value === 'all', + withFiles: tab.value === 'files', + }, +}); +</script> + +<style lang="scss" module> +.tab { + padding: calc(var(--MI-margin) / 2) 0; + background: var(--MI_THEME-bg); +} + +.tl { + background: var(--MI_THEME-bg); + border-radius: var(--MI-radius); + overflow: clip; +} +</style> |