mirror of https://github.com/pixelfed/pixelfed.git
846 lines
23 KiB
Vue
846 lines
23 KiB
Vue
<template>
|
|
<div class="comment-drawer-component">
|
|
<input type="file" ref="fileInput" class="d-none" accept="image/jpeg,image/png" @change="handleImageUpload">
|
|
<div v-if="hide"></div>
|
|
<div v-else-if="!isLoaded" class="border-top d-flex justify-content-center py-3">
|
|
<div class="text-center">
|
|
<div
|
|
class="spinner-border text-lighter"
|
|
role="status">
|
|
<span class="sr-only">Loading...</span>
|
|
</div>
|
|
<p class="text-muted">Loading Comments ...</p>
|
|
</div>
|
|
</div>
|
|
<div v-else class="border-top">
|
|
<!-- <div v-if="profile && canReply" class="my-3">
|
|
<div class="d-flex align-items-top reply-form">
|
|
<img class="rounded-circle mr-2 border" :src="avatar" width="38" height="38">
|
|
<div v-if="isUploading" class="w-100">
|
|
<p class="font-weight-light mb-1">Uploading image ...</p>
|
|
<div class="progress rounded-pill" style="height:4px">
|
|
<div class="progress-bar" role="progressbar" :aria-valuenow="uploadProgress" aria-valuemin="0" aria-valuemax="100" :style="{ width: uploadProgress + '%'}"></div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="reply-form-input">
|
|
<input
|
|
class="form-control bg-light border-lighter rounded-pill"
|
|
placeholder="Write a comment...."
|
|
v-model="replyContent"
|
|
v-on:keyup.enter="storeComment">
|
|
|
|
<div class="reply-form-input-actions">
|
|
<button
|
|
class="btn btn-link text-muted px-1 mr-2"
|
|
@click="uploadImage">
|
|
<i class="far fa-image fa-lg"></i>
|
|
</button>
|
|
<button class="btn btn-link text-muted px-1 small font-weight-bold border py-0 rounded-pill text-decoration-none">
|
|
GIF
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> -->
|
|
<div class="my-3">
|
|
<div
|
|
v-for="(status, index) in feed"
|
|
:key="'cdf' + index + status.id"
|
|
class="media media-status align-items-top">
|
|
|
|
<a
|
|
v-if="replyChildId == status.id"
|
|
href="#comment-1"
|
|
class="comment-border-link"
|
|
@click.prevent="replyToChild(status)">
|
|
<span class="sr-only">Jump to comment-{{ index }}</span>
|
|
</a>
|
|
|
|
<a :href="status.account.url">
|
|
<img class="rounded-circle media-avatar border" :src="status.account.avatar" width="32" height="32" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=2'" />
|
|
</a>
|
|
|
|
<div class="media-body">
|
|
<div v-if="!status.media_attachments.length" class="media-body-comment">
|
|
<p class="media-body-comment-username">
|
|
<a :href="status.account.url">
|
|
{{status.account.acct}}
|
|
</a>
|
|
</p>
|
|
<read-more :status="status" />
|
|
</div>
|
|
<div v-else>
|
|
<p class="media-body-comment-username">
|
|
<a :href="status.account.url">
|
|
{{status.account.acct}}
|
|
</a>
|
|
</p>
|
|
<div class="bh-comment" @click="lightbox(status)">
|
|
<blur-hash-image
|
|
:width="blurhashWidth(status)"
|
|
:height="blurhashHeight(status)"
|
|
:punch="1"
|
|
class="img-fluid rounded-lg border shadow"
|
|
:hash="status.media_attachments[0].blurhash"
|
|
:src="getMediaSource(status)" />
|
|
</div>
|
|
</div>
|
|
<p class="media-body-reactions">
|
|
<a
|
|
v-if="profile"
|
|
href="#"
|
|
class="font-weight-bold"
|
|
:class="[ status.favourited ? 'text-primary' : 'text-muted' ]"
|
|
@click.prevent="likeComment(status, index, $event)">
|
|
{{ status.favourited ? 'Liked' : 'Like' }}
|
|
</a>
|
|
<span class="mx-1">·</span>
|
|
<a href="#" class="text-muted font-weight-bold" @click.prevent="replyToChild(status, index)">Reply</a>
|
|
<span v-if="profile" class="mx-1">·</span>
|
|
<a
|
|
class="font-weight-bold text-muted"
|
|
:href="status.url"
|
|
v-once>
|
|
{{ shortTimestamp(status.created_at) }}
|
|
</a>
|
|
<span v-if="profile && status.account.id === profile.id">
|
|
<span class="mx-1">·</span>
|
|
<a
|
|
class="font-weight-bold text-lighter"
|
|
href="#"
|
|
@click.prevent="deleteComment(index)">
|
|
Delete
|
|
</a>
|
|
</span>
|
|
</p>
|
|
|
|
<!-- <div v-if="replyChildId == status.id && status.reply_count" class="media media-status align-items-top mt-3">
|
|
<div class="comment-border-arrow"></div>
|
|
<a href="https://pixelfed.test/groups/328821658771132416/user/321493203255693312"><img src="https://pixelfed.test/storage/avatars/321493203255693312/5a6nqo.jpg?v=2" width="32" height="32" class="rounded-circle media-avatar border"></a>
|
|
<div class="media-body"><div class="media-body-comment"><p class="media-body-comment-username"><a href="https://pixelfed.test/groups/328821658771132416/user/321493203255693312">
|
|
dansup
|
|
</a></p> <div class="read-more-component" style="word-break: break-all;"><div>test</div></div></div> <p class="media-body-reactions"><a href="#" class="font-weight-bold text-muted">
|
|
Like
|
|
</a> <span class="mx-1">·</span> <a href="https://pixelfed.test/groups/328821658771132416/p/358529382599041029" class="font-weight-bold text-muted">
|
|
1h
|
|
</a> <span><span class="mx-1">·</span> <a href="#" class="font-weight-bold text-lighter">
|
|
Delete
|
|
</a></span></p>
|
|
</div>
|
|
</div> -->
|
|
|
|
<div v-if="replyChildIndex == index && status.hasOwnProperty('children') && status.children.hasOwnProperty('feed') && status.children.feed.length">
|
|
<comment-post
|
|
v-for="(s, index) in status.children.feed"
|
|
:status="s"
|
|
:profile="profile"
|
|
:commentBorderArrow="true"
|
|
:key="'scp_'+index+'_'+s.id"
|
|
/>
|
|
</div>
|
|
|
|
<a
|
|
v-if="replyChildIndex == index &&
|
|
status.hasOwnProperty('children') &&
|
|
status.children.hasOwnProperty('can_load_more') &&
|
|
status.children.can_load_more == true"
|
|
class="text-muted font-weight-bold mt-1 mb-0"
|
|
style="font-size: 13px;"
|
|
href="#"
|
|
:disabled="loadingChildComments"
|
|
@click.prevent="loadMoreChildComments(status, index)">
|
|
<div class="comment-border-arrow"></div>
|
|
<i class="far fa-long-arrow-right mr-1"></i>
|
|
{{ loadingChildComments ? 'Loading' : 'Load' }} more comments
|
|
</a>
|
|
|
|
<a
|
|
v-else-if="replyChildIndex !== index &&
|
|
status.hasOwnProperty('children') &&
|
|
status.children.hasOwnProperty('can_load_more') &&
|
|
status.children.can_load_more == true &&
|
|
status.reply_count > 0 &&
|
|
!loadingChildComments"
|
|
class="text-muted font-weight-bold mt-1 mb-0"
|
|
style="font-size: 13px;"
|
|
href="#"
|
|
:disabled="loadingChildComments"
|
|
@click.prevent="replyToChild(status, index)">
|
|
<i class="far fa-long-arrow-right mr-1"></i>
|
|
{{ loadingChildComments ? 'Loading' : 'Load' }} more comments
|
|
</a>
|
|
|
|
<div v-if="replyChildId == status.id" class="mt-3 mb-3 d-flex align-items-top reply-form child-reply-form">
|
|
<div class="comment-border-arrow"></div>
|
|
<img class="rounded-circle mr-2 border" :src="avatar" width="38" height="38" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=2'">
|
|
<div v-if="isUploading" class="w-100">
|
|
<p class="font-weight-light mb-1">Uploading image ...</p>
|
|
<div class="progress rounded-pill" style="height:10px">
|
|
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" :aria-valuenow="uploadProgress" aria-valuemin="0" aria-valuemax="100" :style="{ width: uploadProgress + '%'}"></div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="reply-form-input">
|
|
<input
|
|
class="form-control bg-light border-lighter rounded-pill"
|
|
placeholder="Write a comment...."
|
|
v-model="childReplyContent"
|
|
:disabled="postingChildComment"
|
|
v-on:keyup.enter="storeChildComment(index)">
|
|
|
|
<!-- <div class="reply-form-input-actions">
|
|
<button
|
|
class="btn btn-link text-muted px-1 mr-2"
|
|
@click="uploadImage">
|
|
<i class="far fa-image fa-lg"></i>
|
|
</button>
|
|
<button class="btn btn-link text-muted px-1 small font-weight-bold border py-0 rounded-pill text-decoration-none">
|
|
GIF
|
|
</button>
|
|
</div> -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<!-- <a v-if="permalinkMode && canLoadMore" class="text-muted mb-n1" style="font-size: 13px;font-weight: 600;" href="#">Load more comments ...</a> -->
|
|
</div>
|
|
<button
|
|
v-if="canLoadMore"
|
|
class="btn btn-link btn-sm text-muted mb-2"
|
|
@click="loadMoreComments"
|
|
:disabled="isLoadingMore">
|
|
|
|
<span v-if="!isLoadingMore">
|
|
Load more comments ...
|
|
</span>
|
|
<div
|
|
v-else
|
|
class="spinner-border spinner-border-sm text-muted"
|
|
role="status">
|
|
<span class="sr-only">Loading...</span>
|
|
</div>
|
|
</button>
|
|
|
|
<div v-if="profile && canReply" class="mt-3 mb-n3">
|
|
<div class="d-flex align-items-top reply-form cdrawer-reply-form">
|
|
<img class="rounded-circle mr-2 border" :src="avatar" width="38" height="38" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=2'">
|
|
<div v-if="isUploading" class="w-100">
|
|
<p class="font-weight-light small text-muted mb-1">Uploading image ...</p>
|
|
<div class="progress rounded-pill" style="height:10px">
|
|
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" :aria-valuenow="uploadProgress" aria-valuemin="0" aria-valuemax="100" :style="{ width: uploadProgress + '%'}"></div>
|
|
</div>
|
|
</div>
|
|
<div v-else class="w-100">
|
|
<div class="reply-form-input">
|
|
<textarea
|
|
class="form-control bg-light border-lighter"
|
|
placeholder="Write a comment...."
|
|
:rows="replyContent && replyContent.length > 40 ? 4 : 1"
|
|
v-model="replyContent"></textarea>
|
|
|
|
<div class="reply-form-input-actions">
|
|
<button
|
|
class="btn btn-link text-muted px-1 mr-2"
|
|
@click="uploadImage">
|
|
<i class="far fa-image fa-lg"></i>
|
|
</button>
|
|
<!-- <button class="btn btn-link text-muted px-1 small font-weight-bold border py-0 rounded-pill text-decoration-none">
|
|
GIF
|
|
</button> -->
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-between reply-form-menu">
|
|
<div class="char-counter">
|
|
<span>{{ replyContent?.length ?? 0 }}</span>
|
|
<span>/</span>
|
|
<span>500</span>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<button
|
|
class="btn btn-link btn-sm font-weight-bold align-self-center ml-3 mb-3"
|
|
@click="storeComment">Post</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<b-modal ref="lightboxModal"
|
|
id="lightbox"
|
|
:hide-header="true"
|
|
:hide-footer="true"
|
|
centered
|
|
size="lg"
|
|
body-class="p-0"
|
|
content-class="bg-transparent border-0"
|
|
>
|
|
<div v-if="lightboxStatus" @click="hideLightbox">
|
|
<img :src="lightboxStatus.url" style="width: 100%;max-height: 90vh;object-fit: contain;">
|
|
</div>
|
|
</b-modal>
|
|
</div>
|
|
</template>
|
|
|
|
<script type="text/javascript">
|
|
import ReadMore from './ReadMore.vue';
|
|
import CommentPost from './CommentPost.vue';
|
|
|
|
export default {
|
|
props: {
|
|
groupId: {
|
|
type: String
|
|
},
|
|
|
|
profile: {
|
|
type: Object
|
|
},
|
|
|
|
status: {
|
|
type: Object
|
|
},
|
|
|
|
show: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
|
|
permalinkMode: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
|
|
permalinkStatus: {
|
|
type: Object
|
|
},
|
|
|
|
canReply: {
|
|
type: Boolean,
|
|
default: true
|
|
}
|
|
},
|
|
|
|
components: {
|
|
"read-more": ReadMore,
|
|
"comment-post": CommentPost
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
isLoaded: false,
|
|
hide: false,
|
|
feed: [],
|
|
canLoadMore: false,
|
|
isLoadingMore: false,
|
|
replyContent: null,
|
|
maxReplyId: null,
|
|
readMoreCursor: 200,
|
|
avatar: '/storage/avatars/default.png',
|
|
isUploading: false,
|
|
uploadProgress: 0,
|
|
lightboxStatus: null,
|
|
replyChildId: undefined,
|
|
replyChildIndex: undefined,
|
|
childReplyContent: null,
|
|
postingChildComment: false,
|
|
loadingChildComments: false,
|
|
replyChildMinId: undefined,
|
|
replyCursorId: null
|
|
}
|
|
},
|
|
|
|
mounted() {
|
|
if(this.permalinkMode && this.permalinkStatus) {
|
|
let status = this.permalinkStatus;
|
|
if(status.reply_count) {
|
|
status.children = {
|
|
feed: [],
|
|
can_load_more: true
|
|
}
|
|
}
|
|
this.feed.push(status);
|
|
this.isLoaded = true;
|
|
this.canLoadMore = false;
|
|
} else {
|
|
this.fetchComments();
|
|
}
|
|
|
|
if(this.profile && this.profile.hasOwnProperty('avatar')) {
|
|
this.avatar = this.profile.avatar;
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
fetchComments() {
|
|
axios.get('/api/v0/groups/comments', {
|
|
params: {
|
|
gid: this.groupId,
|
|
sid: this.status.id,
|
|
limit: 3
|
|
}
|
|
}).then(res => {
|
|
let data = res.data.map(function(c) {
|
|
if(c.reply_count && c.reply_count > 0) {
|
|
c.children = {
|
|
feed: [],
|
|
can_load_more: true
|
|
}
|
|
}
|
|
return c;
|
|
})
|
|
this.feed = data;
|
|
this.isLoaded = true;
|
|
this.maxReplyId = res.data[(res.data.length - 1)].id;
|
|
if(this.feed.length == 3) {
|
|
this.canLoadMore = true;
|
|
} else {
|
|
}
|
|
}).catch(err => {
|
|
this.isLoaded = true;
|
|
})
|
|
},
|
|
|
|
loadMoreComments() {
|
|
this.isLoadingMore = true;
|
|
|
|
axios.get('/api/v0/groups/comments', {
|
|
params: {
|
|
gid: this.groupId,
|
|
sid: this.status.id,
|
|
limit: 3,
|
|
max_id: this.maxReplyId
|
|
}
|
|
}).then(res => {
|
|
if(res.data[res.data.length - 1].id == this.maxReplyId) {
|
|
this.isLoadingMore = false;
|
|
this.canLoadMore = false;
|
|
return;
|
|
}
|
|
this.feed.push(...res.data);
|
|
setTimeout(() => {
|
|
this.isLoadingMore = false;
|
|
}, 500);
|
|
this.maxReplyId = res.data[res.data.length - 1].id;
|
|
if(res.data.length > 0) {
|
|
this.canLoadMore = true;
|
|
} else {
|
|
this.canLoadMore = false;
|
|
}
|
|
}).catch(err => {
|
|
this.isLoadingMore = false;
|
|
this.canLoadMore = false;
|
|
})
|
|
},
|
|
|
|
storeComment($event) {
|
|
$event.currentTarget?.blur();
|
|
axios.post('/api/v0/groups/comment', {
|
|
gid: this.groupId,
|
|
sid: this.status.id,
|
|
content: this.replyContent
|
|
})
|
|
.then(res => {
|
|
this.replyContent = null;
|
|
this.feed.unshift(res.data);
|
|
}).catch(err => {
|
|
if(err.response.status == 422) {
|
|
this.isUploading = false;
|
|
this.uploadProgress = 0;
|
|
swal('Oops!', err.response.data.error, 'error');
|
|
} else {
|
|
this.isUploading = false;
|
|
this.uploadProgress = 0;
|
|
swal('Oops!', 'An error occured while processing your request, please try again later', 'error');
|
|
}
|
|
})
|
|
},
|
|
|
|
shortTimestamp(ts) {
|
|
return window.App.util.format.timeAgo(ts);
|
|
},
|
|
|
|
readMore() {
|
|
this.readMoreCursor = this.readMoreCursor + 200;
|
|
},
|
|
|
|
likeComment(status, index, $event) {
|
|
$event.target.blur();
|
|
let l = status.favourited ? false : true;
|
|
this.feed[index].favourited = l;
|
|
status.favourited = l;
|
|
axios.post(`/api/v0/groups/comment/${l ? 'like' : 'unlike'}`, {
|
|
sid: status.id,
|
|
gid: this.groupId
|
|
});
|
|
},
|
|
|
|
deleteComment(index) {
|
|
if(window.confirm('Are you sure you want to delete this post?') == false) {
|
|
return;
|
|
}
|
|
|
|
axios.post('/api/v0/groups/comment/delete', {
|
|
gid: this.groupId,
|
|
id: this.feed[index].id
|
|
}).then(res => {
|
|
this.feed.splice(index, 1);
|
|
}).catch(err => {
|
|
console.log(err.response);
|
|
swal('Error', 'Something went wrong. Please try again later.', 'error');
|
|
});
|
|
},
|
|
|
|
uploadImage() {
|
|
this.$refs.fileInput.click();
|
|
},
|
|
|
|
handleImageUpload() {
|
|
if(!this.$refs.fileInput.files.length) {
|
|
return;
|
|
}
|
|
this.isUploading = true;
|
|
let self = this;
|
|
let data = new FormData();
|
|
data.append('gid', this.groupId);
|
|
data.append('sid', this.status.id);
|
|
data.append('photo', this.$refs.fileInput.files[0]);
|
|
|
|
axios.post('/api/v0/groups/comment/photo', data, {
|
|
onUploadProgress: function(progressEvent) {
|
|
self.uploadProgress = Math.floor(progressEvent.loaded / progressEvent.total * 100);
|
|
}
|
|
})
|
|
.then(res => {
|
|
this.isUploading = false;
|
|
this.uploadProgress = 0;
|
|
this.feed.unshift(res.data);
|
|
}).catch(err => {
|
|
if(err.response.status == 422) {
|
|
this.isUploading = false;
|
|
this.uploadProgress = 0;
|
|
swal('Oops!', err.response.data.error, 'error');
|
|
} else {
|
|
this.isUploading = false;
|
|
this.uploadProgress = 0;
|
|
swal('Oops!', 'An error occured while processing your request, please try again later', 'error');
|
|
}
|
|
});
|
|
},
|
|
|
|
lightbox(status) {
|
|
this.lightboxStatus = status.media_attachments[0];
|
|
this.$refs.lightboxModal.show();
|
|
},
|
|
|
|
hideLightbox() {
|
|
this.lightboxStatus = null;
|
|
this.$refs.lightboxModal.hide();
|
|
},
|
|
|
|
blurhashWidth(status) {
|
|
if(!status.media_attachments[0].meta) {
|
|
return 25;
|
|
}
|
|
let aspect = status.media_attachments[0].meta.original.aspect;
|
|
if(aspect == 1) {
|
|
return 25;
|
|
} else if(aspect > 1) {
|
|
return 30;
|
|
} else {
|
|
return 20;
|
|
}
|
|
},
|
|
|
|
blurhashHeight(status) {
|
|
if(!status.media_attachments[0].meta) {
|
|
return 25;
|
|
}
|
|
let aspect = status.media_attachments[0].meta.original.aspect;
|
|
if(aspect == 1) {
|
|
return 25;
|
|
} else if(aspect > 1) {
|
|
return 20;
|
|
} else {
|
|
return 30;
|
|
}
|
|
},
|
|
|
|
getMediaSource(status) {
|
|
let media = status.media_attachments[0];
|
|
|
|
if(media.preview_url.endsWith('storage/no-preview.png')) {
|
|
return media.url;
|
|
}
|
|
|
|
return media.preview_url;
|
|
},
|
|
|
|
replyToChild(status, index) {
|
|
|
|
if(this.replyChildId == status.id) {
|
|
this.replyChildId = null;
|
|
this.replyChildIndex = null;
|
|
return;
|
|
} else {
|
|
this.childReplyContent = null;
|
|
}
|
|
|
|
this.replyChildId = status.id;
|
|
this.replyCursorId = status.id
|
|
this.replyChildIndex = index;
|
|
|
|
if(!status.hasOwnProperty('replies_loaded') || !status.replies_loaded) {
|
|
this.$nextTick(() => {
|
|
this.fetchChildReplies(status, index);
|
|
});
|
|
} else {
|
|
this.$nextTick(() => {
|
|
this.fetchChildReplies(status, index);
|
|
});
|
|
}
|
|
},
|
|
|
|
fetchChildReplies(status, index) {
|
|
axios.get('/api/v0/groups/comments', {
|
|
params: {
|
|
gid: this.groupId,
|
|
sid: status.id,
|
|
cid: this.replyCursorId,
|
|
limit: 3
|
|
}
|
|
}).then(res => {
|
|
if(this.feed[index].hasOwnProperty('children')) {
|
|
this.feed[index].children.feed.push(res.data);
|
|
this.feed[index].children.can_load_more = res.data.length == 3;
|
|
} else {
|
|
this.feed[index].children = {
|
|
feed: res.data,
|
|
can_load_more: res.data.length == 3
|
|
}
|
|
}
|
|
this.replyChildMinId = res.data[res.data.length - 1].id;
|
|
this.$nextTick(() => {
|
|
this.feed[index].replies_loaded = true;
|
|
});
|
|
}).catch(err => {
|
|
this.feed[index].children.can_load_more = false;
|
|
})
|
|
},
|
|
|
|
storeChildComment(index) {
|
|
this.postingChildComment = true;
|
|
|
|
axios.post('/api/v0/groups/comment', {
|
|
gid: this.groupId,
|
|
sid: this.status.id,
|
|
cid: this.replyChildId,
|
|
content: this.childReplyContent
|
|
})
|
|
.then(res => {
|
|
this.childReplyContent = null;
|
|
this.postingChildComment = false;
|
|
this.feed[index].children.feed.push(res.data);
|
|
// this.feed.unshift(res.data);
|
|
}).catch(err => {
|
|
if(err.response.status == 422) {
|
|
// this.isUploading = false;
|
|
// this.uploadProgress = 0;
|
|
swal('Oops!', err.response.data.error, 'error');
|
|
} else {
|
|
// this.isUploading = false;
|
|
// this.uploadProgress = 0;
|
|
swal('Oops!', 'An error occured while processing your request, please try again later', 'error');
|
|
}
|
|
});
|
|
},
|
|
|
|
loadMoreChildComments(status, index) {
|
|
this.loadingChildComments = true;
|
|
|
|
axios.get('/api/v0/groups/comments', {
|
|
params: {
|
|
gid: this.groupId,
|
|
sid: status.id,
|
|
max_id: this.replyChildMinId,
|
|
cid: 1,
|
|
limit: 3
|
|
}
|
|
}).then(res => {
|
|
if(this.feed[index].hasOwnProperty('children')) {
|
|
this.feed[index].children.feed.push(...res.data);
|
|
this.feed[index].children.can_load_more = res.data.length == 3;
|
|
} else {
|
|
this.feed[index].children = {
|
|
feed: res.data,
|
|
can_load_more: res.data.length == 3
|
|
}
|
|
}
|
|
this.replyChildMinId = res.data[res.data.length - 1].id;
|
|
this.feed[index].replies_loaded = true;
|
|
this.loadingChildComments = false;
|
|
}).catch(err => {
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.comment-drawer-component {
|
|
.media {
|
|
position: relative;
|
|
|
|
.comment-border-link {
|
|
display: block;
|
|
position: absolute;
|
|
top: 40px;
|
|
left: 11px;
|
|
width: 10px;
|
|
height: calc(100% - 100px);
|
|
border-left: 4px solid transparent;
|
|
border-right: 4px solid transparent;
|
|
background-color: #E5E7EB;
|
|
background-clip: padding-box;
|
|
|
|
&:hover {
|
|
background-color: #BFDBFE;
|
|
}
|
|
}
|
|
|
|
.child-reply-form {
|
|
position: relative;
|
|
}
|
|
|
|
.comment-border-arrow {
|
|
display: block;
|
|
position: absolute;
|
|
top: -6px;
|
|
left: -33px;
|
|
width: 10px;
|
|
height: 29px;
|
|
border-left: 4px solid transparent;
|
|
border-right: 4px solid transparent;
|
|
background-color: #E5E7EB;
|
|
background-clip: padding-box;
|
|
border-bottom: 2px solid transparent;
|
|
|
|
&:after {
|
|
content: '';
|
|
display: block;
|
|
position: absolute;
|
|
top: 25px;
|
|
left: 2px;
|
|
width: 15px;
|
|
height: 2px;
|
|
background-color: #E5E7EB;
|
|
}
|
|
}
|
|
|
|
&-status {
|
|
margin-bottom: 1.3rem;
|
|
}
|
|
|
|
&-avatar {
|
|
margin-right: 12px;
|
|
}
|
|
|
|
&-body {
|
|
&-comment {
|
|
width: fit-content;
|
|
padding: 0.4rem 0.7rem;
|
|
background-color: var(--comment-bg);
|
|
border-radius: 0.9rem;
|
|
|
|
&-username {
|
|
margin-bottom: 0.25rem !important;
|
|
font-size: 14px;
|
|
font-weight: 700 !important;
|
|
color: #000;
|
|
|
|
a {
|
|
color: #000;
|
|
text-decoration: none;
|
|
}
|
|
}
|
|
|
|
&-content {
|
|
margin-bottom: 0;
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
|
|
&-reactions {
|
|
margin-top: 0.25rem !important;
|
|
margin-bottom: 0 !important;
|
|
color: #B8C2CC !important;
|
|
font-size: 12px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.load-more-comments {
|
|
font-weight: 500;
|
|
}
|
|
|
|
.reply-form {
|
|
margin-bottom: 2rem;
|
|
|
|
&-input {
|
|
flex: 1;
|
|
position: relative;
|
|
|
|
textarea {
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.form-control {
|
|
resize: none;
|
|
padding-right: 100px;
|
|
}
|
|
|
|
&-actions {
|
|
position: absolute;
|
|
right: 10px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
}
|
|
|
|
.btn {
|
|
text-decoration: none;
|
|
}
|
|
|
|
&-menu {
|
|
margin-top: 5px;
|
|
|
|
.char-counter {
|
|
color: var(--muted);
|
|
font-size: 10px;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
.bh-comment {
|
|
width: 100%;
|
|
height: auto;
|
|
max-width: 160px !important;
|
|
max-height: 260px !important;
|
|
|
|
span {
|
|
width: 100%;
|
|
height: auto;
|
|
max-width: 160px !important;
|
|
max-height: 260px !important;
|
|
}
|
|
|
|
img {
|
|
width: 100%;
|
|
height: auto;
|
|
max-width: 160px !important;
|
|
max-height: 260px !important;
|
|
object-fit: cover;
|
|
}
|
|
}
|
|
}
|
|
</style>
|