Przeglądaj źródła

Merge pull request #5032 from pixelfed/staging

Staging
daniel 1 rok temu
rodzic
commit
57df06a0b6
59 zmienionych plików z 1537 dodań i 1348 usunięć
  1. 43 0
      CHANGELOG.md
  2. 3 2
      app/Http/Controllers/Api/ApiV1Controller.php
  3. 40 39
      app/Http/Controllers/Settings/PrivacySettings.php
  4. 162 221
      composer.lock
  5. 255 296
      package-lock.json
  6. BIN
      public/css/spa.css
  7. BIN
      public/js/account-import.js
  8. BIN
      public/js/admin.js
  9. BIN
      public/js/app.js
  10. BIN
      public/js/changelog.bundle.bf44edbbfa14bd53.js
  11. BIN
      public/js/changelog.bundle.d5810c2672b6abc7.js
  12. BIN
      public/js/compose.chunk.47ba00abaa827b26.js
  13. BIN
      public/js/compose.chunk.a0cfdf07f5062445.js
  14. BIN
      public/js/daci.chunk.34dc7bad3a0792cc.js
  15. BIN
      public/js/daci.chunk.a498fff65c83f174.js
  16. BIN
      public/js/discover.chunk.1404d3172761023b.js
  17. BIN
      public/js/discover.chunk.c2229e1d15bd3ada.js
  18. BIN
      public/js/discover~findfriends.chunk.29c7f06a6a4c6f61.js
  19. BIN
      public/js/discover~findfriends.chunk.b1858bea66d9723b.js
  20. BIN
      public/js/discover~hashtag.bundle.1b11b46e0b28aa3f.js
  21. BIN
      public/js/discover~hashtag.bundle.a0f00fc7df1f313c.js
  22. BIN
      public/js/discover~memories.chunk.321431bd290466d4.js
  23. BIN
      public/js/discover~memories.chunk.37e0c325f900e163.js
  24. BIN
      public/js/discover~myhashtags.chunk.4cc859102b24780c.js
  25. BIN
      public/js/discover~myhashtags.chunk.8886fc0d4736d819.js
  26. BIN
      public/js/discover~serverfeed.chunk.262bf7e3bce843c3.js
  27. BIN
      public/js/discover~serverfeed.chunk.b4c4ca11f3498bf1.js
  28. BIN
      public/js/discover~settings.chunk.07417fd0cd9c5833.js
  29. BIN
      public/js/discover~settings.chunk.65d6f3cbe5323ed4.js
  30. BIN
      public/js/dms.chunk.2b55effc0e8ba89f.js
  31. BIN
      public/js/dms.chunk.a42edfd973f6c593.js
  32. BIN
      public/js/dms~message.chunk.6cd795c99fc1a568.js
  33. BIN
      public/js/dms~message.chunk.976f7edaa6f71137.js
  34. 0 0
      public/js/error404.bundle.54601f9cdd0f7719.js
  35. BIN
      public/js/home.chunk.264eeb47bfac56c1.js
  36. BIN
      public/js/home.chunk.ccbe0267817f9a26.js
  37. 0 0
      public/js/home.chunk.ccbe0267817f9a26.js.LICENSE.txt
  38. BIN
      public/js/i18n.bundle.28bba3e12cdadf51.js
  39. BIN
      public/js/i18n.bundle.93a02e275ac1a708.js
  40. BIN
      public/js/landing.js
  41. BIN
      public/js/manifest.js
  42. BIN
      public/js/notifications.chunk.0c5151643e4534aa.js
  43. BIN
      public/js/notifications.chunk.1086603ea08d1017.js
  44. BIN
      public/js/portfolio.js
  45. BIN
      public/js/post.chunk.41ea9082b932e599.js
  46. 0 0
      public/js/post.chunk.41ea9082b932e599.js.LICENSE.txt
  47. BIN
      public/js/post.chunk.9184101a2b809af1.js
  48. BIN
      public/js/profile.chunk.a2234f891ba86efd.js
  49. BIN
      public/js/profile.chunk.e86bfb0eb7723ddc.js
  50. BIN
      public/js/profile~followers.bundle.50a39058d98e16eb.js
  51. BIN
      public/js/profile~followers.bundle.5d796e79f32d066c.js
  52. BIN
      public/js/profile~following.bundle.7ca7cfa5aaae75e2.js
  53. BIN
      public/js/profile~following.bundle.9294aa1b560387c7.js
  54. BIN
      public/js/spa.js
  55. BIN
      public/js/vendor.js
  56. BIN
      public/mix-manifest.json
  57. 1008 790
      resources/assets/components/partials/post/ContextMenu.vue
  58. 18 0
      resources/assets/components/sections/Timeline.vue
  59. 8 0
      resources/assets/sass/spa.scss

+ 43 - 0
CHANGELOG.md

