diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2023-09-17 10:33:33 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2023-09-17 10:33:33 +0900 |
| commit | 907d519da36c550dde0a39970057bce22ffdcc5f (patch) | |
| tree | 72ad0cc084a6b6425b42926bf2c1245205068653 /packages/frontend/src/components/MkNoteDetailed.vue | |
| parent | Update CHANGELOG.md (diff) | |
| download | misskey-907d519da36c550dde0a39970057bce22ffdcc5f.tar.gz misskey-907d519da36c550dde0a39970057bce22ffdcc5f.tar.bz2 misskey-907d519da36c550dde0a39970057bce22ffdcc5f.zip | |
enhance(frontend): improve note detail page
Diffstat (limited to 'packages/frontend/src/components/MkNoteDetailed.vue')
| -rw-r--r-- | packages/frontend/src/components/MkNoteDetailed.vue | 133 |
1 files changed, 123 insertions, 10 deletions
diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index f7578dd390..086667127b 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -11,7 +11,12 @@ SPDX-License-Identifier: AGPL-3.0-only v-hotkey="keymap" :class="$style.root" > - <MkNoteSub v-for="note in conversation" :key="note.id" :class="$style.replyToMore" :note="note"/> + <div v-if="appearNote.reply.replyId"> + <div v-if="!conversationLoaded" style="padding: 16px"> + <MkButton style="margin: 0 auto;" primary rounded @click="loadConversation">{{ i18n.ts.loadConversation }}</MkButton> + </div> + <MkNoteSub v-for="note in conversation" :key="note.id" :class="$style.replyToMore" :note="note"/> + </div> <MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/> <div v-if="isRenote" :class="$style.renote"> <MkAvatar :class="$style.renoteAvatar" :user="note.user" link preview/> @@ -125,7 +130,43 @@ SPDX-License-Identifier: AGPL-3.0-only </button> </footer> </article> - <MkNoteSub v-for="note in replies" :key="note.id" :note="note" :class="$style.reply" :detail="true"/> + <div :class="$style.tabs"> + <button class="_button" :class="[$style.tab, { [$style.tabActive]: tab === 'replies' }]" @click="tab = 'replies'"><i class="ti ti-arrow-back-up"></i> {{ i18n.ts.replies }}</button> + <button class="_button" :class="[$style.tab, { [$style.tabActive]: tab === 'renotes' }]" @click="tab = 'renotes'"><i class="ti ti-repeat"></i> {{ i18n.ts.renotes }}</button> + <button class="_button" :class="[$style.tab, { [$style.tabActive]: tab === 'reactions' }]" @click="tab = 'reactions'"><i class="ti ti-icons"></i> {{ i18n.ts.reactions }}</button> + </div> + <div> + <div v-if="tab === 'replies'" :class="$style.tab_replies"> + <div v-if="!repliesLoaded" style="padding: 16px"> + <MkButton style="margin: 0 auto;" primary rounded @click="loadReplies">{{ i18n.ts.loadReplies }}</MkButton> + </div> + <MkNoteSub v-for="note in replies" :key="note.id" :note="note" :class="$style.reply" :detail="true"/> + </div> + <div v-else-if="tab === 'renotes'" :class="$style.tab_renotes"> + <MkPagination :pagination="renotesPagination"> + <template #default="{ items }"> + <MkA v-for="item in items" :key="item.id" :to="userPage(item.user)"> + <MkUserCardMini :user="item.user" :withChart="false"/> + </MkA> + </template> + </MkPagination> + </div> + <div v-else-if="tab === 'reactions'" :class="$style.tab_reactions"> + <div :class="$style.reactionTabs"> + <button v-for="reaction in Object.keys(appearNote.reactions)" :key="reaction" :class="[$style.reactionTab, { [$style.reactionTabActive]: reactionTabType === reaction }]" class="_button" @click="reactionTabType = reaction"> + <MkReactionIcon :reaction="reaction"/> + <span style="margin-left: 4px;">{{ appearNote.reactions[reaction] }}</span> + </button> + </div> + <MkPagination :pagination="reactionsPagination"> + <template #default="{ items }"> + <MkA v-for="item in items" :key="item.id" :to="userPage(item.user)"> + <MkUserCardMini :user="item.user" :withChart="false"/> + </MkA> + </template> + </MkPagination> + </div> + </div> </div> <div v-else class="_panel" :class="$style.muted" @click="muted = false"> <I18n :src="i18n.ts.userSaysSomething" tag="small"> @@ -169,6 +210,10 @@ import { claimAchievement } from '@/scripts/achievements'; import { MenuItem } from '@/types/menu'; import MkRippleEffect from '@/components/MkRippleEffect.vue'; import { showMovedDialog } from '@/scripts/show-moved-dialog'; +import MkUserCardMini from '@/components/MkUserCardMini.vue'; +import MkPagination, { Paging } from '@/components/MkPagination.vue'; +import MkReactionIcon from '@/components/MkReactionIcon.vue'; +import MkButton from '@/components/MkButton.vue'; const props = defineProps<{ note: Misskey.entities.Note; @@ -224,6 +269,26 @@ const keymap = { 's': () => showContent.value !== showContent.value, }; +let tab = $ref('replies'); +let reactionTabType = $ref(null); + +const renotesPagination = $computed(() => ({ + endpoint: 'notes/renotes', + limit: 10, + params: { + noteId: appearNote.id, + }, +})); + +const reactionsPagination = $computed(() => ({ + endpoint: 'notes/reactions', + limit: 10, + params: { + noteId: appearNote.id, + type: reactionTabType, + }, +})); + useNoteCapture({ rootEl: el, note: $$(appearNote), @@ -426,14 +491,20 @@ function blur() { el.value.blur(); } -os.api('notes/children', { - noteId: appearNote.id, - limit: 30, -}).then(res => { - replies.value = res; -}); +const repliesLoaded = ref(false); +function loadReplies() { + repliesLoaded.value = true; + os.api('notes/children', { + noteId: appearNote.id, + limit: 30, + }).then(res => { + replies.value = res; + }); +} -if (appearNote.replyId) { +const conversationLoaded = ref(false); +function loadConversation() { + conversationLoaded.value = true; os.api('notes/conversation', { noteId: appearNote.replyId, }).then(res => { @@ -640,10 +711,52 @@ if (appearNote.replyId) { } } -.reply { +.reply:not(:first-child) { border-top: solid 0.5px var(--divider); } +.tabs { + border-top: solid 0.5px var(--divider); + border-bottom: solid 0.5px var(--divider); + display: flex; +} + +.tab { + flex: 1; + padding: 12px 8px; + border-top: solid 2px transparent; + border-bottom: solid 2px transparent; +} + +.tabActive { + border-bottom: solid 2px var(--accent); +} + +.tab_renotes { + padding: 16px; +} + +.tab_reactions { + padding: 16px; +} + +.reactionTabs { + display: flex; + gap: 8px; + flex-wrap: wrap; + margin-bottom: 8px; +} + +.reactionTab { + padding: 4px 6px; + border: solid 1px var(--divider); + border-radius: 6px; +} + +.reactionTabActive { + border-color: var(--accent); +} + @container (max-width: 500px) { .root { font-size: 0.9em; |