mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-25 15:55:22 +00:00
commit
d99e79aa60
37 changed files with 709 additions and 331 deletions
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -3,10 +3,36 @@
|
|||
## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.10.6...dev)
|
||||
|
||||
### Added
|
||||
- Added drafts API endpoint for Camera Roll ([bad2ecde](https://github.com/pixelfed/pixelfed/commit/bad2ecde))
|
||||
|
||||
### Fixed
|
||||
- Fixed like and share/reblog count on profiles ([86cb7d09](https://github.com/pixelfed/pixelfed/commit/86cb7d09))
|
||||
- Fixed non federating self boosts ([0c59a55e](https://github.com/pixelfed/pixelfed/commit/0c59a55e))
|
||||
- Fixed CORS issues with API endpoints ([6d6f517d](https://github.com/pixelfed/pixelfed/commit/6d6f517d))
|
||||
- Fixed mixed albums not appearing on timelines ([e01dff45](https://github.com/pixelfed/pixelfed/commit/e01dff45))
|
||||
|
||||
### Changed
|
||||
- Removed ```relationship``` from ```AccountTransformer``` ([4d084ac5](https://github.com/pixelfed/pixelfed/commit/4d084ac5))
|
||||
- Updated ```notification``` api endpoint to use ```NotificationService``` ([f4039ce2](https://github.com/pixelfed/pixelfed/commit/f4039ce2)) ([6ef7597](https://github.com/pixelfed/pixelfed/commit/6ef7597))
|
||||
- Update footer to use localization for the ```Places``` link ([39712714](https://github.com/pixelfed/pixelfed/commit/39712714))
|
||||
- Updated ComposeModal.vue, added a caption counter. Fixes [#1722](https://github.com/pixelfed/pixelfed/issues/1722). ([009c6ee8](https://github.com/pixelfed/pixelfed/commit/009c6ee8))
|
||||
- Updated Notifications to use the NotificationService ([f4039ce2](https://github.com/pixelfed/pixelfed/commit/f4039ce218f93a5578225dfdba66f0359c8fc72c))
|
||||
- Updated PrivacySettings controller, clear cache after updating ([d8d11d7b](https://github.com/pixelfed/pixelfed/commit/d8d11d7b))
|
||||
- Updated BaseApiController, add timestamp to signed media previews for client side cache invalidation ([73c08987](https://github.com/pixelfed/pixelfed/commit/73c08987))
|
||||
- Updated AdminInstanceController, remove db transaction from instance scan ([5773434a](https://github.com/pixelfed/pixelfed/commit/5773434a))
|
||||
- Updated Help Center view, added outdated warning ([0e611d00](https://github.com/pixelfed/pixelfed/commit/0e611d00))
|
||||
- Updated language view, added English version of language names ([ebb998d2](https://github.com/pixelfed/pixelfed/commit/ebb998d2))
|
||||
- Updated app.js, added App.utils like ```.format.count```, ```.filters``` and ```.emoji``` ([34c13b6e](https://github.com/pixelfed/pixelfed/commit/34c13b6e))
|
||||
- Updated CollectionCompose.vue component, fix api namespace change ([71ed965c](https://github.com/pixelfed/pixelfed/commit/71ed965c))
|
||||
- Updated PostComponent, mark caption sensitive if post is and use util.emoji ([35d51215](https://github.com/pixelfed/pixelfed/commit/35d51215))
|
||||
- Updated Profile.vue component, use formatted counts ([30f14961](https://github.com/pixelfed/pixelfed/commit/30f14961))
|
||||
- Updated Timeline.vue component, use formatted counts, util.emoji and increase pagination limit to 5 ([abfc9fe7](https://github.com/pixelfed/pixelfed/commit/abfc9fe7))
|
||||
- Updated album presenters, use better carousel ([31b114cc](https://github.com/pixelfed/pixelfed/commit/31b114cc)) ([0617fada](https://github.com/pixelfed/pixelfed/commit/0617fada)) ([767fc887](https://github.com/pixelfed/pixelfed/commit/767fc887))
|
||||
- Updated Timeline.vue component, remove tap for lightbox as it conflicts with new carousel ([96e25ad2](https://github.com/pixelfed/pixelfed/commit/96e25ad2))
|
||||
- Updated ComposeModal.vue, added album support, editing and UI tweaks ([3aaad81e](https://github.com/pixelfed/pixelfed/commit/3aaad81e))
|
||||
- Updated InternalApiController, increase license limit to 140 to match UI counter ([b3c18aec](https://github.com/pixelfed/pixelfed/commit/b3c18aec))
|
||||
|
||||
## Deprecated
|
||||
|
||||
|
||||
## [v0.10.6 (2019-09-30)](https://github.com/pixelfed/pixelfed/compare/v0.10.5...v0.10.6)
|
||||
|
|
|
@ -42,18 +42,18 @@ trait AdminInstanceController
|
|||
|
||||
public function instanceScan(Request $request)
|
||||
{
|
||||
DB::transaction(function() {
|
||||
Profile::select('domain')->whereNotNull('domain')
|
||||
->groupBy('id')
|
||||
->groupBy('domain')
|
||||
->chunk(50, function($domains) {
|
||||
foreach($domains as $domain) {
|
||||
Instance::firstOrCreate([
|
||||
'domain' => $domain->domain
|
||||
]);
|
||||
}
|
||||
});
|
||||
Profile::whereNotNull('domain')
|
||||
->latest()
|
||||
->groupBy('domain')
|
||||
->where('created_at', '>', now()->subMonths(2))
|
||||
->chunk(100, function($domains) {
|
||||
foreach($domains as $domain) {
|
||||
Instance::firstOrCreate([
|
||||
'domain' => $domain->domain
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ use App\Transformer\Api\{
|
|||
AccountTransformer,
|
||||
NotificationTransformer,
|
||||
MediaTransformer,
|
||||
MediaDraftTransformer,
|
||||
StatusTransformer
|
||||
};
|
||||
use League\Fractal;
|
||||
|
@ -192,7 +193,7 @@ class BaseApiController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
public function showTempMedia(Request $request, int $profileId, $mediaId)
|
||||
public function showTempMedia(Request $request, int $profileId, $mediaId, $timestamp)
|
||||
{
|
||||
abort_if(!$request->user(), 403);
|
||||
abort_if(!$request->hasValidSignature(), 404);
|
||||
|
@ -257,10 +258,9 @@ class BaseApiController extends Controller
|
|||
$media->save();
|
||||
|
||||
$url = URL::temporarySignedRoute(
|
||||
'temp-media', now()->addHours(1), ['profileId' => $profile->id, 'mediaId' => $media->id]
|
||||
'temp-media', now()->addHours(1), ['profileId' => $profile->id, 'mediaId' => $media->id, 'timestamp' => time()]
|
||||
);
|
||||
|
||||
$preview_url = $url;
|
||||
switch ($media->mime) {
|
||||
case 'image/jpeg':
|
||||
case 'image/png':
|
||||
|
@ -279,7 +279,7 @@ class BaseApiController extends Controller
|
|||
|
||||
$resource = new Fractal\Resource\Item($media, new MediaTransformer());
|
||||
$res = $this->fractal->createData($resource)->toArray();
|
||||
$res['preview_url'] = $preview_url;
|
||||
$res['preview_url'] = $url;
|
||||
$res['url'] = $url;
|
||||
return response()->json($res);
|
||||
}
|
||||
|
@ -308,8 +308,9 @@ class BaseApiController extends Controller
|
|||
|
||||
public function verifyCredentials(Request $request)
|
||||
{
|
||||
abort_if(!$request->user(), 403);
|
||||
$id = Auth::id();
|
||||
$user = $request->user();
|
||||
abort_if(!$user, 403);
|
||||
$id = $user->id;
|
||||
|
||||
$res = Cache::remember('user:account:id:'.$id, now()->addHours(6), function() use($id) {
|
||||
$profile = Profile::whereNull('status')->whereUserId($id)->firstOrFail();
|
||||
|
@ -320,4 +321,19 @@ class BaseApiController extends Controller
|
|||
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
public function drafts(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
abort_if(!$request->user(), 403);
|
||||
|
||||
$medias = Media::whereUserId($user->id)
|
||||
->whereNull('status_id')
|
||||
->latest()
|
||||
->take(13)
|
||||
->get();
|
||||
$resource = new Fractal\Resource\Collection($medias, new MediaDraftTransformer());
|
||||
$res = $this->fractal->createData($resource)->toArray();
|
||||
return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,7 +237,8 @@ class InternalApiController extends Controller
|
|||
'media.*' => 'required',
|
||||
'media.*.id' => 'required|integer|min:1',
|
||||
'media.*.filter_class' => 'nullable|alpha_dash|max:30',
|
||||
'media.*.license' => 'nullable|string|max:80',
|
||||
'media.*.license' => 'nullable|string|max:140',
|
||||
'media.*.alt' => 'nullable|string|max:140',
|
||||
'cw' => 'nullable|boolean',
|
||||
'visibility' => 'required|string|in:public,private,unlisted|min:2|max:10',
|
||||
'place' => 'nullable',
|
||||
|
|
|
@ -281,7 +281,7 @@ class PublicApiController extends Controller
|
|||
'updated_at'
|
||||
)->where('id', $dir, $id)
|
||||
->with('profile', 'hashtags', 'mentions')
|
||||
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album'])
|
||||
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||
->whereLocal(true)
|
||||
->whereNotIn('profile_id', $filtered)
|
||||
->whereVisibility('public')
|
||||
|
@ -309,7 +309,7 @@ class PublicApiController extends Controller
|
|||
'likes_count',
|
||||
'reblogs_count',
|
||||
'updated_at'
|
||||
)->whereIn('type', ['photo', 'photo:album', 'video', 'video:album'])
|
||||
)->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||
->with('profile', 'hashtags', 'mentions')
|
||||
->whereLocal(true)
|
||||
->whereNotIn('profile_id', $filtered)
|
||||
|
@ -392,7 +392,7 @@ class PublicApiController extends Controller
|
|||
'reblogs_count',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
)->whereIn('type', ['photo', 'photo:album', 'video', 'video:album'])
|
||||
)->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||
->with('profile', 'hashtags', 'mentions')
|
||||
->where('id', $dir, $id)
|
||||
->whereIn('profile_id', $following)
|
||||
|
@ -421,7 +421,7 @@ class PublicApiController extends Controller
|
|||
'reblogs_count',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
)->whereIn('type', ['photo', 'photo:album', 'video', 'video:album'])
|
||||
)->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||
->with('profile', 'hashtags', 'mentions')
|
||||
->whereIn('profile_id', $following)
|
||||
->whereNotIn('profile_id', $filtered)
|
||||
|
|
|
@ -66,6 +66,7 @@ trait PrivacySettings
|
|||
$settings->save();
|
||||
}
|
||||
Cache::forget('profile:settings:' . $profile->id);
|
||||
Cache::forget('user:account:id:' . $profile->user_id);
|
||||
return redirect(route('settings.privacy'))->with('status', 'Settings successfully updated!');
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,12 @@ class SharePipeline implements ShouldQueue
|
|||
->whereItemType('App\Status')
|
||||
->count();
|
||||
|
||||
if ($target->id === $status->profile_id || $exists !== 0) {
|
||||
if ($target->id === $status->profile_id) {
|
||||
$this->remoteAnnounceDeliver();
|
||||
return true;
|
||||
}
|
||||
|
||||
if( $exists !== 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -88,6 +93,9 @@ class SharePipeline implements ShouldQueue
|
|||
|
||||
public function remoteAnnounceDeliver()
|
||||
{
|
||||
if(config('federation.activitypub.enabled') == false) {
|
||||
return true;
|
||||
}
|
||||
$status = $this->status;
|
||||
$profile = $status->profile;
|
||||
|
||||
|
|
38
app/Transformer/Api/MediaDraftTransformer.php
Normal file
38
app/Transformer/Api/MediaDraftTransformer.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Transformer\Api;
|
||||
|
||||
use App\Media;
|
||||
use League\Fractal;
|
||||
use URL;
|
||||
|
||||
class MediaDraftTransformer extends Fractal\TransformerAbstract
|
||||
{
|
||||
public function transform(Media $media)
|
||||
{
|
||||
|
||||
$url = URL::temporarySignedRoute(
|
||||
'temp-media', now()->addHours(1), ['profileId' => $media->profile_id, 'mediaId' => $media->id, 'timestamp' => time()]
|
||||
);
|
||||
|
||||
//$url = $media->thumbnailUrl();
|
||||
//$url = $media->url();
|
||||
|
||||
return [
|
||||
'id' => (string) $media->id,
|
||||
'type' => $media->activityVerb(),
|
||||
'url' => $url,
|
||||
'remote_url' => null,
|
||||
'preview_url' => $url,
|
||||
'text_url' => null,
|
||||
'meta' => null,
|
||||
'description' => $media->caption,
|
||||
'license' => $media->license,
|
||||
'is_nsfw' => $media->is_nsfw,
|
||||
'orientation' => $media->orientation,
|
||||
'filter_name' => $media->filter_name,
|
||||
'filter_class' => $media->filter_class,
|
||||
'mime' => $media->mime,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@ COPY . /var/www/
|
|||
WORKDIR /var/www/
|
||||
RUN cp -r storage storage.skel \
|
||||
&& cp contrib/docker/php.ini /usr/local/etc/php/conf.d/pixelfed.ini \
|
||||
&& composer install --prefer-source --no-interaction \
|
||||
&& composer install --prefer-dist --no-interaction \
|
||||
&& rm -rf html && ln -s public html
|
||||
|
||||
VOLUME /var/www/storage /var/www/bootstrap
|
||||
|
|
51
package-lock.json
generated
51
package-lock.json
generated
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"name": "pixelfed",
|
||||
"requires": true,
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
|
@ -3106,6 +3107,11 @@
|
|||
"entities": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"dom-walk": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
|
||||
"integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
|
||||
},
|
||||
"domain-browser": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
|
||||
|
@ -4621,6 +4627,15 @@
|
|||
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz",
|
||||
"integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs="
|
||||
},
|
||||
"global": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
|
||||
"integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
|
||||
"requires": {
|
||||
"min-document": "^2.19.0",
|
||||
"process": "^0.11.10"
|
||||
}
|
||||
},
|
||||
"global-modules": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
|
||||
|
@ -6085,6 +6100,14 @@
|
|||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
|
||||
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
|
||||
},
|
||||
"min-document": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
|
||||
"integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
|
||||
"requires": {
|
||||
"dom-walk": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
|
@ -7787,14 +7810,14 @@
|
|||
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
|
||||
},
|
||||
"quill": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.6.tgz",
|
||||
"integrity": "sha512-K0mvhimWZN6s+9OQ249CH2IEPZ9JmkFuCQeHAOQax3EZ2nDJ3wfGh59mnlQaZV2i7u8eFarx6wAtvQKgShojug==",
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
|
||||
"integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
|
||||
"requires": {
|
||||
"clone": "^2.1.1",
|
||||
"deep-equal": "^1.0.1",
|
||||
"eventemitter3": "^2.0.3",
|
||||
"extend": "^3.0.1",
|
||||
"extend": "^3.0.2",
|
||||
"parchment": "^1.1.4",
|
||||
"quill-delta": "^3.6.2"
|
||||
},
|
||||
|
@ -9856,8 +9879,24 @@
|
|||
"vue": {
|
||||
"version": "2.6.10",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz",
|
||||
"integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ=="
|
||||
},
|
||||
"vue-carousel": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-carousel/-/vue-carousel-0.18.0.tgz",
|
||||
"integrity": "sha512-a2zxh7QJioDxNMguqcuJ7TPbfgK5bGDaAXIia7NWxPAWsEvNE4ZtHgsGu40L5Aha4uyjmNKXvleB14QAXFoKig==",
|
||||
"requires": {
|
||||
"global": "^4.3.2",
|
||||
"regenerator-runtime": "^0.12.1",
|
||||
"vue": "^2.5.17"
|
||||
},
|
||||
"dependencies": {
|
||||
"regenerator-runtime": {
|
||||
"version": "0.12.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz",
|
||||
"integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-content-loader": {
|
||||
"version": "0.2.2",
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
"socket.io-client": "^2.2.0",
|
||||
"sweetalert": "^2.1.2",
|
||||
"twitter-text": "^2.0.5",
|
||||
"vue-carousel": "^0.18.0",
|
||||
"vue-content-loader": "^0.2.2",
|
||||
"vue-cropperjs": "^4.0.0",
|
||||
"vue-infinite-loading": "^2.4.4",
|
||||
|
|
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/app.js
vendored
BIN
public/js/app.js
vendored
Binary file not shown.
BIN
public/js/collectioncompose.js
vendored
BIN
public/js/collectioncompose.js
vendored
Binary file not shown.
BIN
public/js/components.js
vendored
BIN
public/js/components.js
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/quill.js
vendored
BIN
public/js/quill.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.
63
resources/assets/js/app.js
vendored
63
resources/assets/js/app.js
vendored
|
@ -18,4 +18,65 @@ window.App = window.App || {};
|
|||
|
||||
window.App.boot = function() {
|
||||
new Vue({ el: '#content'});
|
||||
}
|
||||
}
|
||||
|
||||
window.App.util = {
|
||||
time: (function() {
|
||||
return new Date;
|
||||
}),
|
||||
version: (function() {
|
||||
return 1;
|
||||
}),
|
||||
format: {
|
||||
count: (function(count = 0) {
|
||||
if(count < 1) {
|
||||
return 0;
|
||||
}
|
||||
return new Intl.NumberFormat('en-GB', { notation: "compact" , compactDisplay: "short" }).format(count);
|
||||
})
|
||||
},
|
||||
filters: [
|
||||
['1977','filter-1977'],
|
||||
['Aden','filter-aden'],
|
||||
['Amaro','filter-amaro'],
|
||||
['Ashby','filter-ashby'],
|
||||
['Brannan','filter-brannan'],
|
||||
['Brooklyn','filter-brooklyn'],
|
||||
['Charmes','filter-charmes'],
|
||||
['Clarendon','filter-clarendon'],
|
||||
['Crema','filter-crema'],
|
||||
['Dogpatch','filter-dogpatch'],
|
||||
['Earlybird','filter-earlybird'],
|
||||
['Gingham','filter-gingham'],
|
||||
['Ginza','filter-ginza'],
|
||||
['Hefe','filter-hefe'],
|
||||
['Helena','filter-helena'],
|
||||
['Hudson','filter-hudson'],
|
||||
['Inkwell','filter-inkwell'],
|
||||
['Kelvin','filter-kelvin'],
|
||||
['Kuno','filter-juno'],
|
||||
['Lark','filter-lark'],
|
||||
['Lo-Fi','filter-lofi'],
|
||||
['Ludwig','filter-ludwig'],
|
||||
['Maven','filter-maven'],
|
||||
['Mayfair','filter-mayfair'],
|
||||
['Moon','filter-moon'],
|
||||
['Nashville','filter-nashville'],
|
||||
['Perpetua','filter-perpetua'],
|
||||
['Poprocket','filter-poprocket'],
|
||||
['Reyes','filter-reyes'],
|
||||
['Rise','filter-rise'],
|
||||
['Sierra','filter-sierra'],
|
||||
['Skyline','filter-skyline'],
|
||||
['Slumber','filter-slumber'],
|
||||
['Stinson','filter-stinson'],
|
||||
['Sutro','filter-sutro'],
|
||||
['Toaster','filter-toaster'],
|
||||
['Valencia','filter-valencia'],
|
||||
['Vesper','filter-vesper'],
|
||||
['Walden','filter-walden'],
|
||||
['Willow','filter-willow'],
|
||||
['X-Pro II','filter-xpro-ii']
|
||||
],
|
||||
emoji: ['😂','💯','❤️','🙌','👏','👌','😍','😯','😢','😅','😁','🙂','😎','😀','🤣','😃','😄','😆','😉','😊','😋','😘','😗','😙','😚','🤗','🤩','🤔','🤨','😐','😑','😶','🙄','😏','😣','😥','😮','🤐','😪','😫','😴','😌','😛','😜','😝','🤤','😒','😓','😔','😕','🙃','🤑','😲','🙁','😖','😞','😟','😤','😭','😦','😧','😨','😩','🤯','😬','😰','😱','😳','🤪','😵','😡','😠','🤬','😷','🤒','🤕','🤢','🤮','🤧','😇','🤠','🤡','🤥','🤫','🤭','🧐','🤓','😈','👿','👹','👺','💀','👻','👽','🤖','💩','😺','😸','😹','😻','😼','😽','🙀','😿','😾','🤲','👐','🤝','👍','👎','👊','✊','🤛','🤜','🤞','✌️','🤟','🤘','👈','👉','👆','👇','☝️','✋','🤚','🖐','🖖','👋','🤙','💪','🖕','✍️','🙏','💍','💄','💋','👄','👅','👂','👃','👣','👁','👀','🧠','🗣','👤','👥'],
|
||||
};
|
8
resources/assets/js/components.js
vendored
8
resources/assets/js/components.js
vendored
|
@ -3,7 +3,9 @@ import BootstrapVue from 'bootstrap-vue'
|
|||
import InfiniteLoading from 'vue-infinite-loading';
|
||||
import Loading from 'vue-loading-overlay';
|
||||
import VueTimeago from 'vue-timeago';
|
||||
import VueCarousel from 'vue-carousel';
|
||||
|
||||
Vue.use(VueCarousel);
|
||||
Vue.use(BootstrapVue);
|
||||
Vue.use(InfiniteLoading);
|
||||
Vue.use(Loading);
|
||||
|
@ -37,11 +39,7 @@ try {
|
|||
window.filesize = require('filesize');
|
||||
import swal from 'sweetalert';
|
||||
|
||||
$(document).ready(function() {
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
});
|
||||
});
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
|
||||
const warningTitleCSS = 'color:red; font-size:60px; font-weight: bold; -webkit-text-stroke: 1px black;';
|
||||
const warningDescCSS = 'font-size: 18px;';
|
||||
|
|
|
@ -201,7 +201,7 @@ export default {
|
|||
},
|
||||
|
||||
fetchRecentPosts() {
|
||||
axios.get('/api/local/accounts/' + this.profileId + '/statuses', {
|
||||
axios.get('/api/pixelfed/v1/accounts/' + this.profileId + '/statuses', {
|
||||
params: {
|
||||
only_media: true,
|
||||
min_id: 1,
|
||||
|
|
|
@ -1,15 +1,45 @@
|
|||
<template>
|
||||
<div>
|
||||
<input type="file" id="pf-dz" name="media" class="w-100 h-100 d-none file-input" draggable="true" v-bind:accept="config.uploader.media_types">
|
||||
<input type="file" id="pf-dz" name="media" class="w-100 h-100 d-none file-input" draggable="true" v-bind:accept="config.uploader.media_types" multiple="">
|
||||
<div class="timeline">
|
||||
<div v-if="uploading">
|
||||
<div class="card status-card card-md-rounded-0 w-100 h-100 bg-light py-5" style="border-bottom: 1px solid #f1f1f1">
|
||||
<div class="card status-card card-md-rounded-0 w-100 h-100 bg-light py-3" style="border-bottom: 1px solid #f1f1f1">
|
||||
<div class="p-5 mt-2">
|
||||
<b-progress :value="uploadProgress" :max="100" striped :animated="true"></b-progress>
|
||||
<p class="text-center mb-0 font-weight-bold">Uploading ... ({{uploadProgress}}%)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="page == 'cameraRoll'">
|
||||
<div class="card status-card card-md-rounded-0" style="display:flex;">
|
||||
<div class="card-header d-inline-flex align-items-center justify-content-between bg-white">
|
||||
<span class="pr-3">
|
||||
<i class="fas fa-cog fa-lg text-muted"></i>
|
||||
</span>
|
||||
<span class="font-weight-bold">
|
||||
Camera Roll
|
||||
</span>
|
||||
<span class="text-primary font-weight-bold">Upload</span>
|
||||
</div>
|
||||
<div class="h-100 card-body p-0 border-top" style="width:100%; min-height: 400px;">
|
||||
<div v-if="cameraRollMedia.length > 0" class="row p-0 m-0">
|
||||
<div v-for="(m, index) in cameraRollMedia" :class="[index == 0 ? 'col-12 p-0' : 'col-3 p-0']">
|
||||
<div class="card info-overlay p-0 rounded-0 shadow-none border">
|
||||
<div class="square">
|
||||
<img class="square-content" :src="m.preview_url"></img>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="w-100 h-100 d-flex justify-content-center align-items-center">
|
||||
<span class="w-100 h-100">
|
||||
<button type="button" class="btn btn-primary">Upload</button>
|
||||
<button type="button" class="btn btn-primary" @click="fetchCameraRollDrafts()">Load Camera Roll</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="card status-card card-md-rounded-0 w-100 h-100" style="display:flex;">
|
||||
<div class="card-header d-inline-flex align-items-center justify-content-between bg-white">
|
||||
|
@ -18,15 +48,25 @@
|
|||
<i class="fas fa-times fa-lg"></i>
|
||||
<span class="font-weight-bold mb-0">{{pageTitle}}</span>
|
||||
</a>
|
||||
<span v-else>
|
||||
<span>
|
||||
<a class="text-lighter text-decoration-none mr-3" href="#" @click.prevent="goBack()"><i class="fas fa-long-arrow-alt-left fa-lg"></i></a>
|
||||
</span>
|
||||
<span v-else-if="page == 2">
|
||||
<button v-if="config.uploader.album_limit > media.length" class="btn btn-outline-primary btn-sm font-weight-bold" @click.prevent="addMedia" data-toggle="tooltip" data-placement="bottom" title="Upload another photo or video" ><i class="fas fa-plus"></i></button>
|
||||
<!-- <button v-if="config.uploader.album_limit > media.length" class="btn btn-outline-primary btn-sm font-weight-bold" @click.prevent="page = 'cameraRoll'" data-toggle="tooltip" data-placement="bottom" title="Upload another photo or video" ><i class="fas fa-chevron-left"></i> Camera Roll</button> -->
|
||||
<button v-else class="btn btn-outline-secondary btn-sm font-weight-bold" disabled><i class="fas fa-plus"></i></button>
|
||||
</span>
|
||||
<span v-else-if="page == 3">
|
||||
<a class="text-lighter text-decoration-none mr-3 d-flex align-items-center" href="#" @click.prevent="goBack()">
|
||||
<i class="fas fa-long-arrow-alt-left fa-lg mr-2"></i>
|
||||
<span class="btn btn-outline-secondary btn-sm px-2 py-0 disabled" disabled="">{{media.length}}</span>
|
||||
</a>
|
||||
<span class="font-weight-bold mb-0">{{pageTitle}}</span>
|
||||
</span>
|
||||
<span v-else>
|
||||
<a class="text-lighter text-decoration-none mr-3" href="#" @click.prevent="goBack()"><i class="fas fa-long-arrow-alt-left fa-lg"></i></a>
|
||||
</span>
|
||||
<span class="font-weight-bold mb-0">{{pageTitle}}</span>
|
||||
</div>
|
||||
<div v-if="page == 2">
|
||||
<a href="#" class="text-center text-dark" @click.prevent="showCropPhotoCard"><i class="fas fa-magic fa-lg"></i></a>
|
||||
<a v-if="media.length == 1" href="#" class="text-center text-dark" @click.prevent="showCropPhotoCard"><i class="fas fa-magic fa-lg"></i></a>
|
||||
</div>
|
||||
<div>
|
||||
<!-- <a v-if="page > 1" class="font-weight-bold text-decoration-none" href="#" @click.prevent="page--">Back</a> -->
|
||||
|
@ -37,31 +77,65 @@
|
|||
</span>
|
||||
<span v-else>
|
||||
<a v-if="!pageLoading && (page > 1 && page <= 2) || (page == 1 && ids.length != 0) || page == 'cropPhoto'" class="font-weight-bold text-decoration-none" href="#" @click.prevent="nextPage">Next</a>
|
||||
<a v-if="!pageLoading && page == 3" class="font-weight-bold text-decoration-none" href="#" @click.prevent="compose">Post</a>
|
||||
<a v-if="!pageLoading && page == 3" class="font-weight-bold text-decoration-none" href="#" @click.prevent="compose()">Post</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-0 border-top">
|
||||
<div v-if="page == 1" class="w-100 h-100 d-flex justify-content-center align-items-center" style="min-height: 400px;">
|
||||
<div class="text-center">
|
||||
<p>
|
||||
<a class="btn btn-primary font-weight-bold" href="/i/compose">Compose Post</a>
|
||||
</p>
|
||||
<a class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="/i/compose">
|
||||
<div class="card-body">
|
||||
<div class="media">
|
||||
<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;background-color: #008DF5">
|
||||
<i class="far fa-image text-white fa-lg"></i>
|
||||
</div>
|
||||
<div class="media-body text-left">
|
||||
<h5 class="mt-0 font-weight-bold text-primary">New Post</h5>
|
||||
<p class="mb-0 text-muted">Share up to {{config.uploader.album_limit}} photos or videos.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark" href="/i/collections/create">
|
||||
<div class="card-body">
|
||||
<div class="media">
|
||||
<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;background-color: #008DF5">
|
||||
<i class="fas fa-images text-white fa-lg"></i>
|
||||
</div>
|
||||
<div class="media-body text-left">
|
||||
<p class="mb-0">
|
||||
<span class="h5 mt-0 font-weight-bold text-primary">New Collection</span>
|
||||
</p>
|
||||
<p class="mb-0 text-muted">Create a curated collection of photos.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div v-if="media.length == 0" class="card mx-md-5 my-md-3 shadow-none border compose-action text-decoration-none text-dark">
|
||||
<div @click.prevent="addMedia" class="card-body">
|
||||
<div class="media">
|
||||
<div class="mr-3 align-items-center justify-content-center" style="display:inline-flex;width:40px;height:40px;border-radius: 100%;background-color: #008DF5">
|
||||
<i class="fas fa-bolt text-white fa-lg"></i>
|
||||
</div>
|
||||
<div class="media-body text-left">
|
||||
<p class="mb-0">
|
||||
<span class="h5 mt-0 font-weight-bold text-primary">Try ComposeUI v4</span>
|
||||
<sup>
|
||||
<span class="badge badge-primary pb-1">BETA</span>
|
||||
</sup>
|
||||
</p>
|
||||
<p class="mb-0 text-muted">The next generation compose experience.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<p v-if="media.length == 0">
|
||||
<button type="button" class="btn btn-outline-primary font-weight-bold" @click.prevent="addMedia">Compose Post <sup>BETA</sup></button>
|
||||
</p>
|
||||
<p>
|
||||
<button class="btn btn-outline-primary font-weight-bold" @click.prevent="createCollection">New Collection</button>
|
||||
</p>
|
||||
<!-- <p>
|
||||
<button class="btn btn-outline-primary font-weight-bold" @click.prevent="showAddToStoryCard()">Add To My Story</button>
|
||||
</p> -->
|
||||
<p>
|
||||
<a class="font-weight-bold" href="/site/help">Need Help?</a>
|
||||
</p>
|
||||
<p class="text-muted mb-0 small text-center">Formats: <b>{{acceptedFormats()}}</b> up to <b>{{maxSize()}}</b></p>
|
||||
<p class="text-muted mb-0 small text-center">Albums can contain up to <b>{{config.uploader.album_limit}}</b> photos or videos</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -74,32 +148,74 @@
|
|||
:viewMode="cropper.viewMode"
|
||||
:zoomable="cropper.zoomable"
|
||||
:rotatable="true"
|
||||
:src="media[0].url"
|
||||
:src="media[carouselCursor].url"
|
||||
>
|
||||
</vue-cropper>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="page == 2" class="w-100 h-100">
|
||||
<div slot="img" style="display:flex;min-height: 420px;align-items: center;">
|
||||
<img :class="'d-block img-fluid w-100 ' + [media[carouselCursor].filter_class?media[carouselCursor].filter_class:'']" :src="media[carouselCursor].url" :alt="media[carouselCursor].description" :title="media[carouselCursor].description">
|
||||
<div v-if="media.length == 1">
|
||||
<div slot="img" style="display:flex;min-height: 420px;align-items: center;">
|
||||
<img :class="'d-block img-fluid w-100 ' + [media[carouselCursor].filter_class?media[carouselCursor].filter_class:'']" :src="media[carouselCursor].url" :alt="media[carouselCursor].description" :title="media[carouselCursor].description">
|
||||
</div>
|
||||
<hr>
|
||||
<div v-if="ids.length > 0 && media[carouselCursor].type == 'Image'" class="align-items-center px-2 pt-2">
|
||||
<ul class="nav media-drawer-filters text-center">
|
||||
<li class="nav-item">
|
||||
<div class="p-1 pt-3">
|
||||
<img :src="media[carouselCursor].url" width="100px" height="60px" v-on:click.prevent="toggleFilter($event, null)" class="cursor-pointer">
|
||||
</div>
|
||||
<a :class="[media[carouselCursor].filter_class == null ? 'nav-link text-primary active' : 'nav-link text-muted']" href="#" v-on:click.prevent="toggleFilter($event, null)">No Filter</a>
|
||||
</li>
|
||||
<li class="nav-item" v-for="(filter, index) in filters">
|
||||
<div class="p-1 pt-3">
|
||||
<img :src="media[carouselCursor].url" width="100px" height="60px" :class="filter[1]" v-on:click.prevent="toggleFilter($event, filter[1])">
|
||||
</div>
|
||||
<a :class="[media[carouselCursor].filter_class == filter[1] ? 'nav-link text-primary active' : 'nav-link text-muted']" href="#" v-on:click.prevent="toggleFilter($event, filter[1])">{{filter[0]}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div v-if="ids.length > 0 && media[carouselCursor].type == 'Image'" class="align-items-center px-2 pt-2">
|
||||
<div v-else-if="media.length > 1" class="d-flex-inline px-2 pt-2">
|
||||
<ul class="nav media-drawer-filters text-center">
|
||||
<li class="nav-item">
|
||||
<div class="p-1 pt-3">
|
||||
<img :src="media[carouselCursor].url" width="100px" height="60px" v-on:click.prevent="toggleFilter($event, null)" class="cursor-pointer">
|
||||
</div>
|
||||
<a :class="[media[carouselCursor].filter_class == null ? 'nav-link text-primary active' : 'nav-link text-muted']" href="#" v-on:click.prevent="toggleFilter($event, null)">No Filter</a>
|
||||
</li>
|
||||
<li class="nav-item" v-for="(filter, index) in filters">
|
||||
<div class="p-1 pt-3">
|
||||
<img :src="media[carouselCursor].url" width="100px" height="60px" :class="filter[1]" v-on:click.prevent="toggleFilter($event, filter[1])">
|
||||
</div>
|
||||
<a :class="[media[carouselCursor].filter_class == filter[1] ? 'nav-link text-primary active' : 'nav-link text-muted']" href="#" v-on:click.prevent="toggleFilter($event, filter[1])">{{filter[0]}}</a>
|
||||
<li class="nav-item mx-md-4"> </li>
|
||||
<li v-for="(m, i) in media" class="nav-item mx-md-4">
|
||||
<div class="nav-link" style="display:block;width:300px;height:300px;" @click="carouselCursor = i">
|
||||
<!-- <img :class="'d-block img-fluid w-100 ' + [m.filter_class?m.filter_class:'']" :src="m.url" :alt="m.description" :title="m.description"> -->
|
||||
<span :class="[m.filter_class?m.filter_class:'']">
|
||||
|
||||
<span :class="'rounded border ' + [i == carouselCursor ? ' border-primary shadow':'']" :style="'display:block;padding:5px;width:100%;height:100%;background-image: url(' + m.url + ');background-size:cover;border-width:3px !important;'"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="i == carouselCursor" class="text-center mb-0 small text-lighter font-weight-bold pt-2">
|
||||
<span class="cursor-pointer" @click.prevent="showCropPhotoCard">Crop</span>
|
||||
<span class="cursor-pointer px-3" @click.prevent="showEditMediaCard()">Edit</span>
|
||||
<span class="cursor-pointer" @click="deleteMedia()">Delete</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item mx-md-4"> </li>
|
||||
</ul>
|
||||
<hr>
|
||||
<div v-if="ids.length > 0 && media[carouselCursor].type == 'Image'" class="align-items-center px-2 pt-2">
|
||||
<ul class="nav media-drawer-filters text-center">
|
||||
<li class="nav-item">
|
||||
<div class="p-1 pt-3">
|
||||
<img :src="media[carouselCursor].url" width="100px" height="60px" v-on:click.prevent="toggleFilter($event, null)" class="cursor-pointer">
|
||||
</div>
|
||||
<a :class="[media[carouselCursor].filter_class == null ? 'nav-link text-primary active' : 'nav-link text-muted']" href="#" v-on:click.prevent="toggleFilter($event, null)">No Filter</a>
|
||||
</li>
|
||||
<li class="nav-item" v-for="(filter, index) in filters">
|
||||
<div class="p-1 pt-3">
|
||||
<img :src="media[carouselCursor].url" width="100px" height="60px" :class="filter[1]" v-on:click.prevent="toggleFilter($event, filter[1])">
|
||||
</div>
|
||||
<a :class="[media[carouselCursor].filter_class == filter[1] ? 'nav-link text-primary active' : 'nav-link text-muted']" href="#" v-on:click.prevent="toggleFilter($event, filter[1])">{{filter[0]}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="mb-0 p-5 text-center font-weight-bold">An error occured, please refresh the page.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -116,16 +232,27 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-bottom">
|
||||
<p class="px-4 mb-0 py-2 cursor-pointer" @click="showTagCard()">Tag people</p>
|
||||
<div class="border-bottom d-flex justify-content-between px-4 mb-0 py-2 ">
|
||||
<div>
|
||||
<div class="text-dark ">Contains NSFW Media</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="custom-control custom-switch" style="z-index: 9999;">
|
||||
<input type="checkbox" class="custom-control-input" id="asnsfw" v-model="nsfw">
|
||||
<label class="custom-control-label" for="asnsfw"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="border-bottom">
|
||||
<p class="px-4 mb-0 py-2 cursor-pointer" @click="showTagCard()">Tag people</p>
|
||||
</div> -->
|
||||
<div class="border-bottom">
|
||||
<p class="px-4 mb-0 py-2 cursor-pointer" @click="showLocationCard()" v-if="!place">Add location</p>
|
||||
<p v-else class="px-4 mb-0 py-2">
|
||||
<span class="text-lighter">Location:</span> {{place.name}}, {{place.country}}
|
||||
<span class="float-right">
|
||||
<a href="#" @click.prevent="showLocationCard()" class="text-muted font-weight-bold small mr-2">Change</a>
|
||||
<a href="#" @click.prevent="place = false" class="text-muted font-weight-bold small">Remove</a>
|
||||
<a href="#" @click.prevent="showLocationCard()" class="btn btn-outline-secondary btn-sm small mr-2" style="font-size:10px;padding:3px;text-transform: uppercase">Edit</a>
|
||||
<a href="#" @click.prevent="place = false" class="btn btn-outline-secondary btn-sm small" style="font-size:10px;padding:3px;text-transform: uppercase">Remove</a>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -133,10 +260,22 @@
|
|||
<p class="px-4 mb-0 py-2">
|
||||
<span class="text-lighter">Visibility:</span> {{visibilityTag}}
|
||||
<span class="float-right">
|
||||
<a href="#" @click.prevent="showVisibilityCard()" class="text-muted font-weight-bold small mr-2">Change</a>
|
||||
<a v-if="profile.locked == false" href="#" @click.prevent="showVisibilityCard()" class="btn btn-outline-secondary btn-sm small mr-2" style="font-size:10px;padding:3px;text-transform: uppercase">Edit</a>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<!-- <div class="cursor-pointer border-bottom px-4 mb-0 py-2" @click.prevent="showMediaDescriptionsCard()">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<div class="text-dark">Media Descriptions</div>
|
||||
<p class="text-muted small mb-0">Describe your photos for people with visual impairments.</p>
|
||||
</div>
|
||||
<div>
|
||||
<i class="fas fa-chevron-right fa-lg text-lighter"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div style="min-height: 200px;">
|
||||
<p class="px-4 mb-0 py-2 small font-weight-bold text-muted cursor-pointer" @click="showAdvancedSettingsCard()">Advanced settings</p>
|
||||
</div>
|
||||
|
@ -172,33 +311,50 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item d-flex justify-content-between">
|
||||
<div>
|
||||
<div class="text-dark ">Contains NSFW Media</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="custom-control custom-switch" style="z-index: 9999;">
|
||||
<input type="checkbox" class="custom-control-input" id="asnsfw" v-model="nsfw">
|
||||
<label class="custom-control-label" for="asnsfw"></label>
|
||||
<a href="#" class="list-group-item" @click.prevent="showMediaDescriptionsCard()">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<div class="text-dark">Media Descriptions</div>
|
||||
<p class="text-muted small mb-0">Describe your photos for people with visual impairments.</p>
|
||||
</div>
|
||||
<div>
|
||||
<i class="fas fa-chevron-right fa-lg text-lighter"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" class="list-group-item" @click.prevent="page = 'altText'">
|
||||
<div class="text-dark">Write alt text</div>
|
||||
<p class="text-muted small mb-0">Alt text describes your photos for people with visual impairments.</p>
|
||||
</a>
|
||||
<a href="#" class="list-group-item" @click.prevent="page = 'addToCollection'">
|
||||
<div class="text-dark">Add to Collection</div>
|
||||
<p class="text-muted small mb-0">Add this post to a collection.</p>
|
||||
<!-- <a href="#" class="list-group-item" @click.prevent="showAddToCollectionsCard()">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<div class="text-dark">Add to Collection</div>
|
||||
<p class="text-muted small mb-0">Add this post to a collection.</p>
|
||||
</div>
|
||||
<div>
|
||||
<i class="fas fa-chevron-right fa-lg text-lighter"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" class="list-group-item" @click.prevent="page = 'schedulePost'">
|
||||
<div class="text-dark">Schedule</div>
|
||||
<p class="text-muted small mb-0">Schedule post for a future date.</p>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<div class="text-dark">Schedule</div>
|
||||
<p class="text-muted small mb-0">Schedule post for a future date.</p>
|
||||
</div>
|
||||
<div>
|
||||
<i class="fas fa-chevron-right fa-lg text-lighter"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" class="list-group-item" @click.prevent="page = 'mediaMetadata'">
|
||||
<div class="text-dark">Metadata</div>
|
||||
<p class="text-muted small mb-0">Manage media exif and metadata.</p>
|
||||
</a>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<div class="text-dark">Metadata</div>
|
||||
<p class="text-muted small mb-0">Manage media exif and metadata.</p>
|
||||
</div>
|
||||
<div>
|
||||
<i class="fas fa-chevron-right fa-lg text-lighter"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -211,11 +367,38 @@
|
|||
</div>
|
||||
|
||||
<div v-if="page == 'altText'" class="w-100 h-100 p-3">
|
||||
<p class="text-center lead text-muted mb-0 py-5">This feature is not available yet.</p>
|
||||
<div v-for="(m, index) in media">
|
||||
<div class="media">
|
||||
<img :src="m.preview_url" class="mr-3" width="50px" height="50px">
|
||||
<div class="media-body">
|
||||
<textarea class="form-control" v-model="m.alt" placeholder="Add a media description here..."></textarea>
|
||||
<p class="help-text small text-right text-muted mb-0">{{m.alt ? m.alt.length : 0}}/140</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
<p class="d-flex justify-content-between mb-0">
|
||||
<button type="button" @click="goBack()" class="btn btn-link text-muted font-weight-bold text-decoration-none">Cancel</button>
|
||||
<button type="button" @click="goBack()" class="btn btn-primary font-weight-bold">Save</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="page == 'addToCollection'" class="w-100 h-100 p-3">
|
||||
<p class="text-center lead text-muted mb-0 py-5">This feature is not available yet.</p>
|
||||
<div class="list-group mb-3">
|
||||
<div class="list-group-item cursor-pointer compose-action border" @click="goBack()">
|
||||
<div class="media">
|
||||
<img src="" class="mr-3" alt="" width="50px" height="50px">
|
||||
<div class="media-body">
|
||||
<h5 class="mt-0">collection title</h5>
|
||||
<p class="mb-0 text-muted small">3 Photos - Created 2h ago</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="d-flex justify-content-between mb-0">
|
||||
<button type="button" @click="goBack()" class="btn btn-link text-muted font-weight-bold text-decoration-none">Cancel</button>
|
||||
<button type="button" @click="goBack()" class="btn btn-primary font-weight-bold">Save</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="page == 'schedulePost'" class="w-100 h-100 p-3">
|
||||
|
@ -230,6 +413,35 @@
|
|||
<p class="text-center lead text-muted mb-0 py-5">This feature is not available yet.</p>
|
||||
</div>
|
||||
|
||||
<div v-if="page == 'editMedia'" class="w-100 h-100 p-3">
|
||||
<div class="media">
|
||||
<img :src="media[carouselCursor].preview_url" class="mr-3" width="50px" height="50px">
|
||||
<div class="media-body">
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted small">Media Description</label>
|
||||
<textarea class="form-control" v-model="media[carouselCursor].alt" placeholder="Add a media description here..."></textarea>
|
||||
<p class="help-text small text-muted mb-0 d-flex justify-content-between">
|
||||
<span>Describe your photo for people with visual impairments.</span>
|
||||
<span>{{media[carouselCursor].alt ? media[carouselCursor].alt.length : 0}}/140</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="font-weight-bold text-muted small">License</label>
|
||||
<input type="text" class="form-control" v-model="media[carouselCursor].license" placeholder="All Rights Reserved (Default license)">
|
||||
<p class="help-text small text-muted mb-0 d-flex justify-content-between">
|
||||
<span></span>
|
||||
<span>{{media[carouselCursor].license ? media[carouselCursor].license.length : 0}}/140</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<p class="d-flex justify-content-between mb-0">
|
||||
<button type="button" @click="goBack()" class="btn btn-link text-muted font-weight-bold text-decoration-none">Cancel</button>
|
||||
<button type="button" @click="goBack()" class="btn btn-primary font-weight-bold">Save</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- card-footers -->
|
||||
|
@ -258,6 +470,10 @@
|
|||
overflow-x: scroll;
|
||||
flex-wrap:unset;
|
||||
}
|
||||
.media-drawer-filters::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
background: transparent;
|
||||
}
|
||||
.media-drawer-filters .nav-link {
|
||||
min-width:100px;
|
||||
padding-top: 1rem;
|
||||
|
@ -284,6 +500,10 @@
|
|||
text-decoration: none;
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
.compose-action:hover {
|
||||
cursor: pointer;
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
@ -340,8 +560,11 @@ export default {
|
|||
'addToCollection',
|
||||
'schedulePost',
|
||||
'mediaMetadata',
|
||||
'addToStory'
|
||||
]
|
||||
'addToStory',
|
||||
'editMedia',
|
||||
'cameraRoll'
|
||||
],
|
||||
cameraRollMedia: []
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -350,53 +573,17 @@ export default {
|
|||
if(this.config.uploader.media_types.includes('video/mp4') == false) {
|
||||
this.composeType = 'post'
|
||||
}
|
||||
this.filters = window.App.util.filters;
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.mediaWatcher();
|
||||
this.filters = [
|
||||
['1977','filter-1977'],
|
||||
['Aden','filter-aden'],
|
||||
['Amaro','filter-amaro'],
|
||||
['Ashby','filter-ashby'],
|
||||
['Brannan','filter-brannan'],
|
||||
['Brooklyn','filter-brooklyn'],
|
||||
['Charmes','filter-charmes'],
|
||||
['Clarendon','filter-clarendon'],
|
||||
['Crema','filter-crema'],
|
||||
['Dogpatch','filter-dogpatch'],
|
||||
['Earlybird','filter-earlybird'],
|
||||
['Gingham','filter-gingham'],
|
||||
['Ginza','filter-ginza'],
|
||||
['Hefe','filter-hefe'],
|
||||
['Helena','filter-helena'],
|
||||
['Hudson','filter-hudson'],
|
||||
['Inkwell','filter-inkwell'],
|
||||
['Kelvin','filter-kelvin'],
|
||||
['Kuno','filter-juno'],
|
||||
['Lark','filter-lark'],
|
||||
['Lo-Fi','filter-lofi'],
|
||||
['Ludwig','filter-ludwig'],
|
||||
['Maven','filter-maven'],
|
||||
['Mayfair','filter-mayfair'],
|
||||
['Moon','filter-moon'],
|
||||
['Nashville','filter-nashville'],
|
||||
['Perpetua','filter-perpetua'],
|
||||
['Poprocket','filter-poprocket'],
|
||||
['Reyes','filter-reyes'],
|
||||
['Rise','filter-rise'],
|
||||
['Sierra','filter-sierra'],
|
||||
['Skyline','filter-skyline'],
|
||||
['Slumber','filter-slumber'],
|
||||
['Stinson','filter-stinson'],
|
||||
['Sutro','filter-sutro'],
|
||||
['Toaster','filter-toaster'],
|
||||
['Valencia','filter-valencia'],
|
||||
['Vesper','filter-vesper'],
|
||||
['Walden','filter-walden'],
|
||||
['Willow','filter-willow'],
|
||||
['X-Pro II','filter-xpro-ii']
|
||||
];
|
||||
},
|
||||
|
||||
updated() {
|
||||
if(this.page == 2) {
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
@ -406,6 +593,7 @@ export default {
|
|||
window.pixelfed.currentUser = res.data;
|
||||
if(res.data.locked == true) {
|
||||
this.visibility = 'private';
|
||||
this.visibilityTag = 'Followers Only';
|
||||
}
|
||||
}).catch(err => {
|
||||
});
|
||||
|
@ -422,7 +610,6 @@ export default {
|
|||
|
||||
mediaWatcher() {
|
||||
let self = this;
|
||||
self.mediaDragAndDrop();
|
||||
$(document).on('change', '#pf-dz', function(e) {
|
||||
self.mediaUpload();
|
||||
});
|
||||
|
@ -435,6 +622,8 @@ export default {
|
|||
Array.prototype.forEach.call(io.files, function(io, i) {
|
||||
if(self.media && self.media.length + i >= self.config.uploader.album_limit) {
|
||||
swal('Error', 'You can only upload ' + self.config.uploader.album_limit + ' photos per album', 'error');
|
||||
self.uploading = false;
|
||||
self.page = 2;
|
||||
return;
|
||||
}
|
||||
let type = io.type;
|
||||
|
@ -442,6 +631,8 @@ export default {
|
|||
let validated = $.inArray(type, acceptedMimes);
|
||||
if(validated == -1) {
|
||||
swal('Invalid File Type', 'The file you are trying to add is not a valid mime type. Please upload a '+self.config.uploader.media_types+' only.', 'error');
|
||||
self.uploading = false;
|
||||
self.page = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -460,113 +651,50 @@ export default {
|
|||
self.uploadProgress = 100;
|
||||
self.ids.push(e.data.id);
|
||||
self.media.push(e.data);
|
||||
self.page = 2;
|
||||
self.uploading = false;
|
||||
setTimeout(function() {
|
||||
self.uploading = false;
|
||||
}, 1000);
|
||||
self.page = 2;
|
||||
}, 300);
|
||||
}).catch(function(e) {
|
||||
self.uploading = false;
|
||||
io.value = null;
|
||||
swal('Oops, something went wrong!', 'An unexpected error occurred.', 'error');
|
||||
self.page = 2;
|
||||
});
|
||||
io.value = null;
|
||||
self.uploadProgress = 0;
|
||||
});
|
||||
},
|
||||
|
||||
mediaDragAndDrop() {
|
||||
|
||||
let self = this;
|
||||
let pdz = document.getElementById('content');
|
||||
|
||||
|
||||
function allowDrag(e) {
|
||||
e.dataTransfer.dropEffect = 'copy';
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function handleDrop(e) {
|
||||
e.preventDefault();
|
||||
// let dz = document.querySelector('#pf-dz');
|
||||
// dz.files = e.dataTransfer.files;
|
||||
// $('#composeModal').modal('show');
|
||||
// self.mediaUpload();
|
||||
}
|
||||
|
||||
window.addEventListener('dragenter', function(e) {
|
||||
});
|
||||
|
||||
pdz.addEventListener('dragenter', allowDrag);
|
||||
pdz.addEventListener('dragover', allowDrag);
|
||||
|
||||
pdz.addEventListener('dragleave', function(e) {
|
||||
//
|
||||
});
|
||||
|
||||
pdz.addEventListener('drop', handleDrop);
|
||||
},
|
||||
|
||||
toggleFilter(e, filter) {
|
||||
this.media[this.carouselCursor].filter_class = filter;
|
||||
},
|
||||
|
||||
updateMedia() {
|
||||
this.mediaDrawer = false;
|
||||
},
|
||||
|
||||
deleteMedia() {
|
||||
if(window.confirm('Are you sure you want to delete this media?') == false) {
|
||||
return;
|
||||
}
|
||||
let id = this.media[this.carouselCursor].id;
|
||||
|
||||
axios.delete('/api/pixelfed/v1/media', {
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
}).then(res => {
|
||||
if(this.media.length == 1) {
|
||||
this.mediaDrawer = false;
|
||||
this.ids.splice(this.carouselCursor, 1);
|
||||
this.media.splice(this.carouselCursor, 1);
|
||||
if(this.media.length == 0) {
|
||||
this.ids = [];
|
||||
this.media = [];
|
||||
this.carouselCursor = 0;
|
||||
} else {
|
||||
this.carouselCursor = 0;
|
||||
}
|
||||
this.ids.splice(this.carouselCursor, 1);
|
||||
this.media.splice(this.carouselCursor, 1);
|
||||
}).catch(err => {
|
||||
swal('Whoops!', 'An error occured when attempting to delete this, please try again', 'error');
|
||||
});
|
||||
},
|
||||
|
||||
mediaAltText() {
|
||||
return;
|
||||
// deprecate
|
||||
swal({
|
||||
text: 'Add a media description',
|
||||
content: "input"
|
||||
}).then(val => {
|
||||
let media = this.media[this.carouselCursor];
|
||||
media.alt = val;
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
mediaLicense() {
|
||||
return;
|
||||
// deprecate
|
||||
swal({
|
||||
text: 'Add a media license',
|
||||
content: "input",
|
||||
button: {
|
||||
text: "Update",
|
||||
closeModal: true,
|
||||
},
|
||||
}).then(val => {
|
||||
let media = this.media[this.carouselCursor];
|
||||
media.license = val;
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
compose() {
|
||||
let state = this.composeState;
|
||||
|
||||
|
@ -607,7 +735,6 @@ export default {
|
|||
break;
|
||||
|
||||
case 'delete' :
|
||||
this.mediaDrawer = false;
|
||||
this.ids = [];
|
||||
this.media = [];
|
||||
this.carouselCursor = 0;
|
||||
|
@ -619,35 +746,28 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
about() {
|
||||
let text = document.createElement('div');
|
||||
text.innerHTML = `
|
||||
<p class="small font-weight-bold">Please visit the <a href="/site/kb/sharing-media">Sharing Media</a> page for more info.</p>
|
||||
`;
|
||||
swal({
|
||||
title: 'Compose UI v3',
|
||||
content: text,
|
||||
icon: 'info'
|
||||
});
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.composeType = '';
|
||||
$('#composeModal').modal('hide');
|
||||
},
|
||||
|
||||
composeMessage() {
|
||||
let config = this.config;
|
||||
let composeType = this.composeType;
|
||||
let video = config.uploader.media_types.includes('video/mp4');
|
||||
goBack() {
|
||||
this.pageTitle = '';
|
||||
|
||||
switch(this.page) {
|
||||
case 'addToStory':
|
||||
this.page = 1;
|
||||
break;
|
||||
|
||||
return video ?
|
||||
'Click here to add photos or videos' :
|
||||
'Click here to add photos';
|
||||
},
|
||||
case 'cropPhoto':
|
||||
case 'editMedia':
|
||||
this.page = 2;
|
||||
break;
|
||||
|
||||
createCollection() {
|
||||
window.location.href = '/i/collections/create';
|
||||
default:
|
||||
this.namedPages.indexOf(this.page) != -1 ? this.page = 3 : this.page--;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
nextPage() {
|
||||
|
@ -696,18 +816,6 @@ export default {
|
|||
this.$refs.cropper.setAspectRatio(ratio);
|
||||
},
|
||||
|
||||
maxSize() {
|
||||
let limit = this.config.uploader.max_photo_size;
|
||||
return limit / 1000 + ' MB';
|
||||
},
|
||||
|
||||
acceptedFormats() {
|
||||
let formats = this.config.uploader.media_types;
|
||||
return formats.split(',').map(f => {
|
||||
return ' ' + f.split('/')[1];
|
||||
}).toString();
|
||||
},
|
||||
|
||||
showTagCard() {
|
||||
this.pageTitle = 'Tag People';
|
||||
this.page = 'tagPeople';
|
||||
|
@ -746,24 +854,6 @@ export default {
|
|||
return;
|
||||
},
|
||||
|
||||
goBack() {
|
||||
this.pageTitle = '';
|
||||
|
||||
switch(this.page) {
|
||||
case 'addToStory':
|
||||
this.page = 1;
|
||||
break;
|
||||
|
||||
case 'cropPhoto':
|
||||
this.page = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
this.namedPages.indexOf(this.page) != -1 ? this.page = 3 : this.page--;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
showVisibilityCard() {
|
||||
this.pageTitle = 'Post Visibility';
|
||||
this.page = 'visibility';
|
||||
|
@ -789,6 +879,33 @@ export default {
|
|||
this.visibilityTag = tags[state];
|
||||
this.pageTitle = '';
|
||||
this.page = 3;
|
||||
},
|
||||
|
||||
showMediaDescriptionsCard() {
|
||||
this.pageTitle = 'Media Descriptions';
|
||||
this.page = 'altText';
|
||||
},
|
||||
|
||||
showAddToCollectionsCard() {
|
||||
this.pageTitle = 'Add to Collection';
|
||||
this.page = 'addToCollection';
|
||||
},
|
||||
|
||||
showSchedulePostCard() {
|
||||
this.pageTitle = 'Schedule Post';
|
||||
this.page = 'schedulePost';
|
||||
},
|
||||
|
||||
showEditMediaCard() {
|
||||
this.pageTitle = 'Edit Media';
|
||||
this.page = 'editMedia';
|
||||
},
|
||||
|
||||
fetchCameraRollDrafts() {
|
||||
axios.get('/api/pixelfed/local/drafts')
|
||||
.then(res => {
|
||||
this.cameraRollMedia = res.data;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,10 +117,21 @@
|
|||
<div class="d-flex flex-md-column flex-column-reverse h-100" style="overflow-y: auto;">
|
||||
<div class="card-body status-comments pb-5">
|
||||
<div class="status-comment">
|
||||
<p :class="[status.content.length > 620 ? 'mb-1 read-more' : 'mb-1']" style="overflow: hidden;">
|
||||
<a class="font-weight-bold pr-1 text-dark text-decoration-none" :href="statusProfileUrl">{{statusUsername}}</a>
|
||||
<span class="comment-text" :id="status.id + '-status-readmore'" v-html="status.content"></span>
|
||||
</p>
|
||||
<div v-if="showCaption != true">
|
||||
<span class="py-3">
|
||||
<a class="text-dark font-weight-bold mr-1" :href="status.account.url" v-bind:title="status.account.username">{{truncate(status.account.username,15)}}</a>
|
||||
<span class="text-break">
|
||||
<span class="font-italic text-muted">This comment may contain sensitive material</span>
|
||||
<span class="text-primary cursor-pointer pl-1" @click="showCaption = true">Show</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p :class="[status.content.length > 620 ? 'mb-1 read-more' : 'mb-1']" style="overflow: hidden;">
|
||||
<a class="font-weight-bold pr-1 text-dark text-decoration-none" :href="statusProfileUrl">{{statusUsername}}</a>
|
||||
<span class="comment-text" :id="status.id + '-status-readmore'" v-html="status.content"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="showComments">
|
||||
<hr>
|
||||
|
@ -214,19 +225,6 @@
|
|||
</div>
|
||||
<div v-if="showComments && user.length !== 0" class="card-footer bg-white px-2 py-0">
|
||||
<ul class="nav align-items-center emoji-reactions" style="overflow-x: scroll;flex-wrap: unset;">
|
||||
<li class="nav-item" v-on:click="emojiReaction">😂</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">💯</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">❤️</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">🙌</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">👏</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">👌</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">😍</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">😯</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">😢</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">😅</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">😁</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">🙂</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction">😎</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction" v-for="e in emoji">{{e}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -595,8 +593,9 @@ export default {
|
|||
loading: null,
|
||||
replyingToId: this.statusId,
|
||||
replyToIndex: 0,
|
||||
emoji: ['😀','🤣','😃','😄','😆','😉','😊','😋','😘','😗','😙','😚','🤗','🤩','🤔','🤨','😐','😑','😶','🙄','😏','😣','😥','😮','🤐','😪','😫','😴','😌','😛','😜','😝','🤤','😒','😓','😔','😕','🙃','🤑','😲','🙁','😖','😞','😟','😤','😭','😦','😧','😨','😩','🤯','😬','😰','😱','😳','🤪','😵','😡','😠','🤬','😷','🤒','🤕','🤢','🤮','🤧','😇','🤠','🤡','🤥','🤫','🤭','🧐','🤓','😈','👿','👹','👺','💀','👻','👽','🤖','💩','😺','😸','😹','😻','😼','😽','🙀','😿','😾','🤲','👐','🤝','👍','👎','👊','✊','🤛','🤜','🤞','✌️','🤟','🤘','👈','👉','👆','👇','☝️','✋','🤚','🖐','🖖','👋','🤙','💪','🖕','✍️','🙏','💍','💄','💋','👄','👅','👂','👃','👣','👁','👀','🧠','🗣','👤','👥'],
|
||||
emoji: window.App.util.emoji,
|
||||
showReadMore: true,
|
||||
showCaption: true,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -663,6 +662,7 @@ export default {
|
|||
self.likesPage = 2;
|
||||
self.sharesPage = 2;
|
||||
this.showMuteBlock();
|
||||
self.showCaption = !response.data.status.sensitive;
|
||||
if(self.status.comments_disabled == false) {
|
||||
self.showComments = true;
|
||||
this.fetchComments();
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<li class="nav-item">
|
||||
<div class="font-weight-light">
|
||||
<span class="text-dark text-center">
|
||||
<p class="font-weight-bold mb-0">{{profile.statuses_count}}</p>
|
||||
<p class="font-weight-bold mb-0">{{formatCount(profile.statuses_count)}}</p>
|
||||
<p class="text-muted mb-0 small">Posts</p>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -51,7 +51,7 @@
|
|||
<li class="nav-item">
|
||||
<div v-if="profileSettings.followers.count" class="font-weight-light">
|
||||
<a class="text-dark cursor-pointer text-center" v-on:click="followersModal()">
|
||||
<p class="font-weight-bold mb-0">{{profile.followers_count}}</p>
|
||||
<p class="font-weight-bold mb-0">{{formatCount(profile.followers_count)}}</p>
|
||||
<p class="text-muted mb-0 small">Followers</p>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -59,7 +59,7 @@
|
|||
<li class="nav-item">
|
||||
<div v-if="profileSettings.following.count" class="font-weight-light">
|
||||
<a class="text-dark cursor-pointer text-center" v-on:click="followingModal()">
|
||||
<p class="font-weight-bold mb-0">{{profile.following_count}}</p>
|
||||
<p class="font-weight-bold mb-0">{{formatCount(profile.following_count)}}</p>
|
||||
<p class="text-muted mb-0 small">Following</p>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -109,19 +109,19 @@
|
|||
<div class="d-none d-md-inline-flex profile-stats pb-3">
|
||||
<div class="font-weight-light pr-5">
|
||||
<span class="text-dark">
|
||||
<span class="font-weight-bold">{{profile.statuses_count}}</span>
|
||||
<span class="font-weight-bold">{{formatCount(profile.statuses_count)}}</span>
|
||||
Posts
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="profileSettings.followers.count" class="font-weight-light pr-5">
|
||||
<a class="text-dark cursor-pointer" v-on:click="followersModal()">
|
||||
<span class="font-weight-bold">{{profile.followers_count}}</span>
|
||||
<span class="font-weight-bold">{{formatCount(profile.followers_count)}}</span>
|
||||
Followers
|
||||
</a>
|
||||
</div>
|
||||
<div v-if="profileSettings.following.count" class="font-weight-light">
|
||||
<a class="text-dark cursor-pointer" v-on:click="followingModal()">
|
||||
<span class="font-weight-bold">{{profile.following_count}}</span>
|
||||
<span class="font-weight-bold">{{formatCount(profile.following_count)}}</span>
|
||||
Following
|
||||
</a>
|
||||
</div>
|
||||
|
@ -304,15 +304,15 @@
|
|||
<div v-if="profile.note" class="text-center text-muted p-3" v-html="profile.note"></div>
|
||||
<div class="pb-3 text-muted text-center">
|
||||
<a class="text-lighter" :href="profile.url">
|
||||
<span class="font-weight-bold">{{profile.statuses_count}}</span>
|
||||
<span class="font-weight-bold">{{formatCount(profile.statuses_count)}}</span>
|
||||
Posts
|
||||
</a>
|
||||
<a v-if="profileSettings.followers.count" class="text-lighter cursor-pointer px-3" v-on:click="followersModal()">
|
||||
<span class="font-weight-bold">{{profile.followers_count}}</span>
|
||||
<span class="font-weight-bold">{{formatCount(profile.followers_count)}}</span>
|
||||
Followers
|
||||
</a>
|
||||
<a v-if="profileSettings.following.count" class="text-lighter cursor-pointer" v-on:click="followingModal()">
|
||||
<span class="font-weight-bold">{{profile.following_count}}</span>
|
||||
<span class="font-weight-bold">{{formatCount(profile.following_count)}}</span>
|
||||
Following
|
||||
</a>
|
||||
</div>
|
||||
|
@ -1076,6 +1076,10 @@
|
|||
copyProfileLink() {
|
||||
navigator.clipboard.writeText(window.location.href);
|
||||
this.$refs.visitorContextMenu.hide();
|
||||
},
|
||||
|
||||
formatCount(count) {
|
||||
return App.util.format.count(count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="postPresenterContainer" @click="lightbox(status)">
|
||||
<div class="postPresenterContainer">
|
||||
<div v-if="status.pf_type === 'photo'" class="w-100">
|
||||
<photo-presenter :status="status" v-on:lightbox="lightbox"></photo-presenter>
|
||||
</div>
|
||||
|
@ -203,19 +203,6 @@
|
|||
|
||||
<div v-if="status.id == replyId && !status.comments_disabled" class="card-footer bg-white px-2 py-0">
|
||||
<ul class="nav align-items-center emoji-reactions" style="overflow-x: scroll;flex-wrap: unset;">
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">😂</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">💯</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">❤️</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">🙌</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">👏</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">👌</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">😍</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">😯</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">😢</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">😅</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">😁</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">🙂</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)">😎</li>
|
||||
<li class="nav-item" v-on:click="emojiReaction(status)" v-for="e in emoji">{{e}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -274,15 +261,15 @@
|
|||
<div class="card-footer bg-transparent border-0 mt-2 py-1">
|
||||
<div class="d-flex justify-content-between text-center">
|
||||
<span class="cursor-pointer" @click="redirect(profile.url)">
|
||||
<p class="mb-0 font-weight-bold">{{profile.statuses_count}}</p>
|
||||
<p class="mb-0 font-weight-bold">{{formatCount(profile.statuses_count)}}</p>
|
||||
<p class="mb-0 small text-muted">Posts</p>
|
||||
</span>
|
||||
<span class="cursor-pointer" @click="redirect(profile.url+'?md=followers')">
|
||||
<p class="mb-0 font-weight-bold">{{profile.followers_count}}</p>
|
||||
<p class="mb-0 font-weight-bold">{{formatCount(profile.followers_count)}}</p>
|
||||
<p class="mb-0 small text-muted">Followers</p>
|
||||
</span>
|
||||
<span class="cursor-pointer" @click="redirect(profile.url+'?md=following')">
|
||||
<p class="mb-0 font-weight-bold">{{profile.following_count}}</p>
|
||||
<p class="mb-0 font-weight-bold">{{formatCount(profile.following_count)}}</p>
|
||||
<p class="mb-0 small text-muted">Following</p>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -502,7 +489,7 @@
|
|||
showReadMore: true,
|
||||
replyStatus: {},
|
||||
replyText: '',
|
||||
emoji: ['😀','🤣','😃','😄','😆','😉','😊','😋','😘','😗','😙','😚','🤗','🤩','🤔','🤨','😐','😑','😶','🙄','😏','😣','😥','😮','🤐','😪','😫','😴','😌','😛','😜','😝','🤤','😒','😓','😔','😕','🙃','🤑','😲','🙁','😖','😞','😟','😤','😭','😦','😧','😨','😩','🤯','😬','😰','😱','😳','🤪','😵','😡','😠','🤬','😷','🤒','🤕','🤢','🤮','🤧','😇','🤠','🤡','🤥','🤫','🤭','🧐','🤓','😈','👿','👹','👺','💀','👻','👽','🤖','💩','😺','😸','😹','😻','😼','😽','🙀','😿','😾','🤲','👐','🤝','👍','👎','👊','✊','🤛','🤜','🤞','✌️','🤟','🤘','👈','👉','👆','👇','☝️','✋','🤚','🖐','🖖','👋','🤙','💪','🖕','✍️','🙏','💍','💄','💋','👄','👅','👂','👃','👣','👁','👀','🧠','🗣','👤','👥'],
|
||||
emoji: window.App.util.emoji,
|
||||
showHashtagPosts: false,
|
||||
hashtagPosts: [],
|
||||
hashtagPostsName: '',
|
||||
|
@ -592,7 +579,7 @@
|
|||
axios.get(apiUrl, {
|
||||
params: {
|
||||
max_id: this.max_id,
|
||||
limit: 4
|
||||
limit: 5
|
||||
}
|
||||
}).then(res => {
|
||||
let data = res.data;
|
||||
|
@ -1311,6 +1298,10 @@
|
|||
hideTips() {
|
||||
this.showTips = false;
|
||||
window.localStorage.setItem('metro-tips', false);
|
||||
},
|
||||
|
||||
formatCount(count) {
|
||||
return App.util.format.count(count);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
</b-carousel>
|
||||
</details>
|
||||
</div>
|
||||
<div v-else>
|
||||
<b-carousel :id="status.id + '-carousel'"
|
||||
<div v-else class="w-100 h-100 p-0">
|
||||
<!-- <b-carousel :id="status.id + '-carousel'"
|
||||
style="text-shadow: 1px 1px 2px #333; background-color: #000;"
|
||||
controls
|
||||
img-blank
|
||||
|
@ -49,7 +49,22 @@
|
|||
<p v-else class="text-center p-0 font-weight-bold text-white">Error: Problem rendering preview.</p>
|
||||
|
||||
</b-carousel-slide>
|
||||
</b-carousel>
|
||||
</b-carousel> -->
|
||||
<carousel ref="carousel" :centerMode="true" :loop="false" :per-page="1" :paginationPosition="'bottom-overlay'" paginationActiveColor="#3897f0" paginationColor="#dbdbdb">
|
||||
<slide v-for="(media, index) in status.media_attachments" :key="'px-carousel-'+media.id + '-' + index" class="w-100 h-100 d-block mx-auto text-center" style="max-height: 600px;">
|
||||
|
||||
<video v-if="media.type == 'Video'" class="embed-responsive-item" preload="none" controls loop :title="media.description" width="100%" height="100%" :poster="media.preview_url">
|
||||
<source :src="media.url" :type="media.mime">
|
||||
</video>
|
||||
|
||||
<div v-else-if="media.type == 'Image'" :title="media.description">
|
||||
<img :class="media.filter_class + ' img-fluid w-100'" :src="media.url" :alt="media.description" loading="lazy">
|
||||
</div>
|
||||
|
||||
<p v-else class="text-center p-0 font-weight-bold text-white">Error: Problem rendering preview.</p>
|
||||
|
||||
</slide>
|
||||
</carousel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<div v-if="status.sensitive == true">
|
||||
<details class="details-animated">
|
||||
<summary>
|
||||
<summary @click="loadSensitive">
|
||||
<p class="mb-0 lead font-weight-bold">{{ status.spoiler_text ? status.spoiler_text : 'CW / NSFW / Hidden Media'}}</p>
|
||||
<p class="font-weight-light">(click to show)</p>
|
||||
</summary>
|
||||
<b-carousel :id="status.id + '-carousel'"
|
||||
<!-- <b-carousel :id="status.id + '-carousel'"
|
||||
v-model="cursor"
|
||||
style="text-shadow: 1px 1px 2px #333;min-height: 330px;display: flex;align-items: center;"
|
||||
controls
|
||||
|
@ -20,11 +20,16 @@
|
|||
<span class="badge badge-dark box-shadow" style="position: absolute;top:10px;right:10px;">
|
||||
{{cursor + 1}} / {{status.media_attachments.length}}
|
||||
</span>
|
||||
</b-carousel>
|
||||
</b-carousel> -->
|
||||
<carousel ref="carousel" :centerMode="true" :loop="false" :per-page="1" :paginationPosition="'bottom-overlay'" paginationActiveColor="#3897f0" paginationColor="#dbdbdb">
|
||||
<slide v-for="(img, index) in status.media_attachments" :key="'px-carousel-'+img.id + '-' + index" class="w-100 h-100 d-block mx-auto text-center" style="max-height: 600px;" :title="img.description">
|
||||
<img :class="img.filter_class + ' img-fluid'" style="max-height: 600px;" :src="img.url" :alt="img.description">
|
||||
</slide>
|
||||
</carousel>
|
||||
</details>
|
||||
</div>
|
||||
<div v-else>
|
||||
<b-carousel :id="status.id + '-carousel'"
|
||||
<div v-else class="w-100 h-100 p-0">
|
||||
<!-- <b-carousel :id="status.id + '-carousel'"
|
||||
v-model="cursor"
|
||||
style="text-shadow: 1px 1px 2px #333;min-height: 330px;display: flex;align-items: center;"
|
||||
controls
|
||||
|
@ -39,7 +44,12 @@
|
|||
<span class="badge badge-dark box-shadow" style="position: absolute;top:10px;right:10px;">
|
||||
{{cursor + 1}} / {{status.media_attachments.length}}
|
||||
</span>
|
||||
</b-carousel>
|
||||
</b-carousel> -->
|
||||
<carousel ref="carousel" :centerMode="true" :loop="false" :per-page="1" :paginationPosition="'bottom-overlay'" paginationActiveColor="#3897f0" paginationColor="#dbdbdb" class="p-0 m-0">
|
||||
<slide v-for="(img, index) in status.media_attachments" :key="'px-carousel-'+img.id + '-' + index" class="" style="background: #000; display: flex;align-items: center;max-height: 600px;" :title="img.description">
|
||||
<img :class="img.filter_class + ' img-fluid w-100 p-0'" style="max-height: 600px;" :src="img.url" :alt="img.description">
|
||||
</slide>
|
||||
</carousel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -58,6 +68,42 @@
|
|||
return {
|
||||
cursor: 0
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
// window.addEventListener("keydown", this.keypressNavigation);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
// window.removeEventListener("keydown", this.keypressNavigation);
|
||||
},
|
||||
|
||||
methods: {
|
||||
loadSensitive() {
|
||||
this.$refs.carousel.onResize();
|
||||
this.$refs.carousel.goToPage(0);
|
||||
},
|
||||
|
||||
keypressNavigation(e) {
|
||||
let ref = this.$refs.carousel;
|
||||
if (e.keyCode == "37") {
|
||||
e.preventDefault();
|
||||
|
||||
let direction = "backward";
|
||||
|
||||
ref.advancePage(direction);
|
||||
ref.$emit("navigation-click", direction);
|
||||
}
|
||||
|
||||
if (e.keyCode == "39") {
|
||||
e.preventDefault();
|
||||
|
||||
let direction = "forward";
|
||||
|
||||
ref.advancePage(direction);
|
||||
ref.$emit("navigation-click", direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
7
resources/assets/sass/custom.scss
vendored
7
resources/assets/sass/custom.scss
vendored
|
@ -559,3 +559,10 @@ details summary::-webkit-details-marker {
|
|||
.carousel-control-prev-icon, .carousel-control-next-icon {
|
||||
filter: drop-shadow(0px 0px 1px black);
|
||||
}
|
||||
|
||||
.VueCarousel:focus,
|
||||
.VueCarousel-navigation-button:focus,
|
||||
.VueCarousel-dot:focus,
|
||||
.VueCarousel-dot--active:focus {
|
||||
outline: 0px !important;
|
||||
}
|
|
@ -3,6 +3,12 @@
|
|||
@section('content')
|
||||
|
||||
<div class="container px-0 mt-0 mt-md-4 mb-md-5 pb-md-5">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
<p class="lead mb-0">Some sections may contain out of date information</p>
|
||||
<p class="mb-0">We apologize for any inconvenience, we are working on updating the Help Center.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 px-0">
|
||||
<div class="card mt-md-5 px-0 mx-md-3">
|
||||
<div class="card-header font-weight-bold text-muted bg-white py-4">
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
<div class="card-body row pl-md-5 ml-md-5">
|
||||
@foreach(App\Util\Localization\Localization::languages() as $lang)
|
||||
<div class="col-12 col-md-4 mb-2">
|
||||
<a href="/i/lang/{{$lang}}" class="{{$current == $lang ? 'font-weight-bold text-primary' : 'text-muted'}} pr-3 b-3">{{locale_get_display_language($lang, $lang)}}</a>
|
||||
<a href="/i/lang/{{$lang}}" class="{{$current == $lang ? 'font-weight-bold text-primary' : 'text-muted'}} pr-3 b-3">
|
||||
{{locale_get_display_language($lang, $lang)}}
|
||||
<span class="small text-lighter">({{locale_get_display_language($lang, 'en')}})</span>
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
|
|
@ -198,7 +198,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
|
|||
Route::get('auth/checkpoint', 'AccountController@twoFactorCheckpoint');
|
||||
Route::post('auth/checkpoint', 'AccountController@twoFactorVerify');
|
||||
|
||||
Route::get('media/preview/{profileId}/{mediaId}', 'ApiController@showTempMedia')->name('temp-media');
|
||||
Route::get('media/preview/{profileId}/{mediaId}/{timestamp}', 'ApiController@showTempMedia')->name('temp-media');
|
||||
|
||||
Route::get('results', 'SearchController@results');
|
||||
Route::post('visibility', 'StatusController@toggleVisibility');
|
||||
|
|
Loading…
Reference in a new issue