From 64bbfed43222e8469a39eba5249c196c16f96eb7 Mon Sep 17 00:00:00 2001 From: syuilo <syuilotan@yahoo.co.jp> Date: Sun, 10 May 2020 16:22:39 +0900 Subject: [PATCH] feat(client): Implement threaded replies Resolve #2113 Resolve #5819 --- src/client/components/note.sub.vue | 118 +++++++++++++++++++---------- src/client/components/note.vue | 2 +- 2 files changed, 79 insertions(+), 41 deletions(-) diff --git a/src/client/components/note.sub.vue b/src/client/components/note.sub.vue index 5efbb8f1e9..fcdb06bd9e 100644 --- a/src/client/components/note.sub.vue +++ b/src/client/components/note.sub.vue @@ -1,18 +1,21 @@ <template> -<div class="wrpstxzv" v-size="[{ max: 450 }]"> - <mk-avatar class="avatar" :user="note.user"/> +<div class="wrpstxzv" :class="{ children }" v-size="[{ max: 450 }]"> <div class="main"> - <x-note-header class="header" :note="note" :mini="true"/> + <mk-avatar class="avatar" :user="note.user"/> <div class="body"> - <p v-if="note.cw != null" class="cw"> - <mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis" /> - <x-cw-button v-model="showContent" :note="note"/> - </p> - <div class="content" v-show="note.cw == null || showContent"> - <x-sub-note-content class="text" :note="note"/> + <x-note-header class="header" :note="note" :mini="true"/> + <div class="body"> + <p v-if="note.cw != null" class="cw"> + <mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis" /> + <x-cw-button v-model="showContent" :note="note"/> + </p> + <div class="content" v-show="note.cw == null || showContent"> + <x-sub-note-content class="text" :note="note"/> + </div> </div> </div> </div> + <x-sub v-for="reply in replies" :key="reply.id" :note="reply" class="reply" :detail="true" :children="true"/> </div> </template> @@ -23,6 +26,8 @@ import XSubNoteContent from './sub-note-content.vue'; import XCwButton from './cw-button.vue'; export default Vue.extend({ + name: 'x-sub', + components: { XNoteHeader, XSubNoteContent, @@ -34,6 +39,16 @@ export default Vue.extend({ type: Object, required: true }, + detail: { + type: Boolean, + required: false, + default: false + }, + children: { + type: Boolean, + required: false, + default: false + }, // TODO truncate: { type: Boolean, @@ -41,23 +56,28 @@ export default Vue.extend({ } }, - inject: { - narrow: { - default: false - } - }, - data() { return { - showContent: false + showContent: false, + replies: [], }; - } + }, + + created() { + if (this.detail) { + this.$root.api('notes/children', { + noteId: this.note.id, + limit: 5 + }).then(replies => { + this.replies = replies; + }); + } + }, }); </script> <style lang="scss" scoped> .wrpstxzv { - display: flex; padding: 16px 32px; font-size: 0.9em; @@ -65,43 +85,61 @@ export default Vue.extend({ padding: 14px 16px; } - > .avatar { - flex-shrink: 0; - display: block; - margin: 0 8px 0 0; - width: 38px; - height: 38px; - border-radius: 8px; + &.children { + padding: 10px 0 0 16px; + font-size: 1em; + + &.max-width_450px { + padding: 10px 0 0 8px; + } } > .main { - flex: 1; - min-width: 0; + display: flex; - > .header { - margin-bottom: 2px; + > .avatar { + flex-shrink: 0; + display: block; + margin: 0 8px 0 0; + width: 38px; + height: 38px; + border-radius: 8px; } > .body { - > .cw { - cursor: default; - display: block; - margin: 0; - padding: 0; - overflow-wrap: break-word; + flex: 1; + min-width: 0; - > .text { - margin-right: 8px; - } + > .header { + margin-bottom: 2px; } - > .content { - > .text { + > .body { + > .cw { + cursor: default; + display: block; margin: 0; padding: 0; + overflow-wrap: break-word; + + > .text { + margin-right: 8px; + } + } + + > .content { + > .text { + margin: 0; + padding: 0; + } } } } } + + > .reply { + border-left: solid 1px var(--divider); + margin-top: 10px; + } } </style> diff --git a/src/client/components/note.vue b/src/client/components/note.vue index 619d1a5b01..ec31a5f99a 100644 --- a/src/client/components/note.vue +++ b/src/client/components/note.vue @@ -79,7 +79,7 @@ <div class="deleted" v-if="appearNote.deletedAt != null">{{ $t('deleted') }}</div> </div> </article> - <x-sub v-for="note in replies" :key="note.id" :note="note" class="reply"/> + <x-sub v-for="note in replies" :key="note.id" :note="note" class="reply" :detail="true"/> </div> </template>