@@ -19,6 +19,49 @@
 - Update SiteController, add curatedOnboarding method that gracefully falls back to open registration when applicable ([95199843](https://github.com/pixelfed/pixelfed/commit/95199843))
 - Update AP transformers, add DeleteActor activity ([bcce1df6](https://github.com/pixelfed/pixelfed/commit/bcce1df6))
 - Update commands, add user account delete cli command to federate account deletion ([4aa0e25f](https://github.com/pixelfed/pixelfed/commit/4aa0e25f))
+- Update web-api popular accounts route to its own method to remove the breaking oauth scope bug ([a4bc5ce3](https://github.com/pixelfed/pixelfed/commit/a4bc5ce3))
+- Update config cache ([5e4d4eff](https://github.com/pixelfed/pixelfed/commit/5e4d4eff))
+- Update Config, use config_cache ([7785a2da](https://github.com/pixelfed/pixelfed/commit/7785a2da))
+- Update ApiV1Dot1Controller, use config_cache for in-app registration ([b0cb4456](https://github.com/pixelfed/pixelfed/commit/b0cb4456))
+- Update captcha, use config_cache helper ([8a89e3c9](https://github.com/pixelfed/pixelfed/commit/8a89e3c9))
+- Update custom emoji, add config_cache support ([481314cd](https://github.com/pixelfed/pixelfed/commit/481314cd))
+- Update ProfileController, fix permalink redirect bug ([75081e60](https://github.com/pixelfed/pixelfed/commit/75081e60))
+- Update admin css, use font-display:swap for nucleo icons ([8a0c456e](https://github.com/pixelfed/pixelfed/commit/8a0c456e))
+- Update PixelfedDirectoryController, fix boolean cast bug ([f08aab22](https://github.com/pixelfed/pixelfed/commit/f08aab22))
+- Update PixelfedDirectoryController, use cached stats ([f2f2a809](https://github.com/pixelfed/pixelfed/commit/f2f2a809))
+- Update AdminDirectoryController, fix type casting ([ad506e90](https://github.com/pixelfed/pixelfed/commit/ad506e90))
+- Update image pipeline, use config_cache ([a72188a7](https://github.com/pixelfed/pixelfed/commit/a72188a7))
+- Update cloud storage, use config_cache ([665581d8](https://github.com/pixelfed/pixelfed/commit/665581d8))
+- Update pixelfed.max_album_length, use config_cache ([fecbe189](https://github.com/pixelfed/pixelfed/commit/fecbe189))
+- Update media_types, use config_cache ([d670de17](https://github.com/pixelfed/pixelfed/commit/d670de17))
+- Update landing settings, use config_cache ([40478f25](https://github.com/pixelfed/pixelfed/commit/40478f25))
+- Update activitypub setting, use config_cache ([5071aaf4](https://github.com/pixelfed/pixelfed/commit/5071aaf4))
+- Update oauth setting, use config_cache ([ce228f7f](https://github.com/pixelfed/pixelfed/commit/ce228f7f))
+- Update stories config, use config_cache ([d1adb109](https://github.com/pixelfed/pixelfed/commit/d1adb109))
+- Update ig import, use config_cache ([da0e0ffa](https://github.com/pixelfed/pixelfed/commit/da0e0ffa))
+- Update autospam config, use config_cache ([a76cb5f4](https://github.com/pixelfed/pixelfed/commit/a76cb5f4))
+- Update app.name config, use config_cache ([911446c0](https://github.com/pixelfed/pixelfed/commit/911446c0))
+- Update UserObserver, fix type casting ([949e9979](https://github.com/pixelfed/pixelfed/commit/949e9979))
+- Update user_filters, use config_cache ([6ce513f8](https://github.com/pixelfed/pixelfed/commit/6ce513f8))
+- Update filesystems config, add to config_cache ([087b2791](https://github.com/pixelfed/pixelfed/commit/087b2791))
+- Update web-admin routes, add setting api routes ([828a456f](https://github.com/pixelfed/pixelfed/commit/828a456f))
+- Update hashtag component ([cee979ed](https://github.com/pixelfed/pixelfed/commit/cee979ed))
+- Update AdminReadMore component, add .prevent to click action ([704e7b12](https://github.com/pixelfed/pixelfed/commit/704e7b12))
+- Update admin dashboard, add admin settings partials ([eb487123](https://github.com/pixelfed/pixelfed/commit/eb487123))
+- Update admin settings, refactor to vue component ([674e560f](https://github.com/pixelfed/pixelfed/commit/674e560f))
+- Update ConfigCacheService, encrypt keys at rest ([3628b462](https://github.com/pixelfed/pixelfed/commit/3628b462))
+- Update RemoteFollowImportRecent, use MediaPathService ([5162c070](https://github.com/pixelfed/pixelfed/commit/5162c070))
+- Update AdminSettingsController, add user filter max limit settings ([ac1f0748](https://github.com/pixelfed/pixelfed/commit/ac1f0748))
+- Update AdminSettingsController, add AdminSettingsService ([dcc5f416](https://github.com/pixelfed/pixelfed/commit/dcc5f416))
+- Update AdminSettings component, fix user settings ([aba1e13d](https://github.com/pixelfed/pixelfed/commit/aba1e13d))
+- Update AdminInstances component ([ec2fdd61](https://github.com/pixelfed/pixelfed/commit/ec2fdd61))
+- Update AdminSettings, add max_account_size support ([2dcbc1d5](https://github.com/pixelfed/pixelfed/commit/2dcbc1d5))
+- Update AdminSettings, use better validation for user integer settings ([d946afcc](https://github.com/pixelfed/pixelfed/commit/d946afcc))
+- Update spa sass, fix timestamp dark mode bug ([4147f7c5](https://github.com/pixelfed/pixelfed/commit/4147f7c5))
+- Update relationships view, fix unfollow hashtag bug. Fixes #5008 ([8c693640](https://github.com/pixelfed/pixelfed/commit/8c693640))
+- Update PrivacySettings controller, refresh RelationshipService when unmute/unblocking ([b7322b68](https://github.com/pixelfed/pixelfed/commit/b7322b68))
+- Update ApiV1Controller, improve refresh relations logic when (un)muting or (un)blocking ([b8e96a5f](https://github.com/pixelfed/pixelfed/commit/b8e96a5f))
+- Update context menu, add mute/block/unfollow actions and update relationship store accordingly ([81d1e0fd](https://github.com/pixelfed/pixelfed/commit/81d1e0fd))
 -  ([](https://github.com/pixelfed/pixelfed/commit/))
 
 ## [v0.11.13 (2024-03-05)](https://github.com/pixelfed/pixelfed/compare/v0.11.12...v0.11.13)

+ 3 - 2
app/Http/Controllers/Api/ApiV1Controller.php

@@ -1200,8 +1200,8 @@ class ApiV1Controller extends Controller
         if ($filter) {
             $filter->delete();
             UserFilterService::unblock($pid, $profile->id);
-            RelationshipService::refresh($pid, $id);
         }
+        RelationshipService::refresh($pid, $id);
 
         $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer());
         $res = $this->fractal->createData($resource)->toArray();
@@ -2207,9 +2207,10 @@ class ApiV1Controller extends Controller
         if ($filter) {
             $filter->delete();
             UserFilterService::unmute($pid, $profile->id);
-            RelationshipService::refresh($pid, $id);
         }
 
+        RelationshipService::refresh($pid, $id);
+
         $resource = new Fractal\Resource\Item($profile, new RelationshipTransformer());
         $res = $this->fractal->createData($resource)->toArray();
 

+ 40 - 39
app/Http/Controllers/Settings/PrivacySettings.php

@@ -2,23 +2,17 @@
 
 namespace App\Http\Controllers\Settings;
 
-use App\AccountLog;
-use App\EmailVerification;
-use App\Instance;
 use App\Follower;
-use App\Media;
 use App\Profile;
-use App\User;
+use App\Services\RelationshipService;
 use App\UserFilter;
-use App\Util\Lexer\PrettyNumber;
-use App\Util\ActivityPub\Helpers;
-use Auth, Cache, DB;
+use Auth;
+use Cache;
+use DB;
 use Illuminate\Http\Request;
-use App\Models\UserDomainBlock;
 
 trait PrivacySettings
 {
-
     public function privacy()
     {
         $user = Auth::user();
@@ -35,13 +29,13 @@ trait PrivacySettings
         $settings = $request->user()->settings;
         $profile = $request->user()->profile;
         $fields = [
-          'is_private',
-          'crawlable',
-          'public_dm',
-          'show_profile_follower_count',
-          'show_profile_following_count',
-          'indexable',
-          'show_atom',
+            'is_private',
+            'crawlable',
+            'public_dm',
+            'show_profile_follower_count',
+            'show_profile_following_count',
+            'indexable',
+            'show_atom',
         ];
 
         $profile->indexable = $request->input('indexable') == 'on';
@@ -67,7 +61,7 @@ trait PrivacySettings
                 } else {
                     $settings->{$field} = true;
                 }
-             } elseif ($field == 'public_dm') {
+            } elseif ($field == 'public_dm') {
                 if ($form == 'on') {
                     $settings->{$field} = true;
                 } else {
@@ -85,33 +79,35 @@ trait PrivacySettings
             $settings->save();
         }
         $pid = $profile->id;
-        Cache::forget('profile:settings:' . $pid);
-        Cache::forget('user:account:id:' . $profile->user_id);
-        Cache::forget('profile:follower_count:' . $pid);
-        Cache::forget('profile:following_count:' . $pid);
-        Cache::forget('profile:atom:enabled:' . $pid);
-        Cache::forget('profile:embed:' . $pid);
-        Cache::forget('pf:acct:settings:hidden-followers:' . $pid);
-        Cache::forget('pf:acct:settings:hidden-following:' . $pid);
-        Cache::forget('pf:acct-trans:hideFollowing:' . $pid);
-        Cache::forget('pf:acct-trans:hideFollowers:' . $pid);
-        Cache::forget('pfc:cached-user:wt:' . strtolower($profile->username));
-        Cache::forget('pfc:cached-user:wot:' . strtolower($profile->username));
+        Cache::forget('profile:settings:'.$pid);
+        Cache::forget('user:account:id:'.$profile->user_id);
+        Cache::forget('profile:follower_count:'.$pid);
+        Cache::forget('profile:following_count:'.$pid);
+        Cache::forget('profile:atom:enabled:'.$pid);
+        Cache::forget('profile:embed:'.$pid);
+        Cache::forget('pf:acct:settings:hidden-followers:'.$pid);
+        Cache::forget('pf:acct:settings:hidden-following:'.$pid);
+        Cache::forget('pf:acct-trans:hideFollowing:'.$pid);
+        Cache::forget('pf:acct-trans:hideFollowers:'.$pid);
+        Cache::forget('pfc:cached-user:wt:'.strtolower($profile->username));
+        Cache::forget('pfc:cached-user:wot:'.strtolower($profile->username));
+
         return redirect(route('settings.privacy'))->with('status', 'Settings successfully updated!');
     }
 
     public function mutedUsers()
-    {   
+    {
         $pid = Auth::user()->profile->id;
         $ids = (new UserFilter())->mutedUserIds($pid);
         $users = Profile::whereIn('id', $ids)->simplePaginate(15);
+
         return view('settings.privacy.muted', compact('users'));
     }
 
     public function mutedUsersUpdate(Request $request)
-    {   
+    {
         $this->validate($request, [
-            'profile_id' => 'required|integer|min:1'
+            'profile_id' => 'required|integer|min:1',
         ]);
         $fid = $request->input('profile_id');
         $pid = Auth::user()->profile->id;
@@ -123,6 +119,8 @@ trait PrivacySettings
                 ->firstOrFail();
             $filter->delete();
         });
+        RelationshipService::refresh($pid, $fid);
+
         return redirect()->back();
     }
 
@@ -131,14 +129,14 @@ trait PrivacySettings
         $pid = Auth::user()->profile->id;
         $ids = (new UserFilter())->blockedUserIds($pid);
         $users = Profile::whereIn('id', $ids)->simplePaginate(15);
+
         return view('settings.privacy.blocked', compact('users'));
     }
 
-
     public function blockedUsersUpdate(Request $request)
-    {   
+    {
         $this->validate($request, [
-            'profile_id' => 'required|integer|min:1'
+            'profile_id' => 'required|integer|min:1',
         ]);
         $fid = $request->input('profile_id');
         $pid = Auth::user()->profile->id;
@@ -150,6 +148,8 @@ trait PrivacySettings
                 ->firstOrFail();
             $filter->delete();
         });
+        RelationshipService::refresh($pid, $fid);
+
         return redirect()->back();
     }
 
@@ -194,7 +194,7 @@ trait PrivacySettings
         $profile = Auth::user()->profile;
         $settings = Auth::user()->settings;
 
-        if($mode !== 'keep-all') {
+        if ($mode !== 'keep-all') {
             switch ($mode) {
                 case 'mutual-only':
                     $following = $profile->following()->pluck('profiles.id');
@@ -209,9 +209,9 @@ trait PrivacySettings
                 case 'remove-all':
                     Follower::whereFollowingId($profile->id)->delete();
                     break;
-                
+
                 default:
-                    # code...
+                    // code...
                     break;
             }
         }
@@ -221,6 +221,7 @@ trait PrivacySettings
         $settings->save();
         $profile->save();
         Cache::forget('profiles:private');
+
         return [200];
     }
 }

Plik diff jest za duży
+ 162 - 221
composer.lock


Plik diff jest za duży
+ 255 - 296
package-lock.json


BIN
public/css/spa.css


BIN
public/js/account-import.js


BIN
public/js/admin.js


BIN
public/js/app.js


BIN
public/js/changelog.bundle.bf44edbbfa14bd53.js


BIN
public/js/changelog.bundle.d5810c2672b6abc7.js


BIN
public/js/compose.chunk.47ba00abaa827b26.js


BIN
public/js/compose.chunk.a0cfdf07f5062445.js


BIN
public/js/daci.chunk.34dc7bad3a0792cc.js


BIN
public/js/daci.chunk.a498fff65c83f174.js


BIN
public/js/discover.chunk.1404d3172761023b.js


BIN
public/js/discover.chunk.c2229e1d15bd3ada.js


BIN
public/js/discover~findfriends.chunk.29c7f06a6a4c6f61.js


BIN
public/js/discover~findfriends.chunk.b1858bea66d9723b.js


BIN
public/js/discover~hashtag.bundle.1b11b46e0b28aa3f.js


BIN
public/js/discover~hashtag.bundle.a0f00fc7df1f313c.js


BIN
public/js/discover~memories.chunk.321431bd290466d4.js


BIN
public/js/discover~memories.chunk.37e0c325f900e163.js


BIN
public/js/discover~myhashtags.chunk.4cc859102b24780c.js


BIN
public/js/discover~myhashtags.chunk.8886fc0d4736d819.js


BIN
public/js/discover~serverfeed.chunk.262bf7e3bce843c3.js


BIN
public/js/discover~serverfeed.chunk.b4c4ca11f3498bf1.js


BIN
public/js/discover~settings.chunk.07417fd0cd9c5833.js


BIN
public/js/discover~settings.chunk.65d6f3cbe5323ed4.js


BIN
public/js/dms.chunk.2b55effc0e8ba89f.js


BIN
public/js/dms.chunk.a42edfd973f6c593.js


BIN
public/js/dms~message.chunk.6cd795c99fc1a568.js


BIN
public/js/dms~message.chunk.976f7edaa6f71137.js


+ 0 - 0
public/js/error404.bundle.b397483e3991ab20.js → public/js/error404.bundle.54601f9cdd0f7719.js


BIN
public/js/home.chunk.264eeb47bfac56c1.js


BIN
public/js/home.chunk.ccbe0267817f9a26.js


+ 0 - 0
public/js/home.chunk.264eeb47bfac56c1.js.LICENSE.txt → public/js/home.chunk.ccbe0267817f9a26.js.LICENSE.txt


BIN
public/js/i18n.bundle.28bba3e12cdadf51.js


BIN
public/js/i18n.bundle.93a02e275ac1a708.js


BIN
public/js/landing.js


BIN
public/js/manifest.js


BIN
public/js/notifications.chunk.0c5151643e4534aa.js


BIN
public/js/notifications.chunk.1086603ea08d1017.js


BIN
public/js/portfolio.js


BIN
public/js/post.chunk.41ea9082b932e599.js


+ 0 - 0
public/js/post.chunk.9184101a2b809af1.js.LICENSE.txt → public/js/post.chunk.41ea9082b932e599.js.LICENSE.txt


BIN
public/js/post.chunk.9184101a2b809af1.js


BIN
public/js/profile.chunk.a2234f891ba86efd.js


BIN
public/js/profile.chunk.e86bfb0eb7723ddc.js


BIN
public/js/profile~followers.bundle.50a39058d98e16eb.js


BIN
public/js/profile~followers.bundle.5d796e79f32d066c.js


BIN
public/js/profile~following.bundle.7ca7cfa5aaae75e2.js


BIN
public/js/profile~following.bundle.9294aa1b560387c7.js


BIN
public/js/spa.js


BIN
public/js/vendor.js


BIN
public/mix-manifest.json


+ 1008 - 790
resources/assets/components/partials/post/ContextMenu.vue

@@ -1,803 +1,1021 @@
 <template>
-	<div class="modal-stack">
-		<b-modal ref="ctxModal"
-			id="ctx-modal"
-			hide-header
-			hide-footer
-			centered
-			rounded
-			size="sm"
-			body-class="list-group-flush p-0 rounded">
-
-			<div class="list-group text-center">
-				<div
-					v-if="status.visibility !== 'archived'"
-					class="list-group-item rounded cursor-pointer font-weight-bold"
-					@click="ctxMenuGoToPost()">
-					{{ $t('menu.viewPost') }}
-				</div>
-
-				<div
-					v-if="status.visibility !== 'archived'"
-					class="list-group-item rounded cursor-pointer font-weight-bold"
-					@click="ctxMenuGoToProfile()">
-					{{ $t('menu.viewProfile') }}
-				</div>
-
-				<div
-					v-if="status.visibility !== 'archived'"
-					class="list-group-item rounded cursor-pointer font-weight-bold"
-					@click="ctxMenuShare()">
-					{{ $t('common.share') }}
-				</div>
-
-				<div
-					v-if="status && profile && profile.is_admin == true && status.visibility !== 'archived'"
-					class="list-group-item rounded cursor-pointer font-weight-bold"
-					@click="ctxModMenuShow()">
-					{{ $t('menu.moderationTools') }}
-				</div>
-
-				<div
-					v-if="status && status.account.id != profile.id"
-					class="list-group-item rounded cursor-pointer text-danger font-weight-bold"
-					@click="ctxMenuReportPost()">
-					{{ $t('menu.report') }}
-				</div>
-
-				<div
-					v-if="status && profile.id == status.account.id && status.visibility !== 'archived'"
-					class="list-group-item rounded cursor-pointer text-danger font-weight-bold"
-					@click="archivePost(status)">
-					{{ $t('menu.archive') }}
-				</div>
-
-				<div
-					v-if="status && profile.id == status.account.id && status.visibility == 'archived'"
-					class="list-group-item rounded cursor-pointer text-danger font-weight-bold"
-					@click="unarchivePost(status)">
-					{{ $t('menu.unarchive') }}
-				</div>
-
-				<div
-					v-if="config.ab.pue && status && profile.id == status.account.id && status.visibility !== 'archived'"
-					class="list-group-item rounded cursor-pointer text-danger font-weight-bold"
-					@click="editPost(status)">
-					Edit
-				</div>
-
-				<div
-					v-if="status && (profile.is_admin || profile.id == status.account.id) && status.visibility !== 'archived'"
-					class="list-group-item rounded cursor-pointer text-danger font-weight-bold"
-					@click="deletePost(status)">
+    <div class="modal-stack">
+        <b-modal ref="ctxModal"
+            id="ctx-modal"
+            hide-header
+            hide-footer
+            centered
+            rounded
+            size="sm"
+            body-class="list-group-flush p-0 rounded">
+
+            <div class="list-group text-center">
+                <div v-if="status.visibility !== 'archived'" class="list-group-item d-flex p-0 m-0">
+                    <div class="border-right p-2 w-50">
+                        <a
+                            v-if="status"
+                            class="menu-option"
+                            :href="status.url"
+                            @click.prevent="ctxMenuGoToPost()">
+                            <div class="action-icon-link">
+                                <div class="icon"><i class="fal fa-images fa-lg"></i></div>
+                                <p class="mb-0">{{ $t('menu.viewPost') }}</p>
+                            </div>
+                        </a>
+                    </div>
+
+                    <div class="p-2 flex-grow-1">
+                        <a
+                            v-if="status"
+                            class="menu-option"
+                            :href="status.account.url"
+                            @click.prevent="ctxMenuGoToProfile()">
+                            <div class="action-icon-link">
+                                <div class="icon"><i class="fal fa-user fa-lg"></i></div>
+                                <p class="mb-0">{{ $t('menu.viewProfile') }}</p>
+                            </div>
+                        </a>
+                    </div>
+                </div>
+
+                <template v-if="ctxMenuRelationship">
+                    <a
+                        v-if="ctxMenuRelationship.following"
+                        class="list-group-item menu-option text-danger"
+                        href="#"
+                        @click.prevent="handleUnfollow">
+                        {{ $t('profile.unfollow') }}
+                    </a>
+
+                    <div v-else class="d-flex">
+                        <div class="p-3 border-right w-50 text-center">
+                            <a
+                                class="small menu-option text-muted"
+                                href="#"
+                                @click.prevent="handleMute">
+                                <div class="action-icon-link-inline">
+                                    <div class="icon"><i class="far" :class="[ ctxMenuRelationship.muting ? 'fa-eye' : 'fa-eye-slash' ]"></i></div>
+                                    <p class="text-muted mb-0">{{ ctxMenuRelationship.muting ? 'Unmute' : 'Mute' }}</p>
+                                </div>
+                            </a>
+                        </div>
+                        <div class="p-3 w-50">
+                            <a
+                                class="small menu-option text-danger"
+                                href="#"
+                                @click.prevent="handleBlock">
+                                <div class="action-icon-link-inline">
+                                    <div class="icon"><i class="far fa-shield-alt"></i></div>
+                                    <p class="text-danger mb-0">Block</p>
+                                </div>
+                            </a>
+                        </div>
+                    </div>
+                </template>
+
+                <a
+                    v-if="status.visibility !== 'archived'"
+                    class="list-group-item menu-option"
+                    href="#"
+                    @click.prevent="ctxMenuShare()">
+                    {{ $t('common.share') }}
+                </a>
+
+                <a
+                    v-if="status && profile && profile.is_admin == true && status.visibility !== 'archived'"
+                    class="list-group-item menu-option"
+                    href="#"
+                    @click.prevent="ctxModMenuShow()">
+                    {{ $t('menu.moderationTools') }}
+                </a>
+
+                <a
+                    v-if="status && status.account.id != profile.id"
+                    class="list-group-item menu-option text-danger"
+                    href="#"
+                    @click.prevent="ctxMenuReportPost()">
+                    {{ $t('menu.report') }}
+                </a>
+
+                <a
+                    v-if="status && profile.id == status.account.id && status.visibility !== 'archived'"
+                    class="list-group-item menu-option text-danger"
+                    href="#"
+                    @click.prevent="archivePost(status)">
+                    {{ $t('menu.archive') }}
+                </a>
+
+                <a
+                    v-if="status && profile.id == status.account.id && status.visibility == 'archived'"
+                    class="list-group-item menu-option text-danger"
+                    href="#"
+                    @click.prevent="unarchivePost(status)">
+                    {{ $t('menu.unarchive') }}
+                </a>
+
+                <a
+                    v-if="config.ab.pue && status && profile.id == status.account.id && status.visibility !== 'archived'"
+                    class="list-group-item menu-option text-danger"
+                    href="#"
+                    @click.prevent="editPost(status)">
+                    Edit
+                </a>
+
+                <a
+                    v-if="status && (profile.is_admin || profile.id == status.account.id) && status.visibility !== 'archived'"
+                    class="list-group-item menu-option text-danger"
+                    href="#"
+                    @click.prevent="deletePost(status)">
                     <div v-if="isDeleting" class="spinner-border spinner-border-sm" role="status">
                         <span class="sr-only">Loading...</span>
                     </div>
                     <div v-else>
-					   {{ $t('common.delete') }}
+                       {{ $t('common.delete') }}
+                    </div>
+                </a>
+
+                <a
+                    class="list-group-item menu-option text-lighter"
+                    href="#"
+                    @click.prevent="closeCtxMenu()">
+                    {{ $t('common.cancel') }}
+                </a>
+            </div>
+        </b-modal>
+
+        <b-modal ref="ctxModModal"
+            id="ctx-mod-modal"
+            hide-header
+            hide-footer
+            centered
+            rounded
+            size="sm"
+            body-class="list-group-flush p-0 rounded">
+
+            <div class="list-group text-center">
+                <p class="py-2 px-3 mb-0">
+                    <div
+                        class="text-center menu-option text-danger">
+                        {{ $t('menu.moderationTools') }}
                     </div>
-				</div>
-
-				<div
-					class="list-group-item rounded cursor-pointer text-lighter font-weight-bold"
-					@click="closeCtxMenu()">
-					{{ $t('common.cancel') }}
-				</div>
-			</div>
-		</b-modal>
-
-		<b-modal ref="ctxModModal"
-			id="ctx-mod-modal"
-			hide-header
-			hide-footer
-			centered
-			rounded
-			size="sm"
-			body-class="list-group-flush p-0 rounded">
-
-			<div class="list-group text-center">
-				<p class="py-2 px-3 mb-0">
-					<div
-						class="text-center font-weight-bold text-danger">
-						{{ $t('menu.moderationTools') }}
-					</div>
-
-					<div class="small text-center text-muted">
-						{{ $t('menu.selectOneOption') }}
-					</div>
-				</p>
-
-				<div
-					class="list-group-item rounded cursor-pointer"
-					@click="moderatePost(status, 'unlist')">
-					{{ $t('menu.unlistFromTimelines') }}
-				</div>
-
-				<div
-					v-if="status.sensitive"
-					class="list-group-item rounded cursor-pointer"
-					@click="moderatePost(status, 'remcw')">
-					{{ $t('menu.removeCW') }}
-				</div>
-
-				<div
-					v-else
-					class="list-group-item rounded cursor-pointer"
-					@click="moderatePost(status, 'addcw')">
-					{{ $t('menu.addCW') }}
-				</div>
-
-				<div
-					class="list-group-item rounded cursor-pointer"
-					@click="moderatePost(status, 'spammer')">
-					{{ $t('menu.markAsSpammer') }}<br />
-					<span class="small">{{ $t('menu.markAsSpammerText') }}</span>
-				</div>
-
-				<div
-					class="list-group-item rounded cursor-pointer text-lighter"
-					@click="ctxModMenuClose()">
-					{{ $t('common.cancel') }}
-				</div>
-			</div>
-		</b-modal>
-
-		<b-modal ref="ctxModOtherModal"
-			id="ctx-mod-other-modal"
-			hide-header
-			hide-footer
-			centered
-			rounded
-			size="sm"
-			body-class="list-group-flush p-0 rounded">
-			<div class="list-group text-center">
-				<p class="py-2 px-3 mb-0">
-					<div class="text-center font-weight-bold text-danger">{{ $t('menu.moderationTools') }}</div>
-					<div class="small text-center text-muted">{{ $t('menu.selectOneOption') }}</div>
-				</p>
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="confirmModal()">Unlist Posts</div>
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="confirmModal()">Moderation Log</div>
-				<div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxModOtherMenuClose()">{{ $t('common.cancel') }}</div>
-			</div>
-		</b-modal>
-
-		<b-modal ref="ctxShareModal"
-			id="ctx-share-modal"
-			title="Share"
-			hide-footer
-			hide-header
-			centered
-			rounded
-			size="sm"
-			body-class="list-group-flush p-0 rounded text-center">
-			<div class="list-group-item rounded cursor-pointer" @click="shareStatus(status, $event)">{{status.reblogged ? 'Unshare' : 'Share'}} {{ $t('menu.toFollowers') }}</div>
-			<div class="list-group-item rounded cursor-pointer" @click="ctxMenuCopyLink()">{{ $t('common.copyLink') }}</div>
-			<div v-if="status && status.local == true && !status.in_reply_to_id" class="list-group-item rounded cursor-pointer" @click="ctxMenuEmbed()">{{ $t('menu.embed') }}</div>
-			<div class="list-group-item rounded cursor-pointer text-lighter" @click="closeCtxShareMenu()">{{ $t('common.cancel') }}</div>
-		</b-modal>
-
-		<b-modal ref="ctxEmbedModal"
-			id="ctx-embed-modal"
-			hide-header
-			hide-footer
-			centered
-			rounded
-			size="md"
-			body-class="p-2 rounded">
-			<div>
-				<div class="form-group">
-					<textarea class="form-control disabled text-monospace" rows="8" style="overflow-y:hidden;border: 1px solid #efefef; font-size: 12px; line-height: 18px; margin: 0 0 7px;resize:none;" v-model="ctxEmbedPayload" disabled=""></textarea>
-				</div>
-				<div class="form-group pl-2 d-flex justify-content-center">
-					<div class="form-check mr-3">
-						<input class="form-check-input" type="checkbox" v-model="ctxEmbedShowCaption" :disabled="ctxEmbedCompactMode == true">
-						<label class="form-check-label font-weight-light">
-							{{ $t('menu.showCaption') }}
-						</label>
-					</div>
-					<div class="form-check mr-3">
-						<input class="form-check-input" type="checkbox" v-model="ctxEmbedShowLikes" :disabled="ctxEmbedCompactMode == true">
-						<label class="form-check-label font-weight-light">
-							{{ $t('menu.showLikes') }}
-						</label>
-					</div>
-					<div class="form-check">
-						<input class="form-check-input" type="checkbox" v-model="ctxEmbedCompactMode">
-						<label class="form-check-label font-weight-light">
-							{{ $t('menu.compactMode') }}
-						</label>
-					</div>
-				</div>
-				<hr>
-				<button :class="copiedEmbed ? 'btn btn-primary btn-block btn-sm py-1 font-weight-bold disabed': 'btn btn-primary btn-block btn-sm py-1 font-weight-bold'" @click="ctxCopyEmbed" :disabled="copiedEmbed">{{copiedEmbed ? 'Embed Code Copied!' : 'Copy Embed Code'}}</button>
-				<p class="mb-0 px-2 small text-muted">{{ $t('menu.embedConfirmText') }} <a href="/site/terms">{{ $t('site.terms') }}</a></p>
-			</div>
-		</b-modal>
-
-		<b-modal ref="ctxReport"
-			id="ctx-report"
-			hide-header
-			hide-footer
-			centered
-			rounded
-			size="sm"
-			body-class="list-group-flush p-0 rounded">
-			<p class="py-2 px-3 mb-0">
-				<div class="text-center font-weight-bold text-danger">{{ $t('menu.report') }}</div>
-				<div class="small text-center text-muted">{{ $t('menu.selectOneOption') }}</div>
-			</p>
-			<div class="list-group text-center">
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('spam')">{{ $t('menu.spam') }}</div>
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('sensitive')">{{ $t('menu.sensitive') }}</div>
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('abusive')">{{ $t('menu.abusive') }}</div>
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="openCtxReportOtherMenu()">{{ $t('common.other') }}</div>
-				<!-- <div class="list-group-item rounded cursor-pointer" @click="ctxReportMenuGoBack()">Go Back</div> -->
-				<div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxReportMenuGoBack()">{{ $t('common.cancel') }}</div>
-			</div>
-		</b-modal>
-
-		<b-modal ref="ctxReportOther"
-			id="ctx-report-other"
-			hide-header
-			hide-footer
-			centered
-			rounded
-			size="sm"
-			body-class="list-group-flush p-0 rounded">
-			<p class="py-2 px-3 mb-0">
-				<div class="text-center font-weight-bold text-danger">{{ $t('menu.report') }}</div>
-				<div class="small text-center text-muted">{{ $t('menu.selectOneOption') }}</div>
-			</p>
-			<div class="list-group text-center">
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('underage')">{{ $t('menu.underageAccount') }}</div>
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('copyright')">{{ $t('menu.copyrightInfringement') }}</div>
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('impersonation')">{{ $t('menu.impersonation') }}</div>
-				<div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('scam')">{{ $t('menu.scamOrFraud') }}</div>
-				<div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxReportOtherMenuGoBack()">{{ $t('common.cancel') }}</div>
-			</div>
-		</b-modal>
-
-		<b-modal ref="ctxConfirm"
-			id="ctx-confirm"
-			hide-header
-			hide-footer
-			centered
-			rounded
-			size="sm"
-			body-class="list-group-flush p-0 rounded">
-			<div class="d-flex align-items-center justify-content-center py-3">
-				<div>{{ this.confirmModalTitle }}</div>
-			</div>
-			<div class="d-flex border-top btn-group btn-group-block rounded-0" role="group">
-				<button type="button" class="btn btn-outline-lighter border-left-0 border-top-0 border-bottom-0 border-right py-2" style="color: rgb(0,122,255) !important;" @click.prevent="confirmModalCancel()">{{ $t('common.cancel') }}</button>
-				<button type="button" class="btn btn-outline-lighter border-0" style="color: rgb(0,122,255) !important;" @click.prevent="confirmModalConfirm()">Confirm</button>
-			</div>
-		</b-modal>
-
-	</div>
+
+                    <div class="small text-center text-muted">
+                        {{ $t('menu.selectOneOption') }}
+                    </div>
+                </p>
+
+                <a
+                    class="list-group-item menu-option"
+                    href="#"
+                    @click.prevent="moderatePost(status, 'unlist')">
+                    {{ $t('menu.unlistFromTimelines') }}
+                </a>
+
+                <a
+                    v-if="status.sensitive"
+                    class="list-group-item menu-option"
+                    href="#"
+                    @click.prevent="moderatePost(status, 'remcw')">
+                    {{ $t('menu.removeCW') }}
+                </a>
+
+                <a
+                    v-else
+                    class="list-group-item menu-option"
+                    href="#"
+                    @click.prevent="moderatePost(status, 'addcw')">
+                    {{ $t('menu.addCW') }}
+                </a>
+
+                <a
+                    class="list-group-item menu-option"
+                    href="#"
+                    @click.prevent="moderatePost(status, 'spammer')">
+                    {{ $t('menu.markAsSpammer') }}<br />
+                    <span class="small">{{ $t('menu.markAsSpammerText') }}</span>
+                </a>
+
+                <a
+                    class="list-group-item menu-option text-lighter"
+                    href="#"
+                    @click.prevent="ctxModMenuClose()">
+                    {{ $t('common.cancel') }}
+                </a>
+            </div>
+        </b-modal>
+
+        <b-modal ref="ctxModOtherModal"
+            id="ctx-mod-other-modal"
+            hide-header
+            hide-footer
+            centered
+            rounded
+            size="sm"
+            body-class="list-group-flush p-0 rounded">
+            <div class="list-group text-center">
+                <p class="py-2 px-3 mb-0">
+                    <div class="text-center font-weight-bold text-danger">{{ $t('menu.moderationTools') }}</div>
+                    <div class="small text-center text-muted">{{ $t('menu.selectOneOption') }}</div>
+                </p>
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="confirmModal()">Unlist Posts</div>
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="confirmModal()">Moderation Log</div>
+                <div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxModOtherMenuClose()">{{ $t('common.cancel') }}</div>
+            </div>
+        </b-modal>
+
+        <b-modal ref="ctxShareModal"
+            id="ctx-share-modal"
+            title="Share"
+            hide-footer
+            hide-header
+            centered
+            rounded
+            size="sm"
+            body-class="list-group-flush p-0 rounded text-center">
+            <a
+                class="list-group-item menu-option"
+                href="#"
+                @click.prevent="ctxMenuCopyLink()">
+                {{ $t('common.copyLink') }}
+            </a>
+
+            <a
+                v-if="status && status.local == true && !status.in_reply_to_id"
+                class="list-group-item menu-option"
+                @click.prevent="ctxMenuEmbed()">
+                {{ $t('menu.embed') }}
+            </a>
+
+            <a
+                class="list-group-item menu-option text-lighter"
+                href="#"
+                @click.prevent="closeCtxShareMenu()">
+                {{ $t('common.cancel') }}
+            </a>
+        </b-modal>
+
+        <b-modal ref="ctxEmbedModal"
+            id="ctx-embed-modal"
+            hide-header
+            hide-footer
+            centered
+            rounded
+            size="md"
+            body-class="p-2 rounded">
+            <div>
+                <div class="form-group">
+                    <textarea class="form-control disabled text-monospace" rows="8" style="overflow-y:hidden;border: 1px solid #efefef; font-size: 12px; line-height: 18px; margin: 0 0 7px;resize:none;" v-model="ctxEmbedPayload" disabled=""></textarea>
+                </div>
+                <div class="form-group pl-2 d-flex justify-content-center">
+                    <div class="form-check mr-3">
+                        <input class="form-check-input" type="checkbox" v-model="ctxEmbedShowCaption" :disabled="ctxEmbedCompactMode == true">
+                        <label class="form-check-label font-weight-light">
+                            {{ $t('menu.showCaption') }}
+                        </label>
+                    </div>
+                    <div class="form-check mr-3">
+                        <input class="form-check-input" type="checkbox" v-model="ctxEmbedShowLikes" :disabled="ctxEmbedCompactMode == true">
+                        <label class="form-check-label font-weight-light">
+                            {{ $t('menu.showLikes') }}
+                        </label>
+                    </div>
+                    <div class="form-check">
+                        <input class="form-check-input" type="checkbox" v-model="ctxEmbedCompactMode">
+                        <label class="form-check-label font-weight-light">
+                            {{ $t('menu.compactMode') }}
+                        </label>
+                    </div>
+                </div>
+                <hr>
+                <button :class="copiedEmbed ? 'btn btn-primary btn-block btn-sm py-1 font-weight-bold disabed': 'btn btn-primary btn-block btn-sm py-1 font-weight-bold'" @click="ctxCopyEmbed" :disabled="copiedEmbed">{{copiedEmbed ? 'Embed Code Copied!' : 'Copy Embed Code'}}</button>
+                <p class="mb-0 px-2 small text-muted">{{ $t('menu.embedConfirmText') }} <a href="/site/terms">{{ $t('site.terms') }}</a></p>
+            </div>
+        </b-modal>
+
+        <b-modal ref="ctxReport"
+            id="ctx-report"
+            hide-header
+            hide-footer
+            centered
+            rounded
+            size="sm"
+            body-class="list-group-flush p-0 rounded">
+            <p class="py-2 px-3 mb-0">
+                <div class="text-center font-weight-bold text-danger">{{ $t('menu.report') }}</div>
+                <div class="small text-center text-muted">{{ $t('menu.selectOneOption') }}</div>
+            </p>
+            <div class="list-group text-center">
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('spam')">{{ $t('menu.spam') }}</div>
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('sensitive')">{{ $t('menu.sensitive') }}</div>
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('abusive')">{{ $t('menu.abusive') }}</div>
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="openCtxReportOtherMenu()">{{ $t('common.other') }}</div>
+                <!-- <div class="list-group-item rounded cursor-pointer" @click="ctxReportMenuGoBack()">Go Back</div> -->
+                <div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxReportMenuGoBack()">{{ $t('common.cancel') }}</div>
+            </div>
+        </b-modal>
+
+        <b-modal ref="ctxReportOther"
+            id="ctx-report-other"
+            hide-header
+            hide-footer
+            centered
+            rounded
+            size="sm"
+            body-class="list-group-flush p-0 rounded">
+            <p class="py-2 px-3 mb-0">
+                <div class="text-center font-weight-bold text-danger">{{ $t('menu.report') }}</div>
+                <div class="small text-center text-muted">{{ $t('menu.selectOneOption') }}</div>
+            </p>
+            <div class="list-group text-center">
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('underage')">{{ $t('menu.underageAccount') }}</div>
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('copyright')">{{ $t('menu.copyrightInfringement') }}</div>
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('impersonation')">{{ $t('menu.impersonation') }}</div>
+                <div class="list-group-item rounded cursor-pointer font-weight-bold" @click="sendReport('scam')">{{ $t('menu.scamOrFraud') }}</div>
+                <div class="list-group-item rounded cursor-pointer text-lighter" @click="ctxReportOtherMenuGoBack()">{{ $t('common.cancel') }}</div>
+            </div>
+        </b-modal>
+
+        <b-modal ref="ctxConfirm"
+            id="ctx-confirm"
+            hide-header
+            hide-footer
+            centered
+            rounded
+            size="sm"
+            body-class="list-group-flush p-0 rounded">
+            <div class="d-flex align-items-center justify-content-center py-3">
+                <div>{{ this.confirmModalTitle }}</div>
+            </div>
+            <div class="d-flex border-top btn-group btn-group-block rounded-0" role="group">
+                <button type="button" class="btn btn-outline-lighter border-left-0 border-top-0 border-bottom-0 border-right py-2" style="color: rgb(0,122,255) !important;" @click.prevent="confirmModalCancel()">{{ $t('common.cancel') }}</button>
+                <button type="button" class="btn btn-outline-lighter border-0" style="color: rgb(0,122,255) !important;" @click.prevent="confirmModalConfirm()">Confirm</button>
+            </div>
+        </b-modal>
+
+    </div>
 </template>
 
 <script type="text/javascript">
-	export default {
-		props: [
-			'status',
-			'profile'
-		],
-
-		data() {
-			return {
-				config: window.App.config,
-				ctxMenuStatus: false,
-				ctxMenuRelationship: false,
-				ctxEmbedPayload: false,
-				copiedEmbed: false,
-				replySending: false,
-				ctxEmbedShowCaption: true,
-				ctxEmbedShowLikes: false,
-				ctxEmbedCompactMode: false,
-				confirmModalTitle: 'Are you sure?',
-				confirmModalIdentifer: null,
-				confirmModalType: false,
+    export default {
+        props: [
+            'status',
+            'profile'
+        ],
+
+        data() {
+            return {
+                config: window.App.config,
+                ctxMenuStatus: false,
+                ctxMenuRelationship: false,
+                ctxEmbedPayload: false,
+                copiedEmbed: false,
+                replySending: false,
+                ctxEmbedShowCaption: true,
+                ctxEmbedShowLikes: false,
+                ctxEmbedCompactMode: false,
+                confirmModalTitle: 'Are you sure?',
+                confirmModalIdentifer: null,
+                confirmModalType: false,
                 isDeleting: false
-			}
-		},
-
-		watch: {
-			ctxEmbedShowCaption: function (n,o) {
-				if(n == true) {
-					this.ctxEmbedCompactMode = false;
-				}
-				let mode = this.ctxEmbedCompactMode ? 'compact' : 'full';
-				this.ctxEmbedPayload = window.App.util.embed.post(this.ctxMenuStatus.url, this.ctxEmbedShowCaption, this.ctxEmbedShowLikes, mode);
-			},
-			ctxEmbedShowLikes: function (n,o) {
-				if(n == true) {
-					this.ctxEmbedCompactMode = false;
-				}
-				let mode = this.ctxEmbedCompactMode ? 'compact' : 'full';
-				this.ctxEmbedPayload = window.App.util.embed.post(this.ctxMenuStatus.url, this.ctxEmbedShowCaption, this.ctxEmbedShowLikes, mode);
-			},
-			ctxEmbedCompactMode: function (n,o) {
-				if(n == true) {
-					this.ctxEmbedShowCaption = false;
-					this.ctxEmbedShowLikes = false;
-				}
-				let mode = this.ctxEmbedCompactMode ? 'compact' : 'full';
-				this.ctxEmbedPayload = window.App.util.embed.post(this.ctxMenuStatus.url, this.ctxEmbedShowCaption, this.ctxEmbedShowLikes, mode);
-			}
-		},
-
-		methods: {
-			open() {
-				this.ctxMenu();
-			},
-
-			openModMenu() {
-				this.$refs.ctxModModal.show();
-			},
-
-			ctxMenu() {
-				this.ctxMenuStatus = this.status;
-				this.ctxEmbedPayload = window.App.util.embed.post(this.status.url);
-				// if(this.status.account.id == this.profile.id) {
-					this.ctxMenuRelationship = false;
-					this.$refs.ctxModal.show();
-				// } else {
-				// 	axios.get('/api/pixelfed/v1/accounts/relationships', {
-				// 		params: {
-				// 			'id[]': this.status.account.id
-				// 		}
-				// 	}).then(res => {
-				// 		this.ctxMenuRelationship = res.data[0];
-				// 		this.$refs.ctxModal.show();
-				// 	});
-				// }
-			},
-
-			closeCtxMenu() {
-				this.copiedEmbed = false;
-				this.ctxMenuStatus = false;
-				this.ctxMenuRelationship = false;
-				this.$refs.ctxModal.hide();
-				this.$refs.ctxReport.hide();
-				this.$refs.ctxReportOther.hide();
-				this.closeModals();
-			},
-
-			ctxMenuCopyLink() {
-				let status = this.ctxMenuStatus;
-				navigator.clipboard.writeText(status.url);
-				this.closeModals();
-				return;
-			},
-
-			ctxMenuGoToPost() {
-				let status = this.ctxMenuStatus;
-				this.statusUrl(status);
-				this.closeCtxMenu();
-				return;
-			},
-
-			ctxMenuGoToProfile() {
-				let status = this.ctxMenuStatus;
-				this.profileUrl(status);
-				this.closeCtxMenu();
-				return;
-			},
-
-			ctxMenuReportPost() {
-				this.$refs.ctxModal.hide();
-				// this.$refs.ctxReport.show();
-				this.$emit('report-modal', this.ctxMenuStatus);
-				return;
-			},
-
-			ctxMenuEmbed() {
-				this.closeModals();
-				this.$refs.ctxEmbedModal.show();
-			},
-
-			ctxMenuShare() {
-				this.$refs.ctxModal.hide();
-				this.$refs.ctxShareModal.show();
-			},
-
-			closeCtxShareMenu() {
-				this.$refs.ctxShareModal.hide();
-				this.$refs.ctxModal.show();
-			},
-
-			ctxCopyEmbed() {
-				navigator.clipboard.writeText(this.ctxEmbedPayload);
-				this.ctxEmbedShowCaption = true;
-				this.ctxEmbedShowLikes = false;
-				this.ctxEmbedCompactMode = false;
-				this.$refs.ctxEmbedModal.hide();
-			},
-
-			ctxModMenuShow() {
-				this.$refs.ctxModal.hide();
-				this.$refs.ctxModModal.show();
-			},
-
-			ctxModOtherMenuShow() {
-				this.$refs.ctxModal.hide();
-				this.$refs.ctxModModal.hide();
-				this.$refs.ctxModOtherModal.show();
-			},
-
-			ctxModMenu() {
-				this.$refs.ctxModal.hide();
-			},
-
-			ctxModMenuClose() {
-				this.closeModals();
-			},
-
-			ctxModOtherMenuClose() {
-				this.closeModals();
-				this.$refs.ctxModModal.show();
-			},
-
-			formatCount(count) {
-				return App.util.format.count(count);
-			},
-
-			openCtxReportOtherMenu() {
-				let s = this.ctxMenuStatus;
-				this.closeCtxMenu();
-				this.ctxMenuStatus = s;
-				this.$refs.ctxReportOther.show();
-			},
-
-			ctxReportMenuGoBack() {
-				this.$refs.ctxReportOther.hide();
-				this.$refs.ctxReport.hide();
-				this.$refs.ctxModal.show();
-			},
-
-			ctxReportOtherMenuGoBack() {
-				this.$refs.ctxReportOther.hide();
-				this.$refs.ctxModal.hide();
-				this.$refs.ctxReport.show();
-			},
-
-			sendReport(type) {
-				let id = this.ctxMenuStatus.id;
-
-				swal({
-					'title': this.$t('menu.confirmReport'),
-					'text': this.$t('menu.confirmReportText'),
-					'icon': 'warning',
-					'buttons': true,
-					'dangerMode': true
-				}).then((res) => {
-					if(res) {
-						axios.post('/i/report/', {
-							'report': type,
-							'type': 'post',
-							'id': id,
-						}).then(res => {
-							this.closeCtxMenu();
-							swal(this.$t('menu.reportSent'), this.$t('menu.reportSentText'), 'success');
-						}).catch(err => {
-							swal(this.$t('common.oops'), this.$t('menu.reportSentError'), 'error');
-						})
-					} else {
-						this.closeCtxMenu();
-					}
-				});
-			},
-
-			closeModals() {
-				this.$refs.ctxModal.hide();
-				this.$refs.ctxModModal.hide();
-				this.$refs.ctxModOtherModal.hide();
-				this.$refs.ctxShareModal.hide();
-				this.$refs.ctxEmbedModal.hide();
-				this.$refs.ctxReport.hide();
-				this.$refs.ctxReportOther.hide();
-				this.$refs.ctxConfirm.hide();
-			},
-
-			openCtxStatusModal() {
-				this.closeModals();
-				this.$refs.ctxStatusModal.show();
-			},
-
-			openConfirmModal() {
-				this.closeModals();
-				this.$refs.ctxConfirm.show();
-			},
-
-			closeConfirmModal() {
-				this.closeModals();
-				this.confirmModalTitle = 'Are you sure?';
-				this.confirmModalType = false;
-				this.confirmModalIdentifer = null;
-			},
-
-			confirmModalConfirm() {
-				switch(this.confirmModalType) {
-					case 'post.delete':
-						axios.post('/i/delete', {
-							type: 'status',
-							item: this.confirmModalIdentifer
-						}).then(res => {
-							this.feed = this.feed.filter(s => {
-								return s.id != this.confirmModalIdentifer;
-							});
-							this.closeConfirmModal();
-						}).catch(err => {
-							this.closeConfirmModal();
-							swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
-						});
-					break;
-				}
-
-				this.closeConfirmModal();
-			},
-
-			confirmModalCancel() {
-				this.closeConfirmModal();
-			},
-
-			moderatePost(status, action, $event) {
-				let username = status.account.username;
-				let pid = status.id;
-				let msg = '';
-				let self = this;
-				switch(action) {
-					case 'addcw':
-						msg = this.$t('menu.modAddCWConfirm');
-						swal({
-							title: 'Confirm',
-							text: msg,
-							icon: 'warning',
-							buttons: true,
-							dangerMode: true
-						}).then(res =>  {
-							if(res) {
-								axios.post('/api/v2/moderator/action', {
-									action: action,
-									item_id: status.id,
-									item_type: 'status'
-								}).then(res => {
-									swal(this.$t('common.success'), this.$t('menu.modCWSuccess'), 'success');
-									// status.sensitive = true;
-									this.$emit('moderate', 'addcw');
-									self.closeModals();
-									self.ctxModMenuClose();
-								}).catch(err => {
-									self.closeModals();
-									self.ctxModMenuClose();
-									swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
-								});
-							}
-						});
-					break;
-
-					case 'remcw':
-						msg = this.$t('menu.modRemoveCWConfirm');
-						swal({
-							title: 'Confirm',
-							text: msg,
-							icon: 'warning',
-							buttons: true,
-							dangerMode: true
-						}).then(res =>  {
-							if(res) {
-								axios.post('/api/v2/moderator/action', {
-									action: action,
-									item_id: status.id,
-									item_type: 'status'
-								}).then(res => {
-									swal(this.$t('common.success'), this.$t('menu.modRemoveCWSuccess'), 'success');
-									// status.sensitive = false;
-									this.$emit('moderate', 'remcw');
-									self.closeModals();
-									self.ctxModMenuClose();
-								}).catch(err => {
-									self.closeModals();
-									self.ctxModMenuClose();
-									swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
-								});
-							}
-						});
-					break;
-
-					case 'unlist':
-						msg = this.$t('menu.modUnlistConfirm');
-						swal({
-							title: 'Confirm',
-							text: msg,
-							icon: 'warning',
-							buttons: true,
-							dangerMode: true
-						}).then(res =>  {
-							if(res) {
-								axios.post('/api/v2/moderator/action', {
-									action: action,
-									item_id: status.id,
-									item_type: 'status'
-								}).then(res => {
-									// this.feed = this.feed.filter(f => {
-									// 	return f.id != status.id;
-									// });
-									this.$emit('moderate', 'unlist');
-									swal(this.$t('common.success'), this.$t('menu.modUnlistSuccess'), 'success');
-									self.closeModals();
-									self.ctxModMenuClose();
-								}).catch(err => {
-									self.closeModals();
-									self.ctxModMenuClose();
-									swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
-								});
-							}
-						});
-					break;
-
-					case 'spammer':
-						msg = this.$t('menu.modMarkAsSpammerConfirm');
-						swal({
-							title: 'Confirm',
-							text: msg,
-							icon: 'warning',
-							buttons: true,
-							dangerMode: true
-						}).then(res =>  {
-							if(res) {
-								axios.post('/api/v2/moderator/action', {
-									action: action,
-									item_id: status.id,
-									item_type: 'status'
-								}).then(res => {
-									this.$emit('moderate', 'spammer');
-									swal(this.$t('common.success'), this.$t('menu.modMarkAsSpammerSuccess'), 'success');
-									self.closeModals();
-									self.ctxModMenuClose();
-								}).catch(err => {
-									self.closeModals();
-									self.ctxModMenuClose();
-									swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
-								});
-							}
-						});
-					break;
-				}
-			},
-
-			shareStatus(status, $event) {
-				if($('body').hasClass('loggedIn') == false) {
-					return;
-				}
-
-				this.closeModals();
-
-				axios.post('/i/share', {
-					item: status.id
-				}).then(res => {
-					status.reblogs_count = res.data.count;
-					status.reblogged = !status.reblogged;
-					// if(status.reblogged) {
-					// 	swal('Success', 'You shared this post', 'success');
-					// } else {
-					// 	swal('Success', 'You unshared this post', 'success');
-					// }
-				}).catch(err => {
-					swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
-				});
-			},
-
-			statusUrl(status) {
-				if(status.account.local == true) {
-					this.$router.push({
-						name: 'post',
-						path: `/i/web/post/${status.id}`,
-						params: {
-							id: status.id,
-							cachedStatus: status,
-							cachedProfile: this.profile
-						}
-					});
-					return;
-				}
-
-				let permalink = this.$route.params.hasOwnProperty('id');
-				if(permalink) {
-					location.href = status.url;
-					return;
-				} else {
-					this.$router.push({
-						name: 'post',
-						path: `/i/web/post/${status.id}`,
-						params: {
-							id: status.id,
-							cachedStatus: status,
-							cachedProfile: this.profile
-						}
-					});
-					return;
-				}
-			},
-
-			profileUrl(status) {
-				this.$router.push({
-					name: 'profile',
-					path: `/i/web/profile/${status.account.id}`,
-					params: {
-						id: status.account.id,
-						cachedProfile: status.account,
-						cachedUser: this.profile
-					}
-				});
-				return;
-			},
-
-			deletePost(status) {
+            }
+        },
+
+        watch: {
+            ctxEmbedShowCaption: function (n,o) {
+                if(n == true) {
+                    this.ctxEmbedCompactMode = false;
+                }
+                let mode = this.ctxEmbedCompactMode ? 'compact' : 'full';
+                this.ctxEmbedPayload = window.App.util.embed.post(this.ctxMenuStatus.url, this.ctxEmbedShowCaption, this.ctxEmbedShowLikes, mode);
+            },
+            ctxEmbedShowLikes: function (n,o) {
+                if(n == true) {
+                    this.ctxEmbedCompactMode = false;
+                }
+                let mode = this.ctxEmbedCompactMode ? 'compact' : 'full';
+                this.ctxEmbedPayload = window.App.util.embed.post(this.ctxMenuStatus.url, this.ctxEmbedShowCaption, this.ctxEmbedShowLikes, mode);
+            },
+            ctxEmbedCompactMode: function (n,o) {
+                if(n == true) {
+                    this.ctxEmbedShowCaption = false;
+                    this.ctxEmbedShowLikes = false;
+                }
+                let mode = this.ctxEmbedCompactMode ? 'compact' : 'full';
+                this.ctxEmbedPayload = window.App.util.embed.post(this.ctxMenuStatus.url, this.ctxEmbedShowCaption, this.ctxEmbedShowLikes, mode);
+            }
+        },
+
+        methods: {
+            open() {
+                this.ctxMenu();
+            },
+
+            openModMenu() {
+                this.$refs.ctxModModal.show();
+            },
+
+            ctxMenu() {
+                this.ctxMenuStatus = this.status;
+                this.ctxEmbedPayload = window.App.util.embed.post(this.status.url);
+                if(this.status.account.id == this.profile.id) {
+                    this.ctxMenuRelationship = false;
+                    this.$refs.ctxModal.show();
+                } else {
+                 axios.get('/api/v1/accounts/relationships', {
+                     params: {
+                         'id[]': this.status.account.id
+                     }
+                 }).then(res => {
+                     this.ctxMenuRelationship = res.data[0];
+                     this.$refs.ctxModal.show();
+                 });
+                }
+            },
+
+            closeCtxMenu() {
+                this.copiedEmbed = false;
+                this.ctxMenuStatus = false;
+                this.ctxMenuRelationship = false;
+                this.$refs.ctxModal.hide();
+                this.$refs.ctxReport.hide();
+                this.$refs.ctxReportOther.hide();
+                this.closeModals();
+            },
+
+            ctxMenuCopyLink() {
+                let status = this.ctxMenuStatus;
+                navigator.clipboard.writeText(status.url);
+                this.closeModals();
+                return;
+            },
+
+            ctxMenuGoToPost() {
+                let status = this.ctxMenuStatus;
+                this.statusUrl(status);
+                this.closeCtxMenu();
+                return;
+            },
+
+            ctxMenuGoToProfile() {
+                let status = this.ctxMenuStatus;
+                this.profileUrl(status);
+                this.closeCtxMenu();
+                return;
+            },
+
+            ctxMenuReportPost() {
+                this.$refs.ctxModal.hide();
+                // this.$refs.ctxReport.show();
+                this.$emit('report-modal', this.ctxMenuStatus);
+                return;
+            },
+
+            ctxMenuEmbed() {
+                this.closeModals();
+                this.$refs.ctxEmbedModal.show();
+            },
+
+            ctxMenuShare() {
+                this.$refs.ctxModal.hide();
+                this.$refs.ctxShareModal.show();
+            },
+
+            closeCtxShareMenu() {
+                this.$refs.ctxShareModal.hide();
+                this.$refs.ctxModal.show();
+            },
+
+            ctxCopyEmbed() {
+                navigator.clipboard.writeText(this.ctxEmbedPayload);
+                this.ctxEmbedShowCaption = true;
+                this.ctxEmbedShowLikes = false;
+                this.ctxEmbedCompactMode = false;
+                this.$refs.ctxEmbedModal.hide();
+            },
+
+            ctxModMenuShow() {
+                this.$refs.ctxModal.hide();
+                this.$refs.ctxModModal.show();
+            },
+
+            ctxModOtherMenuShow() {
+                this.$refs.ctxModal.hide();
+                this.$refs.ctxModModal.hide();
+                this.$refs.ctxModOtherModal.show();
+            },
+
+            ctxModMenu() {
+                this.$refs.ctxModal.hide();
+            },
+
+            ctxModMenuClose() {
+                this.closeModals();
+            },
+
+            ctxModOtherMenuClose() {
+                this.closeModals();
+                this.$refs.ctxModModal.show();
+            },
+
+            formatCount(count) {
+                return App.util.format.count(count);
+            },
+
+            openCtxReportOtherMenu() {
+                let s = this.ctxMenuStatus;
+                this.closeCtxMenu();
+                this.ctxMenuStatus = s;
+                this.$refs.ctxReportOther.show();
+            },
+
+            ctxReportMenuGoBack() {
+                this.$refs.ctxReportOther.hide();
+                this.$refs.ctxReport.hide();
+                this.$refs.ctxModal.show();
+            },
+
+            ctxReportOtherMenuGoBack() {
+                this.$refs.ctxReportOther.hide();
+                this.$refs.ctxModal.hide();
+                this.$refs.ctxReport.show();
+            },
+
+            sendReport(type) {
+                let id = this.ctxMenuStatus.id;
+
+                swal({
+                    'title': this.$t('menu.confirmReport'),
+                    'text': this.$t('menu.confirmReportText'),
+                    'icon': 'warning',
+                    'buttons': true,
+                    'dangerMode': true
+                }).then((res) => {
+                    if(res) {
+                        axios.post('/i/report/', {
+                            'report': type,
+                            'type': 'post',
+                            'id': id,
+                        }).then(res => {
+                            this.closeCtxMenu();
+                            swal(this.$t('menu.reportSent'), this.$t('menu.reportSentText'), 'success');
+                        }).catch(err => {
+                            swal(this.$t('common.oops'), this.$t('menu.reportSentError'), 'error');
+                        })
+                    } else {
+                        this.closeCtxMenu();
+                    }
+                });
+            },
+
+            closeModals() {
+                this.$refs.ctxModal.hide();
+                this.$refs.ctxModModal.hide();
+                this.$refs.ctxModOtherModal.hide();
+                this.$refs.ctxShareModal.hide();
+                this.$refs.ctxEmbedModal.hide();
+                this.$refs.ctxReport.hide();
+                this.$refs.ctxReportOther.hide();
+                this.$refs.ctxConfirm.hide();
+            },
+
+            openCtxStatusModal() {
+                this.closeModals();
+                this.$refs.ctxStatusModal.show();
+            },
+
+            openConfirmModal() {
+                this.closeModals();
+                this.$refs.ctxConfirm.show();
+            },
+
+            closeConfirmModal() {
+                this.closeModals();
+                this.confirmModalTitle = 'Are you sure?';
+                this.confirmModalType = false;
+                this.confirmModalIdentifer = null;
+            },
+
+            confirmModalConfirm() {
+                switch(this.confirmModalType) {
+                    case 'post.delete':
+                        axios.post('/i/delete', {
+                            type: 'status',
+                            item: this.confirmModalIdentifer
+                        }).then(res => {
+                            this.feed = this.feed.filter(s => {
+                                return s.id != this.confirmModalIdentifer;
+                            });
+                            this.closeConfirmModal();
+                        }).catch(err => {
+                            this.closeConfirmModal();
+                            swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
+                        });
+                    break;
+                }
+
+                this.closeConfirmModal();
+            },
+
+            confirmModalCancel() {
+                this.closeConfirmModal();
+            },
+
+            moderatePost(status, action, $event) {
+                let username = status.account.username;
+                let pid = status.id;
+                let msg = '';
+                let self = this;
+                switch(action) {
+                    case 'addcw':
+                        msg = this.$t('menu.modAddCWConfirm');
+                        swal({
+                            title: 'Confirm',
+                            text: msg,
+                            icon: 'warning',
+                            buttons: true,
+                            dangerMode: true
+                        }).then(res =>  {
+                            if(res) {
+                                axios.post('/api/v2/moderator/action', {
+                                    action: action,
+                                    item_id: status.id,
+                                    item_type: 'status'
+                                }).then(res => {
+                                    swal(this.$t('common.success'), this.$t('menu.modCWSuccess'), 'success');
+                                    // status.sensitive = true;
+                                    this.$emit('moderate', 'addcw');
+                                    self.closeModals();
+                                    self.ctxModMenuClose();
+                                }).catch(err => {
+                                    self.closeModals();
+                                    self.ctxModMenuClose();
+                                    swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
+                                });
+                            }
+                        });
+                    break;
+
+                    case 'remcw':
+                        msg = this.$t('menu.modRemoveCWConfirm');
+                        swal({
+                            title: 'Confirm',
+                            text: msg,
+                            icon: 'warning',
+                            buttons: true,
+                            dangerMode: true
+                        }).then(res =>  {
+                            if(res) {
+                                axios.post('/api/v2/moderator/action', {
+                                    action: action,
+                                    item_id: status.id,
+                                    item_type: 'status'
+                                }).then(res => {
+                                    swal(this.$t('common.success'), this.$t('menu.modRemoveCWSuccess'), 'success');
+                                    // status.sensitive = false;
+                                    this.$emit('moderate', 'remcw');
+                                    self.closeModals();
+                                    self.ctxModMenuClose();
+                                }).catch(err => {
+                                    self.closeModals();
+                                    self.ctxModMenuClose();
+                                    swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
+                                });
+                            }
+                        });
+                    break;
+
+                    case 'unlist':
+                        msg = this.$t('menu.modUnlistConfirm');
+                        swal({
+                            title: 'Confirm',
+                            text: msg,
+                            icon: 'warning',
+                            buttons: true,
+                            dangerMode: true
+                        }).then(res =>  {
+                            if(res) {
+                                axios.post('/api/v2/moderator/action', {
+                                    action: action,
+                                    item_id: status.id,
+                                    item_type: 'status'
+                                }).then(res => {
+                                    // this.feed = this.feed.filter(f => {
+                                    //  return f.id != status.id;
+                                    // });
+                                    this.$emit('moderate', 'unlist');
+                                    swal(this.$t('common.success'), this.$t('menu.modUnlistSuccess'), 'success');
+                                    self.closeModals();
+                                    self.ctxModMenuClose();
+                                }).catch(err => {
+                                    self.closeModals();
+                                    self.ctxModMenuClose();
+                                    swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
+                                });
+                            }
+                        });
+                    break;
+
+                    case 'spammer':
+                        msg = this.$t('menu.modMarkAsSpammerConfirm');
+                        swal({
+                            title: 'Confirm',
+                            text: msg,
+                            icon: 'warning',
+                            buttons: true,
+                            dangerMode: true
+                        }).then(res =>  {
+                            if(res) {
+                                axios.post('/api/v2/moderator/action', {
+                                    action: action,
+                                    item_id: status.id,
+                                    item_type: 'status'
+                                }).then(res => {
+                                    this.$emit('moderate', 'spammer');
+                                    swal(this.$t('common.success'), this.$t('menu.modMarkAsSpammerSuccess'), 'success');
+                                    self.closeModals();
+                                    self.ctxModMenuClose();
+                                }).catch(err => {
+                                    self.closeModals();
+                                    self.ctxModMenuClose();
+                                    swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
+                                });
+                            }
+                        });
+                    break;
+                }
+            },
+
+            statusUrl(status) {
+                if(status.account.local == true) {
+                    this.$router.push({
+                        name: 'post',
+                        path: `/i/web/post/${status.id}`,
+                        params: {
+                            id: status.id,
+                            cachedStatus: status,
+                            cachedProfile: this.profile
+                        }
+                    });
+                    return;
+                }
+
+                let permalink = this.$route.params.hasOwnProperty('id');
+                if(permalink) {
+                    location.href = status.url;
+                    return;
+                } else {
+                    this.$router.push({
+                        name: 'post',
+                        path: `/i/web/post/${status.id}`,
+                        params: {
+                            id: status.id,
+                            cachedStatus: status,
+                            cachedProfile: this.profile
+                        }
+                    });
+                    return;
+                }
+            },
+
+            profileUrl(status) {
+                this.$router.push({
+                    name: 'profile',
+                    path: `/i/web/profile/${status.account.id}`,
+                    params: {
+                        id: status.account.id,
+                        cachedProfile: status.account,
+                        cachedUser: this.profile
+                    }
+                });
+                return;
+            },
+
+            deletePost(status) {
                 this.isDeleting = true;
 
-				if(this.ownerOrAdmin(status) == false) {
-					return;
-				}
-
-				if(window.confirm(this.$t('menu.deletePostConfirm')) == false) {
-					return;
-				}
-
-				axios.post('/i/delete', {
-					type: 'status',
-					item: status.id
-				}).then(res => {
-					this.$emit('delete');
-					this.closeModals();
-                    this.isDeleting = false;
-				}).catch(err => {
-					swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
-				});
-			},
-
-			owner(status) {
-				return this.profile.id === status.account.id;
-			},
-
-			admin() {
-				return this.profile.is_admin == true;
-			},
-
-			ownerOrAdmin(status) {
-				return this.owner(status) || this.admin();
-			},
-
-			archivePost(status) {
-				if(window.confirm(this.$t('menu.archivePostConfirm')) == false) {
-					return;
-				}
-
-				axios.post('/api/pixelfed/v2/status/' + status.id + '/archive')
-				.then(res => {
-					this.$emit('status-delete', status.id);
-					this.$emit('archived', status.id);
-					this.closeModals();
-				});
-			},
-
-			unarchivePost(status) {
-				if(window.confirm(this.$t('menu.unarchivePostConfirm')) == false) {
-					return;
-				}
-
-				axios.post('/api/pixelfed/v2/status/' + status.id + '/unarchive')
-				.then(res => {
-					this.$emit('unarchived', status.id);
-					this.closeModals();
-				});
-			},
-
-			editPost(status) {
-				this.closeModals();
-				this.$emit('edit', status);
-			}
-		}
-	}
+                if(this.ownerOrAdmin(status) == false) {
+                    return;
+                }
+
+                swal({
+                    title: 'Confirm Delete',
+                    text: 'Are you sure you want to delete this post?',
+                    icon: "warning",
+                    buttons: true,
+                    dangerMode: true,
+                })
+                .then(res => {
+                    if(!res) {
+                        this.closeModals();
+                        this.isDeleting = false;
+                    } else {
+                        axios.post('/i/delete', {
+                            type: 'status',
+                            item: status.id
+                        }).then(res => {
+                            this.$emit('delete');
+                            this.closeModals();
+                            this.isDeleting = false;
+                        }).catch(err => {
+                            this.closeModals();
+                            this.isDeleting = false;
+                            swal(this.$t('common.error'), this.$t('common.errorMsg'), 'error');
+                        });
+                    }
+                })
+            },
+
+            owner(status) {
+                return this.profile.id === status.account.id;
+            },
+
+            admin() {
+                return this.profile.is_admin == true;
+            },
+
+            ownerOrAdmin(status) {
+                return this.owner(status) || this.admin();
+            },
+
+            archivePost(status) {
+                if(window.confirm(this.$t('menu.archivePostConfirm')) == false) {
+                    return;
+                }
+
+                axios.post('/api/pixelfed/v2/status/' + status.id + '/archive')
+                .then(res => {
+                    this.$emit('delete', status.id);
+                    this.$emit('archived', status.id);
+                    this.closeModals();
+                });
+            },
+
+            unarchivePost(status) {
+                if(window.confirm(this.$t('menu.unarchivePostConfirm')) == false) {
+                    return;
+                }
+
+                axios.post('/api/pixelfed/v2/status/' + status.id + '/unarchive')
+                .then(res => {
+                    this.$emit('unarchived', status.id);
+                    this.closeModals();
+                });
+            },
+
+            editPost(status) {
+                this.closeModals();
+                this.$emit('edit', status);
+            },
+
+            handleMute() {
+                if(!this.ctxMenuRelationship) {
+                    return;
+                }
+                let curState = this.ctxMenuRelationship.muting;
+
+                swal({
+                    title: curState ? 'Confirm Unmute' : 'Confirm Mute',
+                    text: curState ? 'Are you sure you want to unmute this account?' : 'Are you sure you want to mute this account?',
+                    icon: "warning",
+                    buttons: true,
+                    dangerMode: true,
+                })
+                .then(res => {
+                    if(!res) {
+                        this.closeModals();
+                    } else {
+                        let url = curState ?
+                            `/api/v1/accounts/${this.status.account.id}/unmute` :
+                            `/api/v1/accounts/${this.status.account.id}/mute`;
+                        axios.post(url)
+                        .then(res => {
+                            this.closeModals();
+                            this.$emit('muted', this.status);
+                            this.$store.commit('updateRelationship', [res.data]);
+                        })
+                        .catch(err => {
+                            this.closeModals();
+                            if(err && err.response && err.response.data && err.response.data.error) {
+                                swal('Error', err.response.data.error, 'error');
+                            } else {
+                                swal('Oops!', 'An error occured, please try again later.', 'error');
+                            }
+                        })
+                    }
+                })
+            },
+
+            handleBlock() {
+                if(!this.ctxMenuRelationship) {
+                    return;
+                }
+                let curState = this.ctxMenuRelationship.blocking;
+
+                swal({
+                    title: curState ? 'Confirm Unblock' : 'Confirm Block',
+                    text: curState ? 'Are you sure you want to unblock this account?' : 'Are you sure you want to block this account?',
+                    icon: "warning",
+                    buttons: true,
+                    dangerMode: true,
+                })
+                .then(res => {
+                    if(!res) {
+                        this.closeModals();
+                    } else {
+                        let url = curState ?
+                            `/api/v1/accounts/${this.status.account.id}/unblock` :
+                            `/api/v1/accounts/${this.status.account.id}/block`;
+                        axios.post(url)
+                        .then(res => {
+                            this.closeModals();
+                            this.$store.commit('updateRelationship', [res.data]);
+                            this.$emit('muted', this.status);
+                        })
+                        .catch(err => {
+                            this.closeModals();
+                            if(err && err.response && err.response.data && err.response.data.error) {
+                                swal('Error', err.response.data.error, 'error');
+                            } else {
+                                swal('Oops!', 'An error occured, please try again later.', 'error');
+                            }
+                        })
+                    }
+                })
+            },
+
+            handleUnfollow() {
+                if(!this.ctxMenuRelationship) {
+                    return;
+                }
+
+                swal({
+                    title: 'Unfollow',
+                    text: 'Are you sure you want to unfollow ' + this.status.account.username + '?',
+                    icon: "warning",
+                    buttons: true,
+                    dangerMode: true,
+                })
+                .then(res => {
+                    if(!res) {
+                        this.closeModals();
+                    } else {
+                        axios.post(`/api/v1/accounts/${this.status.account.id}/unfollow`)
+                        .then(res => {
+                            this.closeModals();
+                            this.$store.commit('updateRelationship', [res.data]);
+                            this.$emit('unfollow', this.status);
+                        })
+                        .catch(err => {
+                            this.closeModals();
+                            if(err && err.response && err.response.data && err.response.data.error) {
+                                swal('Error', err.response.data.error, 'error');
+                            } else {
+                                swal('Oops!', 'An error occured, please try again later.', 'error');
+                            }
+                        })
+                    }
+                })
+            },
+        }
+    }
 </script>
+
+<style lang="scss" scoped>
+    .menu-option {
+        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+        text-decoration: none;
+        font-weight: 500;
+        color: var(--dark);
+    }
+
+    .list-group-item {
+        border-color: var(--border-color);
+    }
+
+    .action-icon-link {
+        display: flex;
+        flex-direction: column;
+
+        .icon {
+            opacity: 0.5;
+            margin-bottom: 5px;
+        }
+
+        p {
+            font-weight: 600;
+            font-size: 11px;
+        }
+
+        &-inline {
+            display: flex;
+            flex-direction: row;
+            justify-content: center;
+            align-items: center;
+            gap: 8px;
+
+            p {
+                font-weight: bold;
+            }
+        }
+    }
+</style>

+ 18 - 0
resources/assets/components/sections/Timeline.vue

@@ -91,6 +91,8 @@
             v-on:delete="deletePost"
             v-on:report-modal="handleReport"
             v-on:edit="handleEdit"
+            v-on:muted="handleMuted"
+            v-on:unfollow="handleUnfollow"
         />
 
         <likes-modal
@@ -543,6 +545,7 @@
 
             deletePost() {
                 this.feed.splice(this.postIndex, 1);
+                this.forceUpdateIdx++;
             },
 
             counterChange(index, type) {
@@ -788,6 +791,21 @@
                 .then(res => {
                 })
             },
+
+            handleMuted(post) {
+                this.feed = this.feed.filter(p => {
+                   return p.account.id !== post.account.id;
+                });
+            },
+
+            handleUnfollow(post) {
+                if(this.scope === 'home') {
+                    this.feed = this.feed.filter(p => {
+                       return p.account.id !== post.account.id;
+                    });
+                }
+                this.updateProfile({ following_count: this.profile.following_count - 1 });
+            },
         },
 
         watch: {

+ 8 - 0
resources/assets/sass/spa.scss

@@ -189,6 +189,10 @@ a.text-dark:hover {
 
 .border {
     border: 1px solid var(--border-color) !important;
+
+    &-right {
+        border-color: var(--border-color) !important;
+    }
 }
 
 .bg-white,
@@ -396,6 +400,10 @@ span.twitter-typeahead .tt-suggestion:focus {
     color: var(--dark);
 }
 
+.modal-backdrop {
+    opacity: 0.8;
+}
+
 .timeline-status-component {
     .username {
         font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików