Merge pull request #5320 from pixelfed/staging

Staging
This commit is contained in:
daniel 2024-10-06 00:56:06 -06:00 committed by GitHub
commit 4ec4b02099
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
94 changed files with 1206 additions and 1665 deletions

686
composer.lock generated

File diff suppressed because it is too large Load diff

1358
package-lock.json generated

File diff suppressed because it is too large Load diff

BIN
public/css/app.css vendored

Binary file not shown.

BIN
public/css/appdark.css vendored

Binary file not shown.

BIN
public/css/landing.css vendored

Binary file not shown.

Binary file not shown.

BIN
public/js/activity.js vendored

Binary file not shown.

BIN
public/js/admin.js vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/compose.js vendored

Binary file not shown.

BIN
public/js/daci.chunk.5dbd1faea828ed0b.js vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
public/js/direct.js vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/dms.chunk.1768ba82cee30612.js vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/groups.js vendored

Binary file not shown.

BIN
public/js/hashtag.js vendored

Binary file not shown.

BIN
public/js/home.chunk.1d1e6fe050aaaf98.js vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/landing.js vendored

Binary file not shown.

BIN
public/js/manifest.js vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/post.chunk.af21320999ba64af.js vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/profile.js vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/js/search.js vendored

Binary file not shown.

BIN
public/js/spa.js vendored

Binary file not shown.

BIN
public/js/status.js vendored

Binary file not shown.

BIN
public/js/stories.js vendored

Binary file not shown.

Binary file not shown.

BIN
public/js/timeline.js vendored

Binary file not shown.

BIN
public/js/vendor.js vendored

Binary file not shown.

View file

