mirror of
https://github.com/pixelfed/pixelfed.git
synced 2025-01-12 07:00:45 +00:00
commit
aad77239a9
21 changed files with 1290 additions and 816 deletions
|
@ -49,6 +49,13 @@
|
||||||
- Updated MediaStorageService, improve head checks to fix failed jobs. ([1769cdfd](https://github.com/pixelfed/pixelfed/commit/1769cdfd))
|
- Updated MediaStorageService, improve head checks to fix failed jobs. ([1769cdfd](https://github.com/pixelfed/pixelfed/commit/1769cdfd))
|
||||||
- Updated user admin, remove expensive db query and add search. ([8feeadbf](https://github.com/pixelfed/pixelfed/commit/8feeadbf))
|
- Updated user admin, remove expensive db query and add search. ([8feeadbf](https://github.com/pixelfed/pixelfed/commit/8feeadbf))
|
||||||
- Updated Compose apis, prevent private accounts from posting public or unlisted scopes. ([f53bfa6f](https://github.com/pixelfed/pixelfed/commit/f53bfa6f))
|
- Updated Compose apis, prevent private accounts from posting public or unlisted scopes. ([f53bfa6f](https://github.com/pixelfed/pixelfed/commit/f53bfa6f))
|
||||||
|
- Updated font icons, use font-display:swap. ([77d4353a](https://github.com/pixelfed/pixelfed/commit/77d4353a))
|
||||||
|
- Updated ComposeModal, limit visibility scope for private accounts. ([001d4105](https://github.com/pixelfed/pixelfed/commit/001d4105))
|
||||||
|
- Updated ComposeController, add autocomplete apis for hashtags and mentions. ([f0e48a09](https://github.com/pixelfed/pixelfed/commit/f0e48a09))
|
||||||
|
- Updated StatusController, invalidate profile embed cache on status delete. ([9c8a87c3](https://github.com/pixelfed/pixelfed/commit/9c8a87c3))
|
||||||
|
- Updated moderation api, invalidate profile embed. ([b2501bfc](https://github.com/pixelfed/pixelfed/commit/b2501bfc))
|
||||||
|
- Updated Nodeinfo util, use last_active_at for monthly active user count. ([d200c12c](https://github.com/pixelfed/pixelfed/commit/d200c12c))
|
||||||
|
- Updated PhotoPresenter, add width and height to images. ([3f8202e2](https://github.com/pixelfed/pixelfed/commit/3f8202e2))
|
||||||
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
||||||
|
|
||||||
## [v0.10.10 (2021-01-28)](https://github.com/pixelfed/pixelfed/compare/v0.10.9...v0.10.10)
|
## [v0.10.10 (2021-01-28)](https://github.com/pixelfed/pixelfed/compare/v0.10.9...v0.10.10)
|
||||||
|
|
|
@ -7,6 +7,7 @@ use Auth, Cache, Storage, URL;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use App\{
|
use App\{
|
||||||
Avatar,
|
Avatar,
|
||||||
|
Hashtag,
|
||||||
Like,
|
Like,
|
||||||
Media,
|
Media,
|
||||||
MediaTag,
|
MediaTag,
|
||||||
|
@ -304,6 +305,72 @@ class ComposeController extends Controller
|
||||||
return $places;
|
return $places;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function searchMentionAutocomplete(Request $request)
|
||||||
|
{
|
||||||
|
abort_if(!$request->user(), 403);
|
||||||
|
|
||||||
|
$this->validate($request, [
|
||||||
|
'q' => 'required|string|min:2|max:50'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$q = $request->input('q');
|
||||||
|
|
||||||
|
if(Str::of($q)->startsWith('@')) {
|
||||||
|
if(strlen($q) < 3) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$blocked = UserFilter::whereFilterableType('App\Profile')
|
||||||
|
->whereFilterType('block')
|
||||||
|
->whereFilterableId($request->user()->profile_id)
|
||||||
|
->pluck('user_id');
|
||||||
|
|
||||||
|
$blocked->push($request->user()->profile_id);
|
||||||
|
|
||||||
|
$results = Profile::select('id','domain','username')
|
||||||
|
->whereNotIn('id', $blocked)
|
||||||
|
->where('username','like','%'.$q.'%')
|
||||||
|
->groupBy('domain')
|
||||||
|
->limit(15)
|
||||||
|
->get()
|
||||||
|
->map(function($profile) {
|
||||||
|
$username = $profile->domain ? substr($profile->username, 1) : $profile->username;
|
||||||
|
return [
|
||||||
|
'key' => '@' . str_limit($username, 30),
|
||||||
|
'value' => $username,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function searchHashtagAutocomplete(Request $request)
|
||||||
|
{
|
||||||
|
abort_if(!$request->user(), 403);
|
||||||
|
|
||||||
|
$this->validate($request, [
|
||||||
|
'q' => 'required|string|min:2|max:50'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$q = $request->input('q');
|
||||||
|
|
||||||
|
$results = Hashtag::select('slug')
|
||||||
|
->where('slug', 'like', '%'.$q.'%')
|
||||||
|
->whereIsNsfw(false)
|
||||||
|
->whereIsBanned(false)
|
||||||
|
->limit(5)
|
||||||
|
->get()
|
||||||
|
->map(function($tag) {
|
||||||
|
return [
|
||||||
|
'key' => '#' . $tag->slug,
|
||||||
|
'value' => $tag->slug
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
|
|
|
@ -132,13 +132,15 @@ class InternalApiController extends Controller
|
||||||
|
|
||||||
public function statusReplies(Request $request, int $id)
|
public function statusReplies(Request $request, int $id)
|
||||||
{
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'limit' => 'nullable|int|min:1|max:6'
|
||||||
|
]);
|
||||||
$parent = Status::whereScope('public')->findOrFail($id);
|
$parent = Status::whereScope('public')->findOrFail($id);
|
||||||
|
$limit = $request->input('limit') ?? 3;
|
||||||
$children = Status::whereInReplyToId($parent->id)
|
$children = Status::whereInReplyToId($parent->id)
|
||||||
->orderBy('created_at', 'desc')
|
->orderBy('created_at', 'desc')
|
||||||
->take(3)
|
->take($limit)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
$resource = new Fractal\Resource\Collection($children, new StatusTransformer());
|
$resource = new Fractal\Resource\Collection($children, new StatusTransformer());
|
||||||
$res = $this->fractal->createData($resource)->toArray();
|
$res = $this->fractal->createData($resource)->toArray();
|
||||||
|
|
||||||
|
@ -310,6 +312,10 @@ class InternalApiController extends Controller
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cache::forget('_api:statuses:recent_9:' . $status->profile_id);
|
||||||
|
Cache::forget('profile:embed:' . $status->profile_id);
|
||||||
|
|
||||||
return ['msg' => 200];
|
return ['msg' => 200];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ class PublicApiController extends Controller
|
||||||
->whereNull('reblog_of_id')
|
->whereNull('reblog_of_id')
|
||||||
->whereIn('scope', $scope)
|
->whereIn('scope', $scope)
|
||||||
->whereNotIn('profile_id', $filtered)
|
->whereNotIn('profile_id', $filtered)
|
||||||
->select('id', 'caption', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
|
->select('id', 'caption', 'local', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
|
||||||
->where('id', '>=', $request->min_id)
|
->where('id', '>=', $request->min_id)
|
||||||
->orderBy('id', 'desc')
|
->orderBy('id', 'desc')
|
||||||
->paginate($limit);
|
->paginate($limit);
|
||||||
|
@ -176,7 +176,7 @@ class PublicApiController extends Controller
|
||||||
->whereNull('reblog_of_id')
|
->whereNull('reblog_of_id')
|
||||||
->whereIn('scope', $scope)
|
->whereIn('scope', $scope)
|
||||||
->whereNotIn('profile_id', $filtered)
|
->whereNotIn('profile_id', $filtered)
|
||||||
->select('id', 'caption', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
|
->select('id', 'caption', 'local', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
|
||||||
->where('id', '<=', $request->max_id)
|
->where('id', '<=', $request->max_id)
|
||||||
->orderBy('id', 'desc')
|
->orderBy('id', 'desc')
|
||||||
->paginate($limit);
|
->paginate($limit);
|
||||||
|
@ -186,7 +186,7 @@ class PublicApiController extends Controller
|
||||||
->whereNull('reblog_of_id')
|
->whereNull('reblog_of_id')
|
||||||
->whereIn('scope', $scope)
|
->whereIn('scope', $scope)
|
||||||
->whereNotIn('profile_id', $filtered)
|
->whereNotIn('profile_id', $filtered)
|
||||||
->select('id', 'caption', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
|
->select('id', 'caption', 'local', 'is_nsfw', 'rendered', 'profile_id', 'in_reply_to_id', 'type', 'reply_count', 'created_at')
|
||||||
->orderBy('id', 'desc')
|
->orderBy('id', 'desc')
|
||||||
->paginate($limit);
|
->paginate($limit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,12 @@ class StatusController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$template = $status->in_reply_to_id ? 'status.reply' : 'status.show';
|
$template = $status->in_reply_to_id ? 'status.reply' : 'status.show';
|
||||||
|
// $template = $status->type === 'video' &&
|
||||||
|
// $request->has('video_beta') &&
|
||||||
|
// $request->video_beta == 1 &&
|
||||||
|
// $request->user() ?
|
||||||
|
// 'status.show_video' : 'status.show';
|
||||||
|
|
||||||
return view($template, compact('user', 'status'));
|
return view($template, compact('user', 'status'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,6 +218,7 @@ class StatusController extends Controller
|
||||||
|
|
||||||
Cache::forget('_api:statuses:recent_9:' . $status->profile_id);
|
Cache::forget('_api:statuses:recent_9:' . $status->profile_id);
|
||||||
Cache::forget('profile:status_count:' . $status->profile_id);
|
Cache::forget('profile:status_count:' . $status->profile_id);
|
||||||
|
Cache::forget('profile:embed:' . $status->profile_id);
|
||||||
StatusService::del($status->id);
|
StatusService::del($status->id);
|
||||||
if ($status->profile_id == $user->profile->id || $user->is_admin == true) {
|
if ($status->profile_id == $user->profile->id || $user->is_admin == true) {
|
||||||
Cache::forget('profile:status_count:'.$status->profile_id);
|
Cache::forget('profile:status_count:'.$status->profile_id);
|
||||||
|
|
|
@ -12,24 +12,31 @@ class Nodeinfo {
|
||||||
{
|
{
|
||||||
$res = Cache::remember('api:nodeinfo', now()->addMinutes(15), function () {
|
$res = Cache::remember('api:nodeinfo', now()->addMinutes(15), function () {
|
||||||
$activeHalfYear = Cache::remember('api:nodeinfo:ahy', now()->addHours(12), function() {
|
$activeHalfYear = Cache::remember('api:nodeinfo:ahy', now()->addHours(12), function() {
|
||||||
|
// todo: replace with last_active_at after July 9, 2021 (96afc3e781)
|
||||||
$count = collect([]);
|
$count = collect([]);
|
||||||
$likes = Like::select('profile_id')->with('actor')->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('profile_id')->get()->filter(function($like) {return $like->actor && $like->actor->domain == null;})->pluck('profile_id')->toArray();
|
$likes = Like::select('profile_id')->with('actor')->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('profile_id')->get()->filter(function($like) {return $like->actor && $like->actor->domain == null;})->pluck('profile_id')->toArray();
|
||||||
$count = $count->merge($likes);
|
$count = $count->merge($likes);
|
||||||
$statuses = Status::select('profile_id')->whereLocal(true)->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('profile_id')->pluck('profile_id')->toArray();
|
$statuses = Status::select('profile_id')->whereLocal(true)->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('profile_id')->pluck('profile_id')->toArray();
|
||||||
$count = $count->merge($statuses);
|
$count = $count->merge($statuses);
|
||||||
$profiles = Profile::select('id')->whereNull('domain')->where('created_at', '>', now()->subMonths(6)->toDateTimeString())->groupBy('id')->pluck('id')->toArray();
|
$profiles = User::select('profile_id', 'last_active_at')
|
||||||
|
->whereNotNull('last_active_at')
|
||||||
|
->where('last_active_at', '>', now()->subMonths(6))
|
||||||
|
->pluck('profile_id')
|
||||||
|
->toArray();
|
||||||
|
$newProfiles = User::select('profile_id', 'last_active_at', 'created_at')
|
||||||
|
->whereNull('last_active_at')
|
||||||
|
->where('created_at', '>', now()->subMonths(6))
|
||||||
|
->pluck('profile_id')
|
||||||
|
->toArray();
|
||||||
|
$count = $count->merge($newProfiles);
|
||||||
$count = $count->merge($profiles);
|
$count = $count->merge($profiles);
|
||||||
return $count->unique()->count();
|
return $count->unique()->count();
|
||||||
});
|
});
|
||||||
$activeMonth = Cache::remember('api:nodeinfo:am', now()->addHours(12), function() {
|
$activeMonth = Cache::remember('api:nodeinfo:am', now()->addHours(2), function() {
|
||||||
$count = collect([]);
|
return User::select('last_active_at')
|
||||||
$likes = Like::select('profile_id')->where('created_at', '>', now()->subMonths(1)->toDateTimeString())->groupBy('profile_id')->get()->filter(function($like) {return $like->actor && $like->actor->domain == null;})->pluck('profile_id')->toArray();
|
->where('last_active_at', '>', now()->subMonths(1))
|
||||||
$count = $count->merge($likes);
|
->orWhere('created_at', '>', now()->subMonths(1))
|
||||||
$statuses = Status::select('profile_id')->whereLocal(true)->where('created_at', '>', now()->subMonths(1)->toDateTimeString())->groupBy('profile_id')->pluck('profile_id')->toArray();
|
->count();
|
||||||
$count = $count->merge($statuses);
|
|
||||||
$profiles = Profile::select('id')->whereNull('domain')->where('created_at', '>', now()->subMonths(1)->toDateTimeString())->groupBy('id')->pluck('id')->toArray();
|
|
||||||
$count = $count->merge($profiles);
|
|
||||||
return $count->unique()->count();
|
|
||||||
});
|
});
|
||||||
return [
|
return [
|
||||||
'metadata' => [
|
'metadata' => [
|
||||||
|
|
BIN
public/css/app.css
vendored
BIN
public/css/app.css
vendored
Binary file not shown.
BIN
public/css/appdark.css
vendored
BIN
public/css/appdark.css
vendored
Binary file not shown.
BIN
public/css/landing.css
vendored
BIN
public/css/landing.css
vendored
Binary file not shown.
BIN
public/css/quill.css
vendored
BIN
public/css/quill.css
vendored
Binary file not shown.
BIN
public/js/compose.js
vendored
BIN
public/js/compose.js
vendored
Binary file not shown.
BIN
public/js/profile.js
vendored
BIN
public/js/profile.js
vendored
Binary file not shown.
BIN
public/js/rempos.js
vendored
BIN
public/js/rempos.js
vendored
Binary file not shown.
BIN
public/js/status.js
vendored
BIN
public/js/status.js
vendored
Binary file not shown.
BIN
public/js/timeline.js
vendored
BIN
public/js/timeline.js
vendored
Binary file not shown.
Binary file not shown.
|
@ -479,9 +479,26 @@
|
||||||
|
|
||||||
<div v-if="page == 'visibility'" class="w-100 h-100">
|
<div v-if="page == 'visibility'" class="w-100 h-100">
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
<div :class="'list-group-item lead cursor-pointer ' + [visibility == 'public'?'text-primary':'']" @click="toggleVisibility('public')">Public</div>
|
<div
|
||||||
<div :class="'list-group-item lead cursor-pointer ' + [visibility == 'unlisted'?'text-primary':'']" @click="toggleVisibility('unlisted')">Unlisted</div>
|
v-if="!profile.locked"
|
||||||
<div :class="'list-group-item lead cursor-pointer ' + [visibility == 'private'?'text-primary':'']" @click="toggleVisibility('private')">Followers Only</div>
|
class="list-group-item lead cursor-pointer"
|
||||||
|
:class="{ 'text-primary': visibility == 'public' }"
|
||||||
|
@click="toggleVisibility('public')">
|
||||||
|
Public
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="!profile.locked"
|
||||||
|
class="list-group-item lead cursor-pointer"
|
||||||
|
:class="{ 'text-primary': visibility == 'unlisted' }"
|
||||||
|
@click="toggleVisibility('unlisted')">
|
||||||
|
Unlisted
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="list-group-item lead cursor-pointer"
|
||||||
|
:class="{ 'text-primary': visibility == 'private' }"
|
||||||
|
@click="toggleVisibility('private')">
|
||||||
|
Followers Only
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -641,7 +658,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
config: window.App.config,
|
config: window.App.config,
|
||||||
pageLoading: false,
|
pageLoading: false,
|
||||||
profile: {},
|
profile: window._sharedData.curUser,
|
||||||
composeText: '',
|
composeText: '',
|
||||||
composeTextLength: 0,
|
composeTextLength: 0,
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
|
@ -708,20 +725,19 @@ export default {
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
fetchProfile() {
|
fetchProfile() {
|
||||||
let self = this;
|
if(window._sharedData.curUser.id) {
|
||||||
if(window._sharedData.curUser) {
|
this.profile = window._sharedData.curUser;
|
||||||
self.profile = window._sharedData.curUser;
|
if(this.profile.locked == true) {
|
||||||
if(self.profile.locked == true) {
|
this.visibility = 'private';
|
||||||
self.visibility = 'private';
|
this.visibilityTag = 'Followers Only';
|
||||||
self.visibilityTag = 'Followers Only';
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
axios.get('/api/pixelfed/v1/accounts/verify_credentials').then(res => {
|
axios.get('/api/pixelfed/v1/accounts/verify_credentials').then(res => {
|
||||||
self.profile = res.data;
|
window._sharedData.currentUser = res.data;
|
||||||
window.pixelfed.currentUser = res.data;
|
this.profile = res.data;
|
||||||
if(res.data.locked == true) {
|
if(this.profile.locked == true) {
|
||||||
self.visibility = 'private';
|
this.visibility = 'private';
|
||||||
self.visibilityTag = 'Followers Only';
|
this.visibilityTag = 'Followers Only';
|
||||||
}
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container" style="">
|
<div>
|
||||||
<div v-if="layout === 'feed'" class="row">
|
<div v-if="currentLayout === 'feed'" class="container">
|
||||||
|
<div class="row">
|
||||||
<div v-if="morePostsAvailable == true" class="col-12 mt-5 pt-3 mb-3 fixed-top">
|
<div v-if="morePostsAvailable == true" class="col-12 mt-5 pt-3 mb-3 fixed-top">
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<button class="btn btn-dark px-4 rounded-pill font-weight-bold shadow" @click="syncNewPosts">Load New Posts</button>
|
<button class="btn btn-dark px-4 rounded-pill font-weight-bold shadow" @click="syncNewPosts">Load New Posts</button>
|
||||||
|
@ -207,10 +208,10 @@
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="reactions my-1 pb-2">
|
<div class="reactions my-1 pb-2">
|
||||||
<h3 v-if="status.favourited" class="fas fa-heart text-danger pr-3 m-0 cursor-pointer" title="Like" v-on:click="likeStatus(status, $event);"></h3>
|
<h3 v-if="status.favourited" class="fas fa-heart text-danger pr-3 m-0 cursor-pointer" title="Like" v-on:click="likeStatus(status, $event);"></h3>
|
||||||
<h3 v-else class="far fa-heart pr-3 m-0 like-btn text-lighter cursor-pointer" title="Like" v-on:click="likeStatus(status, $event);"></h3>
|
<h3 v-else class="far fa-heart pr-3 m-0 like-btn text-dark cursor-pointer" title="Like" v-on:click="likeStatus(status, $event);"></h3>
|
||||||
<h3 v-if="!status.comments_disabled" class="far fa-comment text-lighter pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
|
<h3 v-if="!status.comments_disabled" class="far fa-comment text-dark pr-3 m-0 cursor-pointer" title="Comment" v-on:click="commentFocus(status, $event)"></h3>
|
||||||
<h3 v-if="status.visibility == 'public'" v-bind:class="[status.reblogged ? 'fas fa-retweet pr-3 m-0 text-primary cursor-pointer' : 'fas fa-retweet pr-3 m-0 text-lighter share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"></h3>
|
<!-- <h3 v-if="status.visibility == 'public'" v-bind:class="[status.reblogged ? 'fas fa-retweet pr-3 m-0 text-primary cursor-pointer' : 'fas fa-retweet pr-3 m-0 text-dark share-btn cursor-pointer']" title="Share" v-on:click="shareStatus(status, $event)"></h3> -->
|
||||||
<h3 class="fas fa-expand pr-3 m-0 cursor-pointer text-lighter" v-on:click="lightbox(status)"></h3>
|
<!-- <h3 class="fas fa-expand pr-3 m-0 cursor-pointer text-dark" v-on:click="lightbox(status)"></h3> -->
|
||||||
<span v-if="status.taggedPeople.length" class="float-right">
|
<span v-if="status.taggedPeople.length" class="float-right">
|
||||||
<span class="font-weight-light small" style="color:#718096">
|
<span class="font-weight-light small" style="color:#718096">
|
||||||
<i class="far fa-user" data-toggle="tooltip" title="Tagged People"></i>
|
<i class="far fa-user" data-toggle="tooltip" title="Tagged People"></i>
|
||||||
|
@ -234,7 +235,7 @@
|
||||||
<span class="status-content" v-html="status.content"></span>
|
<span class="status-content" v-html="status.content"></span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="comments" v-if="status.id == replyId && !status.comments_disabled">
|
<!-- <div class="comments" v-if="status.id == replyId && !status.comments_disabled">
|
||||||
<p class="mb-0 d-flex justify-content-between align-items-top read-more mt-2" style="overflow-y: hidden;" v-for="(reply, index) in replies">
|
<p class="mb-0 d-flex justify-content-between align-items-top read-more mt-2" style="overflow-y: hidden;" v-for="(reply, index) in replies">
|
||||||
<span>
|
<span>
|
||||||
<a class="text-dark font-weight-bold mr-1" :href="profileUrl(reply)">{{reply.account.username}}</a>
|
<a class="text-dark font-weight-bold mr-1" :href="profileUrl(reply)">{{reply.account.username}}</a>
|
||||||
|
@ -244,13 +245,13 @@
|
||||||
<span v-on:click="likeStatus(reply, $event);">
|
<span v-on:click="likeStatus(reply, $event);">
|
||||||
<i v-bind:class="[reply.favourited ? 'fas fa-heart fa-sm text-danger cursor-pointer':'far fa-heart fa-sm text-lighter cursor-pointer']"></i>
|
<i v-bind:class="[reply.favourited ? 'fas fa-heart fa-sm text-danger cursor-pointer':'far fa-heart fa-sm text-lighter cursor-pointer']"></i>
|
||||||
</span>
|
</span>
|
||||||
<!-- <post-menu :status="reply" :profile="profile" size="sm" :modal="'true'" :feed="feed" class="d-inline-flex pl-2"></post-menu> -->
|
<!-- <post-menu :status="reply" :profile="profile" size="sm" :modal="'true'" :feed="feed" class="d-inline-flex pl-2"></post-menu> - ->
|
||||||
<span class="text-lighter pl-2 cursor-pointer" @click="ctxMenu(reply)">
|
<span class="text-lighter pl-2 cursor-pointer" @click="ctxMenu(reply)">
|
||||||
<span class="fas fa-ellipsis-v text-lighter"></span>
|
<span class="fas fa-ellipsis-v text-lighter"></span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="timestamp mt-2">
|
<div class="timestamp mt-2">
|
||||||
<p class="small text-uppercase mb-0">
|
<p class="small text-uppercase mb-0">
|
||||||
<a :href="statusUrl(status)" class="text-muted">
|
<a :href="statusUrl(status)" class="text-muted">
|
||||||
|
@ -296,7 +297,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-4 col-lg-4 my-4 order-1 order-md-2 d-none d-md-block">
|
<div class="col-md-4 col-lg-4 my-4 order-1 order-md-2 d-none d-md-block">
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
|
@ -401,75 +401,145 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="row">
|
</div>
|
||||||
<div class="col-12">
|
|
||||||
<!-- <div v-if="loading" class="text-center">
|
<div v-if="currentLayout === 'comments'" class="container p-0 overflow-hidden">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-6 offset-md-3">
|
||||||
|
<div class="card shadow-none border" style="height:100vh;">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<div
|
||||||
|
@click="commentNavigateBack(status.id)"
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
|
<i class="fas fa-chevron-left fa-lg px-2"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="font-weight-bold mb-0 h5">Comments</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<i class="fas fa-cog fa-lg text-white"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body" style="overflow-y: auto !important">
|
||||||
|
<div class="media">
|
||||||
|
<img :src="status.account.avatar" class="rounded-circle border mr-3" width="32px" height="32px">
|
||||||
|
<div class="media-body">
|
||||||
|
<p class="d-flex justify-content-between align-items-top mb-0" style="overflow-y: hidden;">
|
||||||
|
<span class="mr-2" style="font-size: 13px;">
|
||||||
|
<a class="text-dark font-weight-bold mr-1 text-break" :href="status.account.url" v-bind:title="status.account.username">{{trimCaption(status.account.username,15)}}</a>
|
||||||
|
<span class="text-break comment-body" style="word-break: break-all;" v-html="status.content"></span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="postCommentsLoader text-center py-2">
|
||||||
<div class="spinner-border" role="status">
|
<div class="spinner-border" role="status">
|
||||||
<span class="sr-only">Loading...</span>
|
<span class="sr-only">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div>
|
||||||
<div class="row">
|
<div class="postCommentsContainer d-none">
|
||||||
<div class="col-12 pl-3 pl-md-0 pt-3 pl-0">
|
<p v-if="replies.length" class="mb-1 text-center load-more-link my-4">
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<a
|
||||||
<p class="lead text-muted mb-0"><i :class="[scope == 'home' ? 'fas fa-home':'fas fa-stream']"></i> {{scope == 'local' ? 'Public' : 'Home'}} Timeline</p>
|
href="#"
|
||||||
<p class="mb-0">
|
class="text-dark"
|
||||||
<span class="btn-group">
|
title="Load more comments"
|
||||||
<a href="#" :class="[layout=='feed'?'btn btn-sm btn-outline-primary font-weight-bold text-decoration-none':'btn btn-sm btn-outline-lighter font-weight-light text-decoration-none']" @click.prevent="switchFeedLayout('feed')"><i class="fas fa-list"></i></a>
|
@click.prevent="loadMoreComments"
|
||||||
<a href="#" :class="[layout!=='feed'?'btn btn-sm btn-outline-primary font-weight-bold text-decoration-none':'btn btn-sm btn-outline-lighter font-weight-light text-decoration-none']" @click.prevent="switchFeedLayout('grid')"><i class="fas fa-th"></i></a>
|
>
|
||||||
|
<svg class="bi bi-plus-circle" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg" style="font-size:2em;"> <path fill-rule="evenodd" d="M8 3.5a.5.5 0 01.5.5v4a.5.5 0 01-.5.5H4a.5.5 0 010-1h3.5V4a.5.5 0 01.5-.5z" clip-rule="evenodd"/> <path fill-rule="evenodd" d="M7.5 8a.5.5 0 01.5-.5h4a.5.5 0 010 1H8.5V12a.5.5 0 01-1 0V8z" clip-rule="evenodd"/> <path fill-rule="evenodd" d="M8 15A7 7 0 108 1a7 7 0 000 14zm0 1A8 8 0 108 0a8 8 0 000 16z" clip-rule="evenodd"/></svg>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<div v-for="(reply, index) in replies" class="pb-3 media" :key="'tl' + reply.id + '_' + index">
|
||||||
|
<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="reply.account.url" 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="reply.account.url" 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>
|
||||||
|
<!-- <post-menu :status="reply" :profile="user" :size="'sm'" :modal="'true'" class="d-inline-block px-2" v-on:deletePost=""></post-menu> -->
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-0 d-none d-md-block">
|
|
||||||
<a class="btn btn-block btn-primary btn-sm font-weight-bold" href="/i/compose" data-toggle="modal" data-target="#composeModal">
|
|
||||||
New Post
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-md-4 p-1 p-md-3 mb-3" v-for="(s, index) in feed" :key="`${index}-${s.id}`">
|
|
||||||
<a class="card info-overlay card-md-border-0 shadow-sm border border-light" :href="statusUrl(s)">
|
|
||||||
<div :class="[s.sensitive ? 'square' : 'square ' + s.media_attachments[0].filter_class]">
|
|
||||||
<span v-if="s.pf_type == 'photo:album'" class="float-right mr-3 post-icon"><i class="fas fa-images fa-2x"></i></span>
|
|
||||||
<span v-if="s.pf_type == 'video'" class="float-right mr-3 post-icon"><i class="fas fa-video fa-2x"></i></span>
|
|
||||||
<span v-if="s.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x"></i></span>
|
|
||||||
<div class="square-content" v-bind:style="previewBackground(s)">
|
|
||||||
</div>
|
|
||||||
<div class="info-overlay-text px-4">
|
|
||||||
<p class="text-white m-auto text-center">
|
|
||||||
{{trimCaption(s.content_text)}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<div class="py-3 media align-items-center">
|
|
||||||
<a class="text-decoration-none" :href="s.account.url"><img :src="s.account.avatar" class="mr-3 rounded-circle shadow-sm" :alt="s.account.username + ' \'s avatar'" width="30px" height="30px" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=2'"></a>
|
|
||||||
<div class="media-body">
|
|
||||||
<p class="mb-0 font-weight-bold small"><a class="text-dark" :href="s.account.url">{{s.account.username}}</a></p>
|
|
||||||
<p class="mb-0" style="line-height: 0.7;">
|
|
||||||
<a :href="statusUrl(s)" class="small text-lighter">
|
|
||||||
<timeago :datetime="s.created_at" :auto-update="60" :converter-options="{includeSeconds:true}" :title="timestampFormat(s.created_at)" v-b-tooltip.hover.bottom></timeago>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="ml-3">
|
|
||||||
<p class="mb-0">
|
<p class="mb-0">
|
||||||
<span v-if="statusOwner(s)" class="font-weight-bold small">{{s.favourites_count == 1 ? '1 like' : s.favourites_count+' likes'}}</span>
|
<a v-once class="text-muted mr-3 text-decoration-none small" style="width: 20px;" v-text="timeAgo(reply.created_at)" :href="reply.url"></a>
|
||||||
<span class="px-2"><i v-bind:class="[s.favourited ? 'fas fa-heart text-danger cursor-pointer' : 'far fa-heart like-btn text-lighter cursor-pointer']" v-on:click="likeStatus(s, $event);"></i></span>
|
<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="mr-2 cursor-pointer"><i class="fas fa-ellipsis-v" @click="ctxMenu(s)"></i></span>
|
<span class="small text-muted comment-reaction font-weight-bold cursor-pointer" v-on:click="replyFocus(reply, index, true)">Reply</span>
|
||||||
|
</p>
|
||||||
|
<div v-if="reply.reply_count > 0" class="cursor-pointer pb-2" v-on:click="toggleReplies(reply)">
|
||||||
|
<span class="show-reply-bar"></span>
|
||||||
|
<span class="comment-reaction small font-weight-bold">{{reply.thread ? 'Hide' : 'View'}} Replies ({{reply.reply_count}})</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="reply.thread == true" class="comment-thread">
|
||||||
|
<div v-for="(s, sindex) in reply.replies" class="py-1 media" :key="'cr' + s.id + '_' + index">
|
||||||
|
<img :src="s.account.avatar" class="rounded-circle border mr-3" width="25px" height="25px">
|
||||||
|
<div class="media-body">
|
||||||
|
<p class="d-flex justify-content-between align-items-top read-more mb-0" style="overflow-y: hidden;">
|
||||||
|
<span class="mr-2" style="font-size: 13px;">
|
||||||
|
<a class="text-dark font-weight-bold mr-1" :href="s.account.url" :title="s.account.username">{{s.account.username}}</a>
|
||||||
|
<span class="text-break comment-body" style="word-break: break-all;" v-html="s.content"></span>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<span v-on:click="likeReply(s, $event)"><i v-bind:class="[s.favourited ? 'fas fa-heart fa-sm text-danger':'far fa-heart fa-sm text-lighter']"></i></span>
|
||||||
|
<!-- <post-menu :status="s" :profile="user" :size="'sm'" :modal="'true'" class="d-inline-block pl-2" v-on:deletePost="deleteCommentReply(s.id, sindex, index) "></post-menu> -->
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p class="mb-0">
|
||||||
|
<a v-once class="text-muted mr-3 text-decoration-none small" style="width: 20px;" v-text="timeAgo(s.created_at)" :href="s.url"></a>
|
||||||
|
<span v-if="s.favourites_count" class="text-muted comment-reaction font-weight-bold mr-3">{{s.favourites_count == 1 ? '1 like' : s.favourites_count + ' likes'}}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!loading && feed.length">
|
</div>
|
||||||
<infinite-loading @infinite="infiniteTimeline" :distance="800">
|
</div>
|
||||||
<div slot="no-more" class="font-weight-bold">No more posts to load</div>
|
<div v-if="!replies.length">
|
||||||
<div slot="no-results" class="font-weight-bold">No more posts to load</div>
|
<p class="text-center text-muted font-weight-bold small">No comments yet</p>
|
||||||
</infinite-loading>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer mb-3">
|
||||||
|
<div class="align-middle d-flex">
|
||||||
|
<img
|
||||||
|
:src="profile.avatar"
|
||||||
|
width="36"
|
||||||
|
height="36"
|
||||||
|
class="rounded-circle border mr-3">
|
||||||
|
<textarea
|
||||||
|
class="form-control rounded-pill"
|
||||||
|
name="comment"
|
||||||
|
placeholder="Add a comment…"
|
||||||
|
autocomplete="off"
|
||||||
|
autocorrect="off"
|
||||||
|
rows="1"
|
||||||
|
maxlength="0"
|
||||||
|
style="resize: none;overflow-y: hidden"
|
||||||
|
@click="replyFocus(status)">
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-stack">
|
||||||
<b-modal ref="ctxModal"
|
<b-modal ref="ctxModal"
|
||||||
id="ctx-modal"
|
id="ctx-modal"
|
||||||
hide-header
|
hide-header
|
||||||
|
@ -538,6 +608,7 @@
|
||||||
rounded
|
rounded
|
||||||
size="sm"
|
size="sm"
|
||||||
body-class="list-group-flush p-0 rounded text-center">
|
body-class="list-group-flush p-0 rounded text-center">
|
||||||
|
<div class="list-group-item rounded cursor-pointer" @click="shareStatus(ctxMenuStatus, $event)">{{ctxMenuStatus.reblogged ? 'Unshare' : 'Share'}} to Followers</div>
|
||||||
<div class="list-group-item rounded cursor-pointer" @click="ctxMenuCopyLink()">Copy Link</div>
|
<div class="list-group-item rounded cursor-pointer" @click="ctxMenuCopyLink()">Copy Link</div>
|
||||||
<div v-if="ctxMenuStatus && ctxMenuStatus.local == true && !ctxMenuStatus.in_reply_to_id" class="list-group-item rounded cursor-pointer" @click="ctxMenuEmbed()">Embed</div>
|
<div v-if="ctxMenuStatus && ctxMenuStatus.local == true && !ctxMenuStatus.in_reply_to_id" class="list-group-item rounded cursor-pointer" @click="ctxMenuEmbed()">Embed</div>
|
||||||
<!-- <div class="list-group-item rounded cursor-pointer border-top-0">Email</div>
|
<!-- <div class="list-group-item rounded cursor-pointer border-top-0">Email</div>
|
||||||
|
@ -669,8 +740,13 @@
|
||||||
size="md"
|
size="md"
|
||||||
body-class="p-2 rounded">
|
body-class="p-2 rounded">
|
||||||
<div>
|
<div>
|
||||||
<textarea class="form-control" rows="4" style="border: none; font-size: 18px; resize: none; white-space: pre-wrap;outline: none;" placeholder="Reply here ..." v-model="replyText">
|
<vue-tribute :options="tributeSettings">
|
||||||
|
<textarea
|
||||||
|
class="form-control replyModalTextarea"
|
||||||
|
rows="4"
|
||||||
|
v-model="replyText">
|
||||||
</textarea>
|
</textarea>
|
||||||
|
</vue-tribute>
|
||||||
|
|
||||||
<div class="border-top border-bottom my-2">
|
<div class="border-top border-bottom my-2">
|
||||||
<ul class="nav align-items-center emoji-reactions" style="overflow-x: scroll;flex-wrap: unset;">
|
<ul class="nav align-items-center emoji-reactions" style="overflow-x: scroll;flex-wrap: unset;">
|
||||||
|
@ -716,81 +792,20 @@
|
||||||
profile-layout="metro">
|
profile-layout="metro">
|
||||||
</post-component> -->
|
</post-component> -->
|
||||||
</b-modal>
|
</b-modal>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style type="text/css" scoped>
|
|
||||||
.postPresenterContainer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
.word-break {
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
.small .custom-control-label {
|
|
||||||
padding-top: 3px;
|
|
||||||
}
|
|
||||||
.reply-btn {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 12px;
|
|
||||||
right: 20px;
|
|
||||||
width: 60px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 0 3px 3px 0;
|
|
||||||
}
|
|
||||||
.emoji-reactions .nav-item {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
padding: 9px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.emoji-reactions::-webkit-scrollbar {
|
|
||||||
width: 0px;
|
|
||||||
height: 0px;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
.reply-btn[disabled] {
|
|
||||||
opacity: .3;
|
|
||||||
color: #3897f0;
|
|
||||||
}
|
|
||||||
.has-story {
|
|
||||||
width: 64px;
|
|
||||||
height: 64px;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 2px;
|
|
||||||
background: radial-gradient(ellipse at 70% 70%, #ee583f 8%, #d92d77 42%, #bd3381 58%);
|
|
||||||
}
|
|
||||||
.has-story img {
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 3px;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
.has-story.has-story-sm {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 2px;
|
|
||||||
background: radial-gradient(ellipse at 70% 70%, #ee583f 8%, #d92d77 42%, #bd3381 58%);
|
|
||||||
}
|
|
||||||
.has-story.has-story-sm img {
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 3px;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
#ctx-reply-modal .form-control:focus {
|
|
||||||
border: none;
|
|
||||||
outline: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
import VueTribute from 'vue-tribute'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['scope', 'layout'],
|
props: ['scope', 'layout'],
|
||||||
|
|
||||||
|
components: {
|
||||||
|
VueTribute
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
ids: [],
|
ids: [],
|
||||||
|
@ -844,7 +859,41 @@
|
||||||
mpPoller: null,
|
mpPoller: null,
|
||||||
confirmModalTitle: 'Are you sure?',
|
confirmModalTitle: 'Are you sure?',
|
||||||
confirmModalIdentifer: null,
|
confirmModalIdentifer: null,
|
||||||
confirmModalType: false
|
confirmModalType: false,
|
||||||
|
currentLayout: 'feed',
|
||||||
|
pagination: {},
|
||||||
|
tributeSettings: {
|
||||||
|
collection: [
|
||||||
|
{
|
||||||
|
trigger: '@',
|
||||||
|
menuShowMinLength: 2,
|
||||||
|
values: (function (text, cb) {
|
||||||
|
let url = '/api/compose/v0/search/mention';
|
||||||
|
axios.get(url, { params: { q: text }})
|
||||||
|
.then(res => {
|
||||||
|
cb(res.data);
|
||||||
|
})
|
||||||
|
.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);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1057,10 +1106,10 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.status && this.status.id == status.id) {
|
// if(this.status && this.status.id == status.id) {
|
||||||
this.$refs.replyModal.show();
|
// this.$refs.replyModal.show();
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.replies = {};
|
this.replies = {};
|
||||||
|
@ -1068,10 +1117,32 @@
|
||||||
this.replyText = '';
|
this.replyText = '';
|
||||||
this.replyId = status.id;
|
this.replyId = status.id;
|
||||||
this.replyStatus = status;
|
this.replyStatus = status;
|
||||||
this.$refs.replyModal.show();
|
// this.$refs.replyModal.show();
|
||||||
this.fetchStatusComments(status, '');
|
this.fetchStatusComments(status, '');
|
||||||
return;
|
|
||||||
|
|
||||||
|
$('nav').hide();
|
||||||
|
$('footer').hide();
|
||||||
|
$('.mobile-footer-spacer').attr('style', 'display:none !important');
|
||||||
|
$('.mobile-footer').attr('style', 'display:none !important');
|
||||||
|
this.currentLayout = 'comments';
|
||||||
|
window.history.pushState({}, '', status.url);
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
|
||||||
|
commentNavigateBack(id) {
|
||||||
|
$('nav').show();
|
||||||
|
$('footer').show();
|
||||||
|
$('.mobile-footer-spacer').attr('style', 'display:block');
|
||||||
|
$('.mobile-footer').attr('style', 'display:block');
|
||||||
|
this.currentLayout = 'feed';
|
||||||
|
setTimeout(function() {
|
||||||
|
$([document.documentElement, document.body]).animate({
|
||||||
|
scrollTop: $(`div[data-status-id="${id}"]`).offset().top
|
||||||
|
}, 1000);
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
let path = this.scope == 'home' ? '/' : '/timeline/public';
|
||||||
|
window.history.pushState({}, '', path);
|
||||||
},
|
},
|
||||||
|
|
||||||
likeStatus(status, event) {
|
likeStatus(status, event) {
|
||||||
|
@ -1102,11 +1173,18 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.closeModals();
|
||||||
|
|
||||||
axios.post('/i/share', {
|
axios.post('/i/share', {
|
||||||
item: status.id
|
item: status.id
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
status.reblogs_count = res.data.count;
|
status.reblogs_count = res.data.count;
|
||||||
status.reblogged = !status.reblogged;
|
status.reblogged = !status.reblogged;
|
||||||
|
if(status.reblogged) {
|
||||||
|
swal('Success', 'You shared this post', 'success');
|
||||||
|
} else {
|
||||||
|
swal('Success', 'You unshared this post', 'success');
|
||||||
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
swal('Error', 'Something went wrong, please try again later.', 'error');
|
swal('Error', 'Something went wrong, please try again later.', 'error');
|
||||||
});
|
});
|
||||||
|
@ -1133,19 +1211,67 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
fetchStatusComments(status, card) {
|
fetchStatusComments(status, card) {
|
||||||
axios.get('/api/v2/status/'+status.id+'/replies')
|
// axios.get('/api/v2/status/'+status.id+'/replies',
|
||||||
.then(res => {
|
// {
|
||||||
let data = res.data.filter(res => {
|
// params: {
|
||||||
return res.sensitive == false;
|
// limit: 6
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// .then(res => {
|
||||||
|
// let data = res.data.filter(res => {
|
||||||
|
// return res.sensitive == false;
|
||||||
|
// });
|
||||||
|
// this.replies = _.reverse(data);
|
||||||
|
// setTimeout(function() {
|
||||||
|
// document.querySelectorAll('.timeline .card-body .comments .comment-body a').forEach(function(i, e) {
|
||||||
|
// i.href = App.util.format.rewriteLinks(i);
|
||||||
|
// });
|
||||||
|
// }, 500);
|
||||||
|
// }).catch(err => {
|
||||||
|
// })
|
||||||
|
let url = '/api/v2/comments/'+status.account.id+'/status/'+status.id;
|
||||||
|
axios.get(url)
|
||||||
|
.then(response => {
|
||||||
|
let self = this;
|
||||||
|
// this.results = this.layout == 'metro' ?
|
||||||
|
// _.reverse(response.data.data) :
|
||||||
|
// response.data.data;
|
||||||
|
this.replies = _.reverse(response.data.data);
|
||||||
|
this.pagination = response.data.meta.pagination;
|
||||||
|
if(this.replies.length > 0) {
|
||||||
|
$('.load-more-link').removeClass('d-none');
|
||||||
|
}
|
||||||
|
$('.postCommentsLoader').addClass('d-none');
|
||||||
|
$('.postCommentsContainer').removeClass('d-none');
|
||||||
|
// setTimeout(function() {
|
||||||
|
// document.querySelectorAll('.status-comment .postCommentsContainer .comment-body a').forEach(function(i, e) {
|
||||||
|
// i.href = App.util.format.rewriteLinks(i);
|
||||||
|
// });
|
||||||
|
// }, 500);
|
||||||
|
}).catch(error => {
|
||||||
|
if(!error.response) {
|
||||||
|
$('.postCommentsLoader .lds-ring')
|
||||||
|
.attr('style','width:100%')
|
||||||
|
.addClass('pt-4 font-weight-bold text-muted')
|
||||||
|
.text('An error occurred, cannot fetch comments. Please try again later.');
|
||||||
|
} else {
|
||||||
|
switch(error.response.status) {
|
||||||
|
case 401:
|
||||||
|
$('.postCommentsLoader .lds-ring')
|
||||||
|
.attr('style','width:100%')
|
||||||
|
.addClass('pt-4 font-weight-bold text-muted')
|
||||||
|
.text('Please login to view.');
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$('.postCommentsLoader .lds-ring')
|
||||||
|
.attr('style','width:100%')
|
||||||
|
.addClass('pt-4 font-weight-bold text-muted')
|
||||||
|
.text('An error occurred, cannot fetch comments. Please try again later.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
this.replies = _.reverse(data);
|
|
||||||
setTimeout(function() {
|
|
||||||
document.querySelectorAll('.timeline .card-body .comments .comment-body a').forEach(function(i, e) {
|
|
||||||
i.href = App.util.format.rewriteLinks(i);
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
}).catch(err => {
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
|
|
||||||
muteProfile(status) {
|
muteProfile(status) {
|
||||||
|
@ -1217,7 +1343,7 @@
|
||||||
sensitive: this.replyNsfw
|
sensitive: this.replyNsfw
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
this.replyText = '';
|
this.replyText = '';
|
||||||
this.replies.unshift(res.data.entity);
|
this.replies.push(res.data.entity);
|
||||||
this.$refs.replyModal.hide();
|
this.$refs.replyModal.hide();
|
||||||
});
|
});
|
||||||
this.replySending = false;
|
this.replySending = false;
|
||||||
|
@ -1927,6 +2053,92 @@
|
||||||
|
|
||||||
confirmModalCancel() {
|
confirmModalCancel() {
|
||||||
this.closeConfirmModal();
|
this.closeConfirmModal();
|
||||||
|
},
|
||||||
|
|
||||||
|
timeAgo(ts) {
|
||||||
|
return App.util.format.timeAgo(ts);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleReplies(reply) {
|
||||||
|
if(reply.thread) {
|
||||||
|
reply.thread = false;
|
||||||
|
} else {
|
||||||
|
if(reply.replies.length > 0) {
|
||||||
|
reply.thread = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let url = '/api/v2/comments/'+reply.account.id+'/status/'+reply.id;
|
||||||
|
axios.get(url)
|
||||||
|
.then(response => {
|
||||||
|
reply.replies = _.reverse(response.data.data);
|
||||||
|
reply.thread = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
likeReply(status, $event) {
|
||||||
|
if($('body').hasClass('loggedIn') == false) {
|
||||||
|
swal('Login', 'Please login to perform this action.', 'info');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.post('/i/like', {
|
||||||
|
item: status.id
|
||||||
|
}).then(res => {
|
||||||
|
status.favourites_count = res.data.count;
|
||||||
|
if(status.favourited == true) {
|
||||||
|
status.favourited = false;
|
||||||
|
} else {
|
||||||
|
status.favourited = true;
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
swal('Error', 'Something went wrong, please try again later.', 'error');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
replyFocus(e, index, prependUsername = false) {
|
||||||
|
if($('body').hasClass('loggedIn') == false) {
|
||||||
|
this.redirect('/login?next=' + encodeURIComponent(window.location.pathname));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(this.status.comments_disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.replyToIndex = index;
|
||||||
|
this.replyingToId = e.id;
|
||||||
|
this.replyingToUsername = e.account.username;
|
||||||
|
this.reply_to_profile_id = e.account.id;
|
||||||
|
let username = e.account.local ? '@' + e.account.username + ' '
|
||||||
|
: '@' + e.account.acct + ' ';
|
||||||
|
if(prependUsername == true) {
|
||||||
|
this.replyText = username;
|
||||||
|
}
|
||||||
|
this.$refs.replyModal.show();
|
||||||
|
setTimeout(function() {
|
||||||
|
$('.replyModalTextarea').focus();
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
|
||||||
|
loadMoreComments() {
|
||||||
|
if(this.pagination.total_pages == 1 || this.pagination.current_page == this.pagination.total_pages) {
|
||||||
|
$('.load-more-link').addClass('d-none');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$('.load-more-link').addClass('d-none');
|
||||||
|
$('.postCommentsLoader').removeClass('d-none');
|
||||||
|
let next = this.pagination.links.next;
|
||||||
|
axios.get(next)
|
||||||
|
.then(response => {
|
||||||
|
let self = this;
|
||||||
|
let res = response.data.data;
|
||||||
|
$('.postCommentsLoader').addClass('d-none');
|
||||||
|
for(let i=0; i < res.length; i++) {
|
||||||
|
this.replies.unshift(res[i]);
|
||||||
|
}
|
||||||
|
this.pagination = response.data.meta.pagination;
|
||||||
|
$('.load-more-link').removeClass('d-none');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1935,3 +2147,129 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style type="text/css" scoped>
|
||||||
|
.postPresenterContainer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.word-break {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
.small .custom-control-label {
|
||||||
|
padding-top: 3px;
|
||||||
|
}
|
||||||
|
/*.reply-btn {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30px;
|
||||||
|
right: 20px;
|
||||||
|
width: 60px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
border-radius: 0 3px 3px 0;
|
||||||
|
}*/
|
||||||
|
.emoji-reactions .nav-item {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
padding: 9px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.emoji-reactions::-webkit-scrollbar {
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.reply-btn[disabled] {
|
||||||
|
opacity: .3;
|
||||||
|
color: #3897f0;
|
||||||
|
}
|
||||||
|
.replyModalTextarea {
|
||||||
|
border: none;
|
||||||
|
font-size: 18px;
|
||||||
|
resize: none;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.has-story {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 2px;
|
||||||
|
background: radial-gradient(ellipse at 70% 70%, #ee583f 8%, #d92d77 42%, #bd3381 58%);
|
||||||
|
}
|
||||||
|
.has-story img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 3px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.has-story.has-story-sm {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 2px;
|
||||||
|
background: radial-gradient(ellipse at 70% 70%, #ee583f 8%, #d92d77 42%, #bd3381 58%);
|
||||||
|
}
|
||||||
|
.has-story.has-story-sm img {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 3px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
#ctx-reply-modal .form-control:focus {
|
||||||
|
border: none;
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style type="text/css">
|
||||||
|
.tribute-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: auto;
|
||||||
|
max-height: 300px;
|
||||||
|
min-width: 120px;
|
||||||
|
max-width: 100vw;
|
||||||
|
overflow: auto;
|
||||||
|
display: block;
|
||||||
|
z-index: 999999;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(#000, 0.13);
|
||||||
|
}
|
||||||
|
.tribute-container ul {
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 2px;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid rgba(#000, 0.13);
|
||||||
|
background-clip: padding-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.tribute-container li {
|
||||||
|
color: #000;
|
||||||
|
padding: 5px 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
overflow-x: hidden !important;
|
||||||
|
}
|
||||||
|
.tribute-container li.highlight,
|
||||||
|
.tribute-container li:hover {
|
||||||
|
background: #2c78bf;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.tribute-container li span {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.tribute-container li.no-match {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.tribute-container .menu-highlighted {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -23,7 +23,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div :title="status.media_attachments[0].description">
|
<div :title="status.media_attachments[0].description">
|
||||||
<img :class="status.media_attachments[0].filter_class + ' card-img-top'" :src="status.media_attachments[0].url" loading="lazy" :alt="altText(status)" onerror="this.onerror=null;this.src='/storage/no-preview.png'">
|
<img class="card-img-top"
|
||||||
|
:src="status.media_attachments[0].url"
|
||||||
|
loading="lazy"
|
||||||
|
:alt="altText(status)"
|
||||||
|
:width="width()"
|
||||||
|
:height="height()"
|
||||||
|
onerror="this.onerror=null;this.src='/storage/no-preview.png'">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -67,6 +73,24 @@
|
||||||
|
|
||||||
toggleContentWarning(status) {
|
toggleContentWarning(status) {
|
||||||
this.$emit('togglecw');
|
this.$emit('togglecw');
|
||||||
|
},
|
||||||
|
|
||||||
|
width() {
|
||||||
|
if( !this.status.media_attachments[0].meta ||
|
||||||
|
!this.status.media_attachments[0].meta.original ||
|
||||||
|
!this.status.media_attachments[0].meta.original.width ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return this.status.media_attachments[0].meta.original.width;
|
||||||
|
},
|
||||||
|
|
||||||
|
height() {
|
||||||
|
if( !this.status.media_attachments[0].meta ||
|
||||||
|
!this.status.media_attachments[0].meta.original ||
|
||||||
|
!this.status.media_attachments[0].meta.original.height ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return this.status.media_attachments[0].meta.original.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6
resources/assets/sass/lib/fontawesome.scss
vendored
6
resources/assets/sass/lib/fontawesome.scss
vendored
|
@ -4255,7 +4255,7 @@ readers do not read off random characters that represent icons */
|
||||||
font-family: 'Font Awesome 5 Brands';
|
font-family: 'Font Awesome 5 Brands';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-display: auto;
|
font-display: swap;
|
||||||
src: url("/fonts/fa-brands-400.eot");
|
src: url("/fonts/fa-brands-400.eot");
|
||||||
src: url("/fonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("/fonts/fa-brands-400.woff2") format("woff2"), url("/fonts/fa-brands-400.woff") format("woff"), url("/fonts/fa-brands-400.ttf") format("truetype"), url("/fonts/fa-brands-400.svg#fontawesome") format("svg"); }
|
src: url("/fonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("/fonts/fa-brands-400.woff2") format("woff2"), url("/fonts/fa-brands-400.woff") format("woff"), url("/fonts/fa-brands-400.ttf") format("truetype"), url("/fonts/fa-brands-400.svg#fontawesome") format("svg"); }
|
||||||
|
|
||||||
|
@ -4265,7 +4265,7 @@ readers do not read off random characters that represent icons */
|
||||||
font-family: 'Font Awesome 5 Free';
|
font-family: 'Font Awesome 5 Free';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: auto;
|
font-display: swap;
|
||||||
src: url("/fonts/fa-regular-400.eot");
|
src: url("/fonts/fa-regular-400.eot");
|
||||||
src: url("/fonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("/fonts/fa-regular-400.woff2") format("woff2"), url("/fonts/fa-regular-400.woff") format("woff"), url("/fonts/fa-regular-400.ttf") format("truetype"), url("/fonts/fa-regular-400.svg#fontawesome") format("svg"); }
|
src: url("/fonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("/fonts/fa-regular-400.woff2") format("woff2"), url("/fonts/fa-regular-400.woff") format("woff"), url("/fonts/fa-regular-400.ttf") format("truetype"), url("/fonts/fa-regular-400.svg#fontawesome") format("svg"); }
|
||||||
|
|
||||||
|
@ -4276,7 +4276,7 @@ readers do not read off random characters that represent icons */
|
||||||
font-family: 'Font Awesome 5 Free';
|
font-family: 'Font Awesome 5 Free';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-display: auto;
|
font-display: swap;
|
||||||
src: url("/fonts/fa-solid-900.eot");
|
src: url("/fonts/fa-solid-900.eot");
|
||||||
src: url("/fonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("/fonts/fa-solid-900.woff2") format("woff2"), url("/fonts/fa-solid-900.woff") format("woff"), url("/fonts/fa-solid-900.ttf") format("truetype"), url("/fonts/fa-solid-900.svg#fontawesome") format("svg"); }
|
src: url("/fonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("/fonts/fa-solid-900.woff2") format("woff2"), url("/fonts/fa-solid-900.woff") format("woff"), url("/fonts/fa-solid-900.ttf") format("truetype"), url("/fonts/fa-solid-900.svg#fontawesome") format("svg"); }
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
|
||||||
Route::delete('/media/delete', 'ComposeController@mediaDelete');
|
Route::delete('/media/delete', 'ComposeController@mediaDelete');
|
||||||
Route::get('/search/tag', 'ComposeController@searchTag');
|
Route::get('/search/tag', 'ComposeController@searchTag');
|
||||||
Route::get('/search/location', 'ComposeController@searchLocation');
|
Route::get('/search/location', 'ComposeController@searchLocation');
|
||||||
|
Route::get('/search/mention', 'ComposeController@searchMentionAutocomplete');
|
||||||
|
Route::get('/search/hashtag', 'ComposeController@searchHashtagAutocomplete');
|
||||||
|
|
||||||
Route::post('/publish', 'ComposeController@store')
|
Route::post('/publish', 'ComposeController@store')
|
||||||
->middleware('throttle:maxPostsPerHour,60')
|
->middleware('throttle:maxPostsPerHour,60')
|
||||||
|
|
Loading…
Reference in a new issue