pixelfed/resources/assets/components/partials/post/PostHeader.vue
2023-05-25 00:33:44 -06:00

349 lines
8.5 KiB
Vue

<template>
<div class="card-header border-0" style="border-top-left-radius: 15px;border-top-right-radius: 15px;">
<div class="media align-items-center">
<a :href="status.account.url" @click.prevent="goToProfile()" style="margin-right: 10px;">
<img :src="getStatusAvatar()" style="border-radius:15px;" width="44" height="44" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';">
</a>
<div class="media-body">
<p class="font-weight-bold username">
<a :href="status.account.url" class="text-dark" :id="'apop_'+status.id" @click.prevent="goToProfile">
{{ status.account.acct }}
</a>
<b-popover :target="'apop_'+status.id" triggers="hover" placement="bottom" custom-class="shadow border-0 rounded-px">
<profile-hover-card
:profile="status.account"
v-on:follow="follow"
v-on:unfollow="unfollow" />
</b-popover>
</p>
<p class="text-lighter mb-0" style="font-size: 13px;">
<span v-if="status.account.is_admin" class="d-none d-md-inline-block">
<span class="badge badge-light text-danger user-select-none" title="Admin account">ADMIN</span>
<span class="mx-1 text-lighter">·</span>
</span>
<a class="timestamp text-lighter" :href="status.url" @click.prevent="goToPost()" :title="status.created_at">
{{ timeago(status.created_at) }}
</a>
<span v-if="config.ab.pue && status.hasOwnProperty('edited_at') && status.edited_at">
<span class="mx-1 text-lighter">·</span>
<a class="text-lighter" href="#" @click.prevent="openEditModal">Edited</a>
</span>
<span class="mx-1 text-lighter">·</span>
<span class="visibility text-lighter" :title="scopeTitle(status.visibility)"><i :class="scopeIcon(status.visibility)"></i></span>
<span v-if="status.place && status.place.hasOwnProperty('name')" class="d-none d-md-inline-block">
<span class="mx-1 text-lighter">·</span>
<span class="location text-lighter"><i class="far fa-map-marker-alt"></i> {{ status.place.name }}, {{ status.place.country }}</span>
</span>
</p>
</div>
<button v-if="!useDropdownMenu" class="btn btn-link text-lighter" @click="openMenu">
<i class="far fa-ellipsis-v fa-lg"></i>
</button>
<b-dropdown
v-else
no-caret
right
variant="link"
toggle-class="text-lighter"
html="<i class='far fa-ellipsis-v fa-lg px-3'></i>"
>
<b-dropdown-item>
<p class="mb-0 font-weight-bold">{{ $t('menu.viewPost') }}</p>
</b-dropdown-item>
<b-dropdown-item>
<p class="mb-0 font-weight-bold">{{ $t('common.copyLink') }}</p>
</b-dropdown-item>
<b-dropdown-item v-if="status.local">
<p class="mb-0 font-weight-bold">{{ $t('menu.embed') }}</p>
</b-dropdown-item>
<b-dropdown-divider v-if="!owner"></b-dropdown-divider>
<b-dropdown-item v-if="!owner">
<p class="mb-0 font-weight-bold">{{ $t('menu.report') }}</p>
<p class="small text-muted mb-0">Report content that violate our rules</p>
</b-dropdown-item>
<b-dropdown-item v-if="!owner && status.hasOwnProperty('relationship')">
<p class="mb-0 font-weight-bold">{{ status.relationship.muting ? 'Unmute' : 'Mute' }}</p>
<p class="small text-muted mb-0">Hide posts from this account in your feeds</p>
</b-dropdown-item>
<b-dropdown-item v-if="!owner && status.hasOwnProperty('relationship')">
<p class="mb-0 font-weight-bold text-danger">{{ status.relationship.blocking ? 'Unblock' : 'Block' }}</p>
<p class="small text-muted mb-0">Restrict all content from this account</p>
</b-dropdown-item>
<b-dropdown-divider v-if="owner || admin"></b-dropdown-divider>
<b-dropdown-item v-if="owner || admin">
<p class="mb-0 font-weight-bold text-danger">
{{ $t('common.delete') }}
</p>
</b-dropdown-item>
</b-dropdown>
</div>
<edit-history-modal ref="editModal" :status="status" />
</div>
</template>
<script type="text/javascript">
import ProfileHoverCard from './../profile/ProfileHoverCard.vue';
import EditHistoryModal from './EditHistoryModal.vue';
export default {
props: {
status: {
type: Object
},
profile: {
type: Object
},
useDropdownMenu: {
type: Boolean,
default: false
}
},
components: {
"profile-hover-card": ProfileHoverCard,
"edit-history-modal": EditHistoryModal
},
data() {
return {
config: window.App.config,
menuLoading: true,
owner: false,
admin: false,
license: false
}
},
methods: {
timeago(ts) {
let short = App.util.format.timeAgo(ts);
if(
short.endsWith('s') ||
short.endsWith('m') ||
short.endsWith('h')
) {
return short;
}
const intl = new Intl.DateTimeFormat(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
});
return intl.format(new Date(ts));
},
openMenu() {
this.$emit('menu');
},
scopeIcon(scope) {
switch(scope) {
case 'public':
return 'far fa-globe';
break;
case 'unlisted':
return 'far fa-lock-open';
break;
case 'private':
return 'far fa-lock';
break;
default:
return 'far fa-globe';
break;
}
},
scopeTitle(scope) {
switch(scope) {
case 'public':
return 'Visible to everyone';
break;
case 'unlisted':
return 'Hidden from public feeds';
break;
case 'private':
return 'Only visible to followers';
break;
default:
return '';
break;
}
},
goToPost() {
if(location.pathname.split('/').pop() == this.status.id) {
location.href = this.status.local ? this.status.url + '?fs=1' : this.status.url;
return;
}
this.$router.push({
name: 'post',
path: `/i/web/post/${this.status.id}`,
params: {
id: this.status.id,
cachedStatus: this.status,
cachedProfile: this.profile
}
})
},
goToProfile() {
this.$nextTick(() => {
this.$router.push({
name: 'profile',
path: `/i/web/profile/${this.status.account.id}`,
params: {
id: this.status.account.id,
cachedProfile: this.status.account,
cachedUser: this.profile
}
});
});
},
toggleContentWarning() {
this.key++;
this.sensitive = true;
this.status.sensitive = !this.status.sensitive;
},
like() {
event.currentTarget.blur();
if(this.status.favourited) {
this.$emit('unlike');
} else {
this.$emit('like');
}
},
toggleMenu(bvEvent) {
setTimeout(() => {
this.menuLoading = false;
}, 500);
},
closeMenu(bvEvent) {
setTimeout(() => {
bvEvent.target.parentNode.firstElementChild.blur();
}, 100);
},
showLikes() {
event.currentTarget.blur();
this.$emit('likes-modal');
},
showShares() {
event.currentTarget.blur();
this.$emit('shares-modal');
},
showComments() {
event.currentTarget.blur();
this.showCommentDrawer = !this.showCommentDrawer;
},
copyLink() {
event.currentTarget.blur();
App.util.clipboard(this.status.url);
},
shareToOther() {
if (navigator.canShare) {
navigator.share({
url: this.status.url
})
.then(() => console.log('Share was successful.'))
.catch((error) => console.log('Sharing failed', error));
} else {
swal('Not supported', 'Your current device does not support native sharing.', 'error');
}
},
counterChange(type) {
this.$emit('counter-change', type);
},
showCommentLikes(post) {
this.$emit('comment-likes-modal', post);
},
shareStatus() {
this.$emit('share');
},
unshareStatus() {
this.$emit('unshare');
},
handleReport(post) {
this.$emit('handle-report', post);
},
follow() {
this.$emit('follow');
},
unfollow() {
this.$emit('unfollow');
},
handleReblog() {
this.isReblogging = true;
if(this.status.reblogged) {
this.$emit('unshare');
} else {
this.$emit('share');
}
setTimeout(() => {
this.isReblogging = false;
}, 5000);
},
handleBookmark() {
event.currentTarget.blur();
this.isBookmarking = true;
this.$emit('bookmark');
setTimeout(() => {
this.isBookmarking = false;
}, 5000);
},
getStatusAvatar() {
if(window._sharedData.user.id == this.status.account.id) {
return window._sharedData.user.avatar;
}
return this.status.account.avatar;
},
openModTools() {
this.$emit('mod-tools');
},
openEditModal() {
this.$refs.editModal.open();
}
}
}
</script>