@ -31,13 +31,13 @@
*/ */
/*! /*!
* Cropper.js v1.6.1 * Cropper.js v1.6.2
* https://fengyuanchen.github.io/cropperjs * https://fengyuanchen.github.io/cropperjs
* *
* Copyright 2015-present Chen Fengyuan * Copyright 2015-present Chen Fengyuan
* Released under the MIT license * Released under the MIT license
* *
* Date: 2023-09-17T03:44:19.860Z * Date: 2024-04-21T07:43:05.335Z
*/ */
/*! /*!
@ -63,13 +63,6 @@
* @license MIT * @license MIT
*/ */
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*! /*!
* Vue.js v2.7.16 * Vue.js v2.7.16
* (c) 2014-2023 Evan You * (c) 2014-2023 Evan You
@ -159,16 +152,6 @@ and limitations under the License.
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */ /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! queue-microtask. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! run-parallel. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! simple-peer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! simple-websocket. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/** /**
* vue-class-component v7.2.3 * vue-class-component v7.2.3
* (c) 2015-present Evan You * (c) 2015-present Evan You
@ -184,23 +167,6 @@ and limitations under the License.
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/ */
/**
* @license Apache-2.0
* Copyright 2018 Novage LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** /**
* filesize * filesize
* *

Binary file not shown.

View file

@ -112,14 +112,17 @@
import Sidebar from './partials/sidebar.vue'; import Sidebar from './partials/sidebar.vue';
import Placeholder from './partials/placeholders/DirectMessagePlaceholder.vue'; import Placeholder from './partials/placeholders/DirectMessagePlaceholder.vue';
import Intersect from 'vue-intersect' import Intersect from 'vue-intersect'
import Autocomplete from '@trevoreyre/autocomplete-vue'
import '@trevoreyre/autocomplete-vue/dist/style.css';
export default { export default {
components: { components: {
"drawer": Drawer, "drawer": Drawer,
"sidebar": Sidebar, "sidebar": Sidebar,
"intersect": Intersect, "intersect": Intersect,
"dm-placeholder": Placeholder "dm-placeholder": Placeholder,
}, "autocomplete": Autocomplete
},
data() { data() {
return { return {

View file

@ -456,7 +456,9 @@
// objDiv.scrollTop = objDiv.scrollHeight; // objDiv.scrollTop = objDiv.scrollHeight;
// }, 300); // }, 300);
}).catch(err => { }).catch(err => {
if(err.response.status == 403) { if(err.response.status == 400) {
swal('Error', err.response.data.error, 'error');
} else if(err.response.status == 403) {
self.blocked = true; self.blocked = true;
swal('Profile Unavailable', 'You cannot message this profile at this time.', 'error'); swal('Profile Unavailable', 'You cannot message this profile at this time.', 'error');
} }

View file

@ -1,196 +1,14 @@
<template> <template>
<div class="web-wrapper"> <div class="web-wrapper">
<div v-if="isLoaded" class="container-fluid mt-3"> <div class="container-fluid mt-3">
<div class="row"> <div class="row">
<div class="col-md-4 col-lg-3"> <div class="col-md-4 col-lg-3">
<sidebar :user="profile" /> <sidebar :user="profile" />
</div> </div>
<div v-if="tab == 'index'" class="col-md-8 col-lg-9 mt-n4"> <div class="col-md-8 col-lg-9 mt-n4">
<div v-if="profile.is_admin" class="d-md-flex my-md-3">
<grid-card
:dark="true"
:title="'Hello ' + profile.username"
subtitle="Welcome to the new Discover experience! Only admins can see this"
button-text="Manage Discover Settings"
button-link="/i/web/discover/settings"
icon-class="fal fa-cog"
:small="true" />
</div>
<!-- <section class="mb-1 mb-md-3 mb-lg-4">
<news-slider />
</section> -->
<!-- <discover-spotlight /> -->
<!-- <div class="d-md-flex my-md-3">
<grid-card
:dark="true"
title="The Not So Trending"
subtitle="Explore the posts that deserve more attention"
button-text="Explore posts"
icon-class="fal fa-analytics"
button-link="/i/web/discover/future-trending"
:button-event="true"
v-on:btn-click="toggleTab('trending')"
:small="true" />
<grid-card
title="Behind The Posts"
subtitle="Discover the people"
button-text="Discover People"
button-link="/i/web/discover/people"
icon-class="fal fa-user-friends"
:small="true" />
</div> -->
<daily-trending v-on:btn-click="toggleTab('trending')"/>
<!-- <div class="d-md-flex my-md-3">
<grid-card
title="Explore Loops"
subtitle="Loops are short, looping videos"
button-text="Explore Loops"
icon-class="fal fa-camcorder"
button-link="/i/web/discover/loops"
:small="false" />
<grid-card
:dark="true"
title="Popular Places"
subtitle="Explore posts by popular locations"
button-text="Explore Popular Places"
icon-class="fal fa-map"
:button-event="true"
v-on:btn-click="toggleTab('popular-places')"
button-link="/i/web/discover/popular-places"
:small="false" />
</div> -->
<div class="d-md-flex my-md-3">
<grid-card
v-if="config.hashtags.enabled"
:dark="true"
title="My Hashtags"
subtitle="Explore posts tagged with hashtags you follow"
button-text="Explore Posts"
button-link="/i/web/discover/my-hashtags"
icon-class="fal fa-hashtag"
:small="false" />
<grid-card
v-if="config.memories.enabled"
title="My Memories"
subtitle="A distant look back"
button-text="View Memories"
button-link="/i/web/discover/my-memories"
icon-class="fal fa-history"
:small="false" />
</div>
<div class="d-md-flex my-md-3">
<grid-card
v-if="config.insights.enabled"
title="Account Insights"
subtitle="Get a rich overview of your account activity and interactions"
button-text="View Account Insights"
icon-class="fal fa-user-circle"
button-link="/i/web/discover/account-insights"
:small="false" />
<grid-card
v-if="config.friends.enabled"
:dark="true"
title="Find Friends"
subtitle="Find accounts to follow based on common interests"
button-text="Find Friends & Followers"
button-link="/i/web/discover/find-friends"
icon-class="fal fa-user-plus"
:small="false" />
</div>
<div class="d-md-flex my-md-3">
<grid-card
v-if="config.server.enabled && config.server.domains && config.server.domains.length"
:dark="true"
title="Server Timelines"
subtitle="Browse timelines of a specific remote instance"
button-text="Browse Server Feeds"
icon-class="fal fa-list"
button-link="/i/web/discover/server-timelines"
:small="false" />
<!-- <grid-card
title="Curate the Spotlight"
subtitle="Apply to curate the spotlight for one week"
button-text="Apply to Curate Spotlight"
button-link="/i/web/discover/spotlight/curate/apply"
icon-class="fal fa-thumbs-up"
:small="false" /> -->
</div>
</div>
<div v-else-if="tab == 'trending'" class="col-md-8 col-lg-9 mt-n4">
<discover :profile="profile" /> <discover :profile="profile" />
</div> </div>
<div v-else-if="tab == 'popular-places'" class="col-md-8 col-lg-9 mt-n4">
<section class="mt-3 mb-5 section-explore">
<div class="profile-timeline">
<div class="row p-0 mt-5">
<div class="col-12 mb-4 d-flex justify-content-between align-items-center">
<p class="d-block d-md-none h1 font-weight-bold mb-0 font-default">Popular Places</p>
<p class="d-none d-md-block display-4 font-weight-bold mb-0 font-default">Popular Places</p>
</div>
</div>
</div>
<div class="row mt-5">
<div class="col-12 col-md-12 mb-3">
<div class="card-img big">
<img src="/img/places/nyc.jpg">
<div class="title font-default">New York City</div>
</div>
</div>
<div class="col-12 col-md-6 mb-3">
<div class="card-img">
<img src="/img/places/edmonton.jpg">
<div class="title font-default">Edmonton</div>
</div>
</div>
<div class="col-12 col-md-6 mb-3">
<div class="card-img">
<img src="/img/places/paris.jpg">
<div class="title font-default">Paris</div>
</div>
</div>
<div class="col-12 col-md-4 mb-3">
<div class="card-img">
<img src="/img/places/london.jpg">
<div class="title font-default">London</div>
</div>
</div>
<div class="col-12 col-md-4 mb-3">
<div class="card-img">
<img src="/img/places/vancouver.jpg">
<div class="title font-default">Vancouver</div>
</div>
</div>
<div class="col-12 col-md-4 mb-3">
<div class="card-img">
<img src="/img/places/toronto.jpg">
<div class="title font-default">Toronto</div>
</div>
</div>
</div>
</section>
</div>
</div> </div>
<drawer /> <drawer />
@ -201,205 +19,23 @@
<script type="text/javascript"> <script type="text/javascript">
import Drawer from './partials/drawer.vue'; import Drawer from './partials/drawer.vue';
import Sidebar from './partials/sidebar.vue'; import Sidebar from './partials/sidebar.vue';
import Rightbar from './partials/rightbar.vue';
import Discover from './sections/DiscoverFeed.vue'; import Discover from './sections/DiscoverFeed.vue';
import DiscoverNewsSlider from './partials/discover/news-slider.vue';
import DiscoverSpotlight from './partials/discover/discover-spotlight.vue';
import DailyTrending from './partials/discover/daily-trending.vue';
import DiscoverGridCard from './partials/discover/grid-card.vue';
export default { export default {
components: { components: {
"drawer": Drawer, "drawer": Drawer,
"sidebar": Sidebar, "sidebar": Sidebar,
"rightbar": Rightbar,
"discover": Discover, "discover": Discover,
"news-slider": DiscoverNewsSlider,
"discover-spotlight": DiscoverSpotlight,
"daily-trending": DailyTrending,
"grid-card": DiscoverGridCard
}, },
data() { data() {
return { return {
isLoaded: false,
profile: undefined, profile: undefined,
config: {},
tab: 'index',
popularAccounts: [],
followingIndex: undefined
} }
}, },
updated() {
// let u = new URLSearchParams(window.location.search);
// if(u.has('ft') && u.get('ft') == '1') {
// this.tab = 'index';
// }
},
mounted() { mounted() {
this.profile = window._sharedData.user; this.profile = window._sharedData.user;
this.fetchConfig();
},
methods: {
fetchConfig() {
axios.get('/api/pixelfed/v2/discover/meta')
.then(res => {
this.config = res.data;
this.isLoaded = true;
window._sharedData.discoverMeta = res.data;
// this.fetchPopularAccounts();
})
},
fetchPopularAccounts() {
// axios.get('/api/pixelfed/discover/accounts/popular')
// .then(res => {
// this.popularAccounts = res.data;
// })
},
followProfile(index) {
event.currentTarget.blur();
this.followingIndex = index;
let id = this.popularAccounts[index].id;
axios.post('/api/v1/accounts/' + id + '/follow')
.then(res => {
this.followingIndex = undefined;
this.popularAccounts.splice(index, 1);
}).catch(err => {
this.followingIndex = undefined;
swal('Oops!', 'An error occured when attempting to follow this account.', 'error');
});
},
goToProfile(account) {
this.$router.push({
path: `/i/web/profile/${account.id}`,
params: {
id: account.id,
cachedProfile: account,
cachedUser: this.profile
}
})
},
toggleTab(index) {
this.tab = index;
setTimeout(() => {
window.scrollTo({top: 0, behavior: 'smooth'});
}, 300);
},
openManageModal() {
event.currentTarget.blur();
swal('Settings', 'Discover settings here', 'info');
}
} }
} }
</script> </script>
<style lang="scss" scoped>
.card-img {
position: relative;
img {
object-fit: cover;
width: 100%;
height: 200px;
border-radius: 10px;
}
&:before,
&:after {
content: "";
background: rgba(0,0,0,0.2);
z-index: 2;
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
border-radius: 10px;
}
.title {
position: absolute;
bottom: 5px;
left: 10px;
font-size: 40px;
color: #fff;
z-index: 3;
font-weight: 700;
}
&.big {
img {
height: 300px;
}
}
}
.font-default {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
letter-spacing: -0.7px;
}
.bg-stellar {
background: #7474BF;
background: -webkit-linear-gradient(to right, #348AC7, #7474BF);
background: linear-gradient(to right, #348AC7, #7474BF);
}
.bg-berry {
background: #5433FF;
background: -webkit-linear-gradient(to right, #acb6e5, #86fde8);
background: linear-gradient(to right, #acb6e5, #86fde8);
}
.bg-midnight {
background: #232526;
background: -webkit-linear-gradient(to right, #414345, #232526);
background: linear-gradient(to right, #414345, #232526);
}
.media-body {
margin-right: 0.5rem;
}
.avatar {
border-radius: 15px;
}
.username {
font-size: 14px;
line-height: 14px;
margin-bottom: 2px;
word-break: break-word !important;
word-wrap: break-word !important;
}
.display-name {
margin-bottom: 0;
font-size: 12px;
word-break: break-word !important;
word-wrap: break-word !important;
}
.follower-count {
margin-bottom: 0;
font-size: 10px;
word-break: break-word !important;
word-wrap: break-word !important;
}
.follow {
background-color: var(--primary);
border-radius: 18px;
font-weight: 600;
padding: 5px 15px;
}
</style>

View file

@ -209,8 +209,8 @@
permissionChecked: false, permissionChecked: false,
membershipCategories: [ membershipCategories: [
{ key: 'Public', value: 'public' }, { key: 'Public', value: 'public' },
{ key: 'Private', value: 'private' }, // { key: 'Private', value: 'private' },
{ key: 'Local', value: 'local' }, // { key: 'Local', value: 'local' },
], ],
} }
}, },

View file

@ -343,7 +343,8 @@
childReplyContent: null, childReplyContent: null,
postingChildComment: false, postingChildComment: false,
loadingChildComments: false, loadingChildComments: false,
replyChildMinId: undefined replyChildMinId: undefined,
replyCursorId: null
} }
}, },
@ -584,6 +585,7 @@
} }
this.replyChildId = status.id; this.replyChildId = status.id;
this.replyCursorId = status.id
this.replyChildIndex = index; this.replyChildIndex = index;
if(!status.hasOwnProperty('replies_loaded') || !status.replies_loaded) { if(!status.hasOwnProperty('replies_loaded') || !status.replies_loaded) {
@ -591,7 +593,9 @@
this.fetchChildReplies(status, index); this.fetchChildReplies(status, index);
}); });
} else { } else {
this.$nextTick(() => {
this.fetchChildReplies(status, index);
});
} }
}, },
@ -600,7 +604,7 @@
params: { params: {
gid: this.groupId, gid: this.groupId,
sid: status.id, sid: status.id,
cid: 1, cid: this.replyCursorId,
limit: 3 limit: 3
} }
}).then(res => { }).then(res => {

View file

@ -17,6 +17,7 @@
:profile="profile" :profile="profile"
:showGroupHeader="showGroupHeader" :showGroupHeader="showGroupHeader"
:showGroupChevron="showGroupChevron" :showGroupChevron="showGroupChevron"
v-on:delete="statusDeleted"
/> />
<div> <div>

View file

@ -1,63 +1,50 @@
<template> <template>
<div class="col-12 col-md-9" style="overflow:hidden"> <div class="col-12 col-md-9" style="overflow:hidden">
<div class="row h-100 bg-light justify-content-center"> <div class="row bg-light justify-content-center">
<div class="col-12 col-md-10 col-lg-7"> <div class="col-12 flex-shrink-1">
<div v-if="!initalLoad"> <div class="my-4 px-3">
<p class="text-center mt-5 pt-5 font-weight-bold">Loading...</p> <p class="h1 font-weight-bold mb-1">Groups Feed</p>
</div> <p class="lead text-muted mb-0">Recent posts from your groups</p>
<div v-else class="px-5"> </div>
<div v-if="emptyFeed"> </div>
<div class="jumbotron mt-5"> </div>
<h1 class="display-4">Hello 👋</h1> <div class="row h-100 bg-light justify-content-center">
<h3 class="font-weight-light">Welcome to Pixelfed Groups!</h3> <div class="col-12 col-md-10 col-lg-6">
<p class="lead">Groups are a way to participate in like minded communities and topics.</p> <div v-if="emptyFeed" class="mt-5">
<hr class="my-4"> <h1 class="font-weight-bold">Welcome to Pixelfed Groups!</h1>
<p>Anyone can create and manage their own group as long as it abides by our <a href="#">community guidelines</a>.</p> <p class="lead">Groups are a way to participate in like minded communities and topics.</p>
<p class="text-center mb-0"> <hr class="my-4">
<router-link to="/groups/discover" class="btn btn-primary btn-lg rounded-pill"> <p>Anyone can create and manage their own group as long as it abides by our <a href="/site/kb/community-guidelines" target="_blank">community guidelines</a>.</p>
Discover Groups <p class="text-center mb-0">
</router-link> <router-link to="/groups/discover" class="btn btn-primary btn-lg rounded-pill">
</p> Discover Groups
</div> </router-link>
</div> </p>
</div>
<div v-else> <div v-else>
<div class="my-4"> <div class="my-3">
<p class="h1 font-weight-bold mb-1">Groups Feed</p> <group-status
<p class="lead text-muted mb-0">Recent posts from your groups</p> v-for="(status, index) in feed"
</div> :key="'gs:' + status.id + index"
:prestatus="status"
:profile="profile"
:show-group-header="true"
:group="status.group"
:group-id="status.group.id" />
<div class="my-3"> <div v-if="feed.length > 2">
<group-status <infinite-loading @infinite="infiniteFeed" :distance="800">
v-for="(status, index) in feed" <div slot="no-more" class="my-3">
:key="'gs:' + status.id + index" <p class="lead font-weight-bold pt-5">You have reached the end of this feed</p>
:prestatus="status" <div style="height: 10rem;"></div>
:profile="profile" </div>
:show-group-header="true" <div slot="no-results"></div>
:group="status.group" </infinite-loading>
:group-id="status.group.id" /> </div>
</div>
<div v-if="feed.length > 2"> </div>
<infinite-loading @infinite="infiniteFeed" :distance="800"> </div>
<div slot="no-more" class="my-3">
<p class="lead font-weight-bold pt-5">You have reached the end of this feed</p>
<div style="height: 10rem;"></div>
</div>
<div slot="no-results"></div>
</infinite-loading>
</div>
</div>
</div>
</div>
</div>
<!-- <div class="col-12 col-md-4">
<div class="mt-5 media align-items-center">
<div class="mr-3">
<i class="fas fa-info-circle fa-2x text-lighter"></i>
</div>
<p class="media-body text-muted mb-0 font-weight-light">Groups are in beta, some <a href="#" class="font-weight-bold">limitations</a> apply.</p>
</div>
</div> -->
</div> </div>
</div> </div>
</template> </template>

View file

@ -110,12 +110,12 @@
<span class="fas fa-ellipsis-h text-lighter"></span> <span class="fas fa-ellipsis-h text-lighter"></span>
</button> </button>
<div class="dropdown-menu dropdown-menu-right"> <div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item" href="#">View Post</a> <a class="dropdown-item" :href="statusUrl()">View Post</a>
<a class="dropdown-item" href="#">View Profile</a> <a class="dropdown-item" :href="profileUrl()">View Profile</a>
<a class="dropdown-item" href="#">Copy Link</a> <!-- <a class="dropdown-item" href="#">Copy Link</a> -->
<a class="dropdown-item" href="#" @click.prevent="sendReport()">Report</a> <a class="dropdown-item" href="#" @click.prevent="sendReport()">Report</a>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<a class="dropdown-item text-danger" href="#">Delete</a> <a class="dropdown-item text-danger" href="#" @click.prevent="onDelete()">Delete</a>
</div> </div>
</div> </div>
<!-- <button class="btn btn-link text-dark py-0" type="button" @click="ctxMenu()"> <!-- <button class="btn btn-link text-dark py-0" type="button" @click="ctxMenu()">
@ -171,12 +171,12 @@
return App.util.format.count(count); return App.util.format.count(count);
}, },
statusUrl(status) { statusUrl() {
return '/groups/' + status.gid + '/p/' + status.id; return '/groups/' + this.status.gid + '/p/' + this.status.id;
}, },
profileUrl(status) { profileUrl() {
return '/groups/' + status.gid + '/user/' + status.account.id; return '/groups/' + this.status.gid + '/user/' + this.status.account.id;
}, },
timestampFormat(timestamp) { timestampFormat(timestamp) {
@ -268,6 +268,28 @@
swal("Cancelled", "Your report was not submitted.", "error"); swal("Cancelled", "Your report was not submitted.", "error");
} }
}); });
},
onDelete() {
swal({
title: "Delete Post Confirmation",
text: 'Are you sure you want to delete this post?',
icon: "warning",
dangerMode: true,
buttons: true
}).then((confirm) => {
if(confirm) {
axios.post('/api/v0/groups/status/delete', {
id: this.status.id,
gid: this.status.gid,
})
.then(res => {
this.$emit('delete', this.status)
})
.catch(err => {
console.log(err)
})
}
});
} }
} }
} }

View file

@ -275,6 +275,7 @@
v-on:likes-modal="openLikesModal(index)" v-on:likes-modal="openLikesModal(index)"
v-on:shares-modal="openSharesModal(index)" v-on:shares-modal="openSharesModal(index)"
v-on:comment-likes-modal="openCommentLikesModal" v-on:comment-likes-modal="openCommentLikesModal"
v-on:bookmark="handleBookmark(index)"
v-on:handle-report="handleReport" /> v-on:handle-report="handleReport" />
</div> </div>
@ -845,6 +846,32 @@
}) })
}, },
handleBookmark(index) {
let p = this.feed[index];
if(p.reblog) {
p = p.reblog;
}
axios.post('/i/bookmark', {
item: p.id
})
.then(res => {
if(this.feed[index].reblog) {
this.feed[index].reblog.bookmarked = !p.bookmarked;
} else {
this.feed[index].bookmarked = !p.bookmarked;
}
})
.catch(err => {
this.$bvToast.toast('Cannot bookmark post at this time.', {
title: 'Bookmark Error',
variant: 'danger',
autoHideDelay: 5000
});
});
},
formatCount(val) { formatCount(val) {
return App.util.format.count(val); return App.util.format.count(val);
}, },

View file

@ -45,8 +45,6 @@
import Hls from 'hls.js'; import Hls from 'hls.js';
import "plyr/dist/plyr.css"; import "plyr/dist/plyr.css";
import Plyr from 'plyr'; import Plyr from 'plyr';
import { p2pml } from '@peertube/p2p-media-loader-core'
import { Engine, initHlsJsPlayer } from '@peertube/p2p-media-loader-hlsjs'
export default { export default {
props: ['status', 'fixedHeight'], props: ['status', 'fixedHeight'],
@ -72,8 +70,8 @@
methods: { methods: {
handleShouldPlay(){ handleShouldPlay(){
this.shouldPlay = true; this.shouldPlay = true;
this.isHlsSupported = this.hlsConfig.enabled && Hls.isSupported(); this.isHlsSupported = false;
this.isP2PSupported = this.hlsConfig.enabled && this.hlsConfig.p2p && Engine.isSupported(); this.isP2PSupported = false;
this.$nextTick(() => { this.$nextTick(() => {
this.init(); this.init();
}) })

View file

@ -1,12 +1,10 @@
<template> <template>
<div class="discover-feed-component"> <div class="discover-feed-component">
<section class="mt-3 mb-5 section-explore"> <section class="mt-3 mb-5 section-explore">
<b-breadcrumb class="font-default" :items="breadcrumbItems"></b-breadcrumb>
<div class="profile-timeline"> <div class="profile-timeline">
<div class="row p-0 mt-5"> <div class="row p-0 mt-5">
<div class="col-12 mb-4 d-flex justify-content-between align-items-center"> <div class="col-12 mb-4 d-flex justify-content-between align-items-center flex-column flex-lg-row">
<p class="d-block d-md-none h1 font-weight-bold mb-0 font-default">Trending</p> <p class="d-block d-md-none h1 font-weight-bold mb-3 font-default">Trending</p>
<p class="d-none d-md-block display-4 font-weight-bold mb-0 font-default">Trending</p> <p class="d-none d-md-block display-4 font-weight-bold mb-0 font-default">Trending</p>
<div> <div>

View file

@ -302,53 +302,6 @@
v-on:likeStatus="likeStatus" /> v-on:likeStatus="likeStatus" />
<comment-feed :status="status" class="mt-3" /> <comment-feed :status="status" class="mt-3" />
<!-- <div v-if="user.hasOwnProperty('id')" class="card card-body shadow-none border border-top-0 bg-light">
<div class="media">
<img src="/storage/avatars/default.png" class="rounded-circle mr-2" width="40" height="40">
<div class="media-body">
<div class="form-group mb-0" style="position:relative;">
<input class="form-control rounded-pill" placeholder="Add a comment..." style="padding-right: 90px;">
<div class="btn btn-primary btn-sm rounded-pill font-weight-bold px-3" style="position:absolute;top: 5px;right:6px;">Post</div>
</div>
</div>
</div>
</div>
<div v-if="user.hasOwnProperty('id')" v-for="(reply, index) in results" :key="'replies:'+index" class="card card-body shadow-none border border-top-0">
<div class="media">
<img :src="reply.account.avatar" class="rounded-circle border mr-3" width="32px" height="32px">
<div class="media-body">
<div v-if="reply.sensitive == true">
<span class="py-3">
<a class="text-dark font-weight-bold mr-3" style="font-size: 13px;" :href="profileUrl(reply)" v-bind:title="reply.account.username">{{trimCaption(reply.account.username,15)}}</a>
<span class="text-break" style="font-size: 13px;">
<span class="font-italic text-muted">This comment may contain sensitive material</span>
<span class="text-primary cursor-pointer pl-1" @click="reply.sensitive = false;">Show</span>
</span>
</span>
</div>
<div v-else>
<p class="d-flex justify-content-between align-items-top read-more mb-0" style="overflow-y: hidden;">
<span class="mr-3" style="font-size: 13px;">
<a class="text-dark font-weight-bold mr-1 text-break" :href="profileUrl(reply)" v-bind:title="reply.account.username">{{trimCaption(reply.account.username,15)}}</a>
<span class="text-break comment-body" style="word-break: break-all;" v-html="reply.content"></span>
</span>
<span class="text-right" style="min-width: 30px;">
<span v-on:click="likeReply(reply, $event)"><i v-bind:class="[reply.favourited ? 'fas fa-heart fa-sm text-danger':'far fa-heart fa-sm text-lighter']"></i></span>
<span class="pl-2 text-lighter cursor-pointer" @click="ctxMenu(reply)">
<span class="fas fa-ellipsis-v text-lighter"></span>
</span>
</span>
</p>
<p class="mb-0">
<a v-once class="text-muted mr-3 text-decoration-none small" style="width: 20px;" v-text="timeAgo(reply.created_at)" :href="getStatusUrl(reply)"></a>
<span v-if="reply.favourites_count" class="text-muted comment-reaction font-weight-bold mr-3 small">{{reply.favourites_count == 1 ? '1 like' : reply.favourites_count + ' likes'}}</span>
<span class="small text-muted comment-reaction font-weight-bold cursor-pointer" v-on:click="replyFocus(reply, index, true)">Reply</span>
</p>
</div>
</div>
</div>
</div> -->
</div> </div>
</div> </div>
</div> </div>
@ -660,85 +613,85 @@ export default {
}, },
data() { data() {
return { return {
config: window.App.config, config: window.App.config,
status: false, status: false,
media: {}, media: {},
user: false, user: false,
reactions: { reactions: {
liked: false, liked: false,
shared: false shared: false
}, },
likes: [], likes: [],
likesCursor: null, likesCursor: null,
likesCanLoadMore: true, likesCanLoadMore: true,
likedLoaded: false, likedLoaded: false,
shares: [], shares: [],
lightboxMedia: false, lightboxMedia: false,
replyText: '', replyText: '',
replyStatus: {}, replyStatus: {},
replySensitive: false, replySensitive: false,
relationship: {}, relationship: {},
results: [], results: [],
pagination: {}, pagination: {},
min_id: 0, min_id: 0,
max_id: 0, max_id: 0,
reply_to_profile_id: 0, reply_to_profile_id: 0,
thread: false, thread: false,
showComments: false, showComments: false,
warning: false, warning: false,
loaded: false, loaded: false,
loading: null, loading: null,
replyingToId: this.statusId, replyingToId: this.statusId,
replyingToUsername: this.statusUsername, replyingToUsername: this.statusUsername,
replyToIndex: 0, replyToIndex: 0,
replySending: false, replySending: false,
emoji: window.App.util.emoji, emoji: window.App.util.emoji,
showReadMore: true, showReadMore: true,
showCaption: true, showCaption: true,
ctxEmbedPayload: false, ctxEmbedPayload: false,
copiedEmbed: false, copiedEmbed: false,
ctxEmbedShowCaption: true, ctxEmbedShowCaption: true,
ctxEmbedShowLikes: false, ctxEmbedShowLikes: false,
ctxEmbedCompactMode: false, ctxEmbedCompactMode: false,
layout: this.profileLayout, layout: this.profileLayout,
showProfileMorePosts: false, showProfileMorePosts: false,
profileMorePosts: [], profileMorePosts: [],
reactionBarLoading: true, reactionBarLoading: true,
tributeSettings: { tributeSettings: {
collection: [ collection: [
{ {
trigger: '@', trigger: '@',
menuShowMinLength: 2, menuShowMinLength: 2,
values: (function (text, cb) { values: (function (text, cb) {
let url = '/api/compose/v0/search/mention'; let url = '/api/compose/v0/search/mention';
axios.get(url, { params: { q: text }}) axios.get(url, { params: { q: text }})
.then(res => { .then(res => {
cb(res.data); cb(res.data);
})
.catch(err => {
console.log(err);
})
}) })
}, .catch(err => {
{ console.log(err);
trigger: '#',
menuShowMinLength: 2,
values: (function (text, cb) {
let url = '/api/compose/v0/search/hashtag';
axios.get(url, { params: { q: text }})
.then(res => {
cb(res.data);
})
.catch(err => {
console.log(err);
})
}) })
} })
] },
}, {
content: undefined trigger: '#',
} menuShowMinLength: 2,
values: (function (text, cb) {
let url = '/api/compose/v0/search/hashtag';
axios.get(url, { params: { q: text }})
.then(res => {
cb(res.data);
})
.catch(err => {
console.log(err);
})
})
}
]
},
content: undefined
}
}, },
watch: { watch: {
ctxEmbedShowCaption: function (n,o) { ctxEmbedShowCaption: function (n,o) {
@ -1424,7 +1377,15 @@ export default {
}, },
previewUrl(status) { previewUrl(status) {
return status.sensitive ? '/storage/no-preview.png?v=' + new Date().getTime() : status.media_attachments[0].preview_url; if(status.sensitive) {
return '/storage/no-preview.png';
}
if(status.media_attachments[0]?.optimized_url) {
return status.media_attachments[0]?.optimized_url;
}
return status.media_attachments[0].preview_url;
}, },
previewBackground(status) { previewBackground(status) {

View file

@ -140,6 +140,10 @@ body {
z-index: 2; z-index: 2;
} }
.fw-bold {
font-weight: bold;
}
.navbar-light .navbar-brand { .navbar-light .navbar-brand {
color: var(--dark); color: var(--dark);