From 06042569f1d2f2c7217917459df007adbb113e53 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 3 Feb 2022 22:10:45 +0200
Subject: fix alignment issues

---
 src/components/popover/popover.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 2e78a09e..8588b351 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -33,7 +33,7 @@
 @import '../../_variables.scss';
 
 .popover-trigger-button {
-  display: block;
+  display: inline-block;
 }
 
 .popover {
-- 
cgit v1.2.3-70-g09d2


From 041c72b07c7d0559bd5b97c49503e69707aa08b2 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Wed, 6 Apr 2022 20:04:36 -0400
Subject: Fix dropdown menu style inside panel header

---
 src/components/popover/popover.vue | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 8588b351..1502c30c 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -149,5 +149,30 @@
     }
 
   }
+
+  .button-default.dropdown-item {
+    &,
+    i[class*=icon-] {
+      color: $fallback--text;
+      color: var(--btnText, $fallback--text);
+    }
+
+    &:active {
+      background-color: $fallback--fg;
+      background-color: var(--btnPressed, $fallback--fg);
+      color: $fallback--text;
+      color: var(--btnPressedText, $fallback--text);
+    }
+
+    &:disabled {
+      color: $fallback--text;
+      color: var(--btnDisabledText, $fallback--text);
+    }
+
+    &.toggled {
+      color: $fallback--text;
+      color: var(--btnToggledText, $fallback--text);
+    }
+  }
 }
 </style>
-- 
cgit v1.2.3-70-g09d2


From fce9c5eeb2092a3c66609afbed81f933b6bec069 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Wed, 6 Apr 2022 22:50:01 -0400
Subject: Fix active popover style

---
 src/components/popover/popover.vue | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 1502c30c..332a0398 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -158,10 +158,10 @@
     }
 
     &:active {
-      background-color: $fallback--fg;
-      background-color: var(--btnPressed, $fallback--fg);
-      color: $fallback--text;
-      color: var(--btnPressedText, $fallback--text);
+      background-color: $fallback--lightBg;
+      background-color: var(--selectedMenuPopover, $fallback--lightBg);
+      color: $fallback--link;
+      color: var(--selectedMenuPopoverText, $fallback--link);
     }
 
     &:disabled {
-- 
cgit v1.2.3-70-g09d2


From 51c996bd7e964802233f031090a97b6e3786794d Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 7 Apr 2022 16:18:39 +0300
Subject: boost z-index of popover

---
 src/components/popover/popover.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 332a0398..4b3ad7da 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -37,7 +37,7 @@
 }
 
 .popover {
-  z-index: 8;
+  z-index: 90;
   position: absolute;
   min-width: 0;
 }
-- 
cgit v1.2.3-70-g09d2


From 282e6812b38b5354b1f5a77297cf77ca7365397e Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 8 Apr 2022 13:31:29 +0300
Subject: fix chats, boost popover's z-index some more

---
 src/components/chat/chat.scss      | 43 --------------------------------------
 src/components/popover/popover.vue |  2 +-
 2 files changed, 1 insertion(+), 44 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/chat/chat.scss b/src/components/chat/chat.scss
index 85e9f59d..34a335fe 100644
--- a/src/components/chat/chat.scss
+++ b/src/components/chat/chat.scss
@@ -108,47 +108,4 @@
       }
     }
   }
-
-  @media all and (max-width: 800px) {
-    height: 100%;
-    overflow: hidden;
-
-    .chat-view-inner {
-      overflow: hidden;
-      height: 100%;
-      margin-top: 0;
-      margin-left: 0;
-      margin-right: 0;
-    }
-
-    .chat-view-body {
-      display: flex;
-      min-height: auto;
-      overflow: hidden;
-      height: 100%;
-      margin: 0;
-      border-radius: 0;
-    }
-
-    .chat-view-heading {
-      box-sizing: border-box;
-      position: static;
-      top: 0;
-      margin-top: 0;
-      border-radius: 0;
-      height: 50px;
-    }
-
-    .scrollable-message-list {
-      display: unset;
-      overflow-y: scroll;
-      overflow-x: hidden;
-      -webkit-overflow-scrolling: touch;
-    }
-
-    .footer {
-      position: sticky;
-      bottom: auto;
-    }
-  }
 }
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 4b3ad7da..3f2a81f5 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -37,7 +37,7 @@
 }
 
 .popover {
-  z-index: 90;
+  z-index: 500;
   position: absolute;
   min-width: 0;
 }
-- 
cgit v1.2.3-70-g09d2


From f27226b55cefe6e351e562bbc908f5517e236804 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 10 Apr 2022 22:09:46 +0300
Subject: improvements to relative font sizes

---
 src/App.scss                       |  6 +++---
 src/components/popover/popover.vue |  2 +-
 src/panel.scss                     | 13 +++++++------
 3 files changed, 11 insertions(+), 10 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/App.scss b/src/App.scss
index cc8ef592..1025bb50 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -301,7 +301,7 @@ nav {
   cursor: pointer;
   box-shadow: $fallback--buttonShadow;
   box-shadow: var(--buttonShadow);
-  font-size: 1rem;
+  font-size: 1em;
   font-family: sans-serif;
   font-family: var(--interfaceFont, sans-serif);
 
@@ -429,7 +429,7 @@ textarea,
   color: var(--inputText, $fallback--lightText);
   font-family: sans-serif;
   font-family: var(--inputFont, sans-serif);
-  font-size: 1rem;
+  font-size: 1em;
   margin: 0;
   box-sizing: border-box;
   display: inline-block;
@@ -730,7 +730,7 @@ i[class*=icon-],
 }
 
 .btn.button-default {
-  min-height: 28px;
+  min-height: 2em;
 }
 
 .new-status-notification {
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 3f2a81f5..973625d1 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -65,7 +65,7 @@
 .dropdown-menu {
   display: block;
   padding: .5rem 0;
-  font-size: 1rem;
+  font-size: 1em;
   text-align: left;
   list-style: none;
   max-width: 100vw;
diff --git a/src/panel.scss b/src/panel.scss
index 049144ba..b23ec4bb 100644
--- a/src/panel.scss
+++ b/src/panel.scss
@@ -28,7 +28,8 @@
 
 .panel-body:empty::before {
   content: "¯\\_(ツ)_/¯"; // Could use words but it'd require translations
-  display: block; margin: 1em;
+  display: block;
+  margin: 1em;
   text-align: center;
 }
 
@@ -42,18 +43,18 @@
   background-size: cover;
   padding: 0.6em 0.6em;
   text-align: left;
-  line-height: 28px;
+  line-height: calc(var(--panel-heading-height) / 2);
   color: var(--panelText);
   background-color: $fallback--bg;
   background-color: var(--bg, $fallback--bg);
   align-items: baseline;
-  height: var(--panelHeadingHeight);
+  height: var(--panel-heading-height);
   z-index: -2;
 
-  --panelHeadingHeight: 45px;
+  --panel-heading-height: 3.2em;
 
   &.-flexible-height {
-    --panelHeadingHeight: auto;
+    --panel-heading-height: auto;
 
     &::after,
     &::before {
@@ -92,7 +93,7 @@
     z-index: -1;
     border-radius: $fallback--panelRadius $fallback--panelRadius 0 0;
     border-radius: var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius) 0 0;
-    mask: linear-gradient(to bottom, white var(--panelHeadingHeight), transparent var(--panelHeadingHeight));
+    mask: linear-gradient(to bottom, white var(--panel-heading-height), transparent var(--panel-heading-height));
   }
 
   .title {
-- 
cgit v1.2.3-70-g09d2


From df18a74adc4dbad7ca0daf38c041f9ac482a29c8 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 11 Apr 2022 23:18:46 +0300
Subject: fixes for z-indexes

---
 src/components/popover/popover.vue                   |  2 +-
 src/components/post_status_form/post_status_form.vue |  4 ++--
 src/panel.scss                                       | 16 +++++-----------
 3 files changed, 8 insertions(+), 14 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 973625d1..91939ee7 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -69,7 +69,7 @@
   text-align: left;
   list-style: none;
   max-width: 100vw;
-  z-index: 10;
+  z-index: 200;
   white-space: nowrap;
 
   .dropdown-divider {
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index 47b8a213..f052e4de 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -509,7 +509,7 @@
     flex-direction: column;
     padding: 0.25em 0.5em 0.5em;
     line-height:24px;
-    z-index: 50;
+    z-index: 10;
   }
 
   form textarea.form-cw {
@@ -572,7 +572,7 @@
 
   .drop-indicator {
     position: absolute;
-    z-index: 100;
+    z-index: 11;
     width: 100%;
     height: 100%;
     font-size: 5em;
diff --git a/src/panel.scss b/src/panel.scss
index 57059cb9..175d2181 100644
--- a/src/panel.scss
+++ b/src/panel.scss
@@ -2,7 +2,6 @@
   position: relative;
   display: flex;
   flex-direction: column;
-  z-index: 0;
   background-color: $fallback--bg;
   background-color: var(--bg, $fallback--bg);
 
@@ -19,7 +18,7 @@
     bottom: 0;
     left: 0;
     right: 0;
-    z-index: 100;
+    z-index: 3;
     box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
     box-shadow: var(--panelShadow);
     pointer-events: none;
@@ -53,7 +52,6 @@
   background-color: var(--bg, $fallback--bg);
   align-items: baseline;
   height: var(--panel-heading-height);
-  z-index: -2;
 
   &.-flexible-height {
     --panel-heading-height: auto;
@@ -90,14 +88,6 @@
     box-shadow: var(--panelHeaderShadow);
   }
 
-  &::before {
-    bottom: -20px;
-    z-index: -1;
-    border-radius: $fallback--panelRadius $fallback--panelRadius 0 0;
-    border-radius: var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius) 0 0;
-    mask: linear-gradient(to bottom, white var(--panel-heading-height), transparent var(--panel-heading-height));
-  }
-
   .title {
     flex: 1 0 auto;
     font-size: 1.3em;
@@ -202,3 +192,7 @@
   padding: 1em;
   margin: 0;
 }
+
+.panel-body {
+  padding: var(--panel-body-padding, 0);
+}
-- 
cgit v1.2.3-70-g09d2


From e744775ce8a5ca5f5fbad63e207ce75dbde04e63 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 11 Apr 2022 23:49:46 +0300
Subject: fix dropdown menus

---
 src/components/popover/popover.vue | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 91939ee7..e1eb2c21 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -45,8 +45,19 @@
 .popover-default {
   transition: opacity 0.3s;
 
-  box-shadow: 1px 1px 4px rgba(0,0,0,.6);
-  box-shadow: var(--panelShadow);
+  &:after {
+    content: '';
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    z-index: 3;
+    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
+    box-shadow: var(--panelShadow);
+    pointer-events: none;
+  }
+
   border-radius: $fallback--btnRadius;
   border-radius: var(--btnRadius, $fallback--btnRadius);
 
@@ -110,14 +121,15 @@
     &:active, &:hover {
       background-color: $fallback--lightBg;
       background-color: var(--selectedMenuPopover, $fallback--lightBg);
-      color: $fallback--link;
-      color: var(--selectedMenuPopoverText, $fallback--link);
+      box-shadow: none;
+      --btnText: var(--selectedMenuPopoverText, $fallback--link);
       --faint: var(--selectedMenuPopoverFaintText, $fallback--faint);
       --faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint);
       --lightText: var(--selectedMenuPopoverLightText, $fallback--lightText);
       --icon: var(--selectedMenuPopoverIcon, $fallback--icon);
       svg {
         color: var(--selectedMenuPopoverIcon, $fallback--icon);
+        --icon: var(--selectedMenuPopoverIcon, $fallback--icon);
       }
     }
 
-- 
cgit v1.2.3-70-g09d2


From d87a1fda591a972571ce45dbb21bd193ef892555 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 20 Apr 2022 00:37:08 +0300
Subject: fix scrollbars in dropdowns

---
 src/components/notifications/notification_filters.vue | 8 ++------
 src/components/popover/popover.vue                    | 2 +-
 src/panel.scss                                        | 6 +++---
 3 files changed, 6 insertions(+), 10 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/notifications/notification_filters.vue b/src/components/notifications/notification_filters.vue
index ba0e90a0..7418fc7c 100644
--- a/src/components/notifications/notification_filters.vue
+++ b/src/components/notifications/notification_filters.vue
@@ -64,7 +64,7 @@
       </div>
     </template>
     <template v-slot:trigger>
-      <button class="button-unstyled">
+      <button class="filter-trigger-button button-unstyled">
         <FAIcon icon="filter" />
       </button>
     </template>
@@ -106,17 +106,13 @@ export default {
 .NotificationFilters {
   align-self: stretch;
 
-  > button {
+  .filter-trigger-button {
     font-size: 1.2em;
     padding-left: 0.7em;
     padding-right: 0.2em;
     line-height: 100%;
     height: 100%;
   }
-
-  .dropdown-item {
-    margin: 0;
-  }
 }
 
 </style>
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index e1eb2c21..044b887d 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -95,7 +95,7 @@
     line-height: 21px;
     overflow: auto;
     display: block;
-    padding: .5em 0.75em;
+    padding: 0.25em 0.75em;
     clear: both;
     font-weight: 400;
     text-align: inherit;
diff --git a/src/panel.scss b/src/panel.scss
index f3e51d39..147b17a9 100644
--- a/src/panel.scss
+++ b/src/panel.scss
@@ -110,8 +110,8 @@
     overflow-x: hidden;
   }
 
-  .button-default,
-  .alert {
+  > .button-default,
+  > .alert {
     height: var(--__panel-heading-height-inner);
     min-height: 0;
     box-sizing: border-box;
@@ -122,7 +122,7 @@
     padding-bottom: 0;
   }
 
-  .button-default {
+  > .button-default {
     flex-shrink: 0;
 
     &,
-- 
cgit v1.2.3-70-g09d2


From 631b8b93a4a8dd548bae5ab9fa7bc4d6e892ae3f Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 20 Apr 2022 19:44:31 +0300
Subject: tons of fixes mainly aimed at panel headings

---
 src/App.scss                                       |   6 +-
 src/components/account_actions/account_actions.vue |   4 -
 src/components/popover/popover.vue                 |  12 +-
 .../settings_modal/tabs/theme_tab/theme_tab.scss   |  17 --
 src/components/timeline/timeline.js                |   2 +-
 src/components/timeline/timeline.scss              |  22 +-
 src/components/timeline/timeline.vue               |   2 +-
 .../timeline/timeline_quick_settings.vue           |  16 +-
 src/components/user_card/user_card.vue             | 325 +--------------------
 src/components/user_profile/user_profile.vue       |  18 --
 .../user_reporting_modal/user_reporting_modal.vue  |  11 -
 src/panel.scss                                     |  77 ++---
 12 files changed, 73 insertions(+), 439 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/App.scss b/src/App.scss
index 0ee1c610..bc792263 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -641,12 +641,10 @@ option {
 }
 
 .alert {
-  margin: 0.35em;
-  padding: 0.25em;
+  margin: 0 0.35em;
+  padding: 0 0.25em;
   border-radius: $fallback--tooltipRadius;
   border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
-  min-height: 28px;
-  line-height: 28px;
 
   &.error {
     background-color: $fallback--alertError;
diff --git a/src/components/account_actions/account_actions.vue b/src/components/account_actions/account_actions.vue
index 1e31151c..c35d01af 100644
--- a/src/components/account_actions/account_actions.vue
+++ b/src/components/account_actions/account_actions.vue
@@ -74,10 +74,6 @@
 <style lang="scss">
 @import '../../_variables.scss';
 .AccountActions {
-  button.dropdown-item {
-    margin-left: 0;
-  }
-
   .ellipsis-button {
     width: 2.5em;
     margin: -0.5em 0;
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 044b887d..0350daa1 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -93,7 +93,7 @@
 
   .dropdown-item {
     line-height: 21px;
-    overflow: auto;
+    overflow: hidden;
     display: block;
     padding: 0.25em 0.75em;
     clear: both;
@@ -154,9 +154,13 @@
         content: '✓';
       }
 
-      &.menu-checkbox-radio::after {
-        font-size: 2em;
-        content: '•';
+      &.-radio {
+        border-radius: 9999px;
+
+        &.menu-checkbox-checked::after {
+          font-size: 2em;
+          content: '•';
+        }
       }
     }
 
diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss
index 21b49a32..cb8e477c 100644
--- a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss
+++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss
@@ -245,25 +245,8 @@
         border-color: var(--border, $fallback--border);
       }
 
-      .panel-heading {
-        .badge, .alert, .btn, .faint {
-          margin-left: 1em;
-          white-space: nowrap;
-        }
-        .faint {
-          text-overflow: ellipsis;
-          min-width: 2em;
-          overflow-x: hidden;
-        }
-        .flex-spacer {
-          flex: 1;
-        }
-      }
       .btn {
-        margin-left: 0;
-        padding: 0 1em;
         min-width: 3em;
-        min-height: 30px;
       }
     }
   }
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index 4ae7410e..f79b5167 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -60,7 +60,7 @@ const Timeline = {
       }
     },
     classes () {
-      let rootClasses = !this.embedded ? ['panel', 'panel-default'] : []
+      let rootClasses = !this.embedded ? ['panel', 'panel-default'] : ['-nonpanel']
       if (this.blockingClicks) rootClasses = rootClasses.concat(['-blocked', '_misclick-prevention'])
       return {
         root: rootClasses,
diff --git a/src/components/timeline/timeline.scss b/src/components/timeline/timeline.scss
index ae8324b3..4c58e686 100644
--- a/src/components/timeline/timeline.scss
+++ b/src/components/timeline/timeline.scss
@@ -13,15 +13,6 @@
     max-width: 100%;
     flex-wrap: nowrap;
     align-items: center;
-
-    .loadmore-button {
-      flex-shrink: 0;
-    }
-
-    .loadmore-text {
-      flex-shrink: 0;
-      line-height: 1em;
-    }
   }
 
   .timeline-footer {
@@ -31,4 +22,17 @@
   .conversation-heading {
     top: calc(var(--panel-heading-height) * 2);
   }
+
+  &.-nonpanel {
+    .timeline-heading {
+      text-align: center;
+      line-height: 2.75em;
+      padding: 0 0.5em;
+    }
+
+    .button-default, .alert {
+      line-height: 2em;
+      width: 100%;
+    }
+  }
 }
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index d37a9e2a..ff3cd72d 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -1,5 +1,5 @@
 <template>
-  <div :class="[classes.root, 'Timeline']">
+  <div :class="['Timeline', classes.root]">
     <div :class="classes.header">
       <TimelineMenu v-if="!embedded" />
       <button
diff --git a/src/components/timeline/timeline_quick_settings.vue b/src/components/timeline/timeline_quick_settings.vue
index 4d67e06b..c62d0fe9 100644
--- a/src/components/timeline/timeline_quick_settings.vue
+++ b/src/components/timeline/timeline_quick_settings.vue
@@ -12,8 +12,8 @@
             @click="replyVisibilityAll = true"
           >
             <span
-              class="menu-checkbox"
-              :class="{ 'menu-checkbox-radio': replyVisibilityAll }"
+              class="menu-checkbox -radio"
+              :class="{ 'menu-checkbox-checked': replyVisibilityAll }"
             />{{ $t('settings.reply_visibility_all') }}
           </button>
           <button
@@ -21,8 +21,8 @@
             @click="replyVisibilityFollowing = true"
           >
             <span
-              class="menu-checkbox"
-              :class="{ 'menu-checkbox-radio': replyVisibilityFollowing }"
+              class="menu-checkbox -radio"
+              :class="{ 'menu-checkbox-checked': replyVisibilityFollowing }"
             />{{ $t('settings.reply_visibility_following_short') }}
           </button>
           <button
@@ -30,8 +30,8 @@
             @click="replyVisibilitySelf = true"
           >
             <span
-              class="menu-checkbox"
-              :class="{ 'menu-checkbox-radio': replyVisibilitySelf }"
+              class="menu-checkbox -radio"
+              :class="{ 'menu-checkbox-checked': replyVisibilitySelf }"
             />{{ $t('settings.reply_visibility_self_short') }}
           </button>
           <div
@@ -102,10 +102,6 @@
     line-height: 100%;
     height: 100%;
   }
-
-  .dropdown-item {
-    margin: 0;
-  }
 }
 
 </style>
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 43a660e1..67837845 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -284,327 +284,4 @@
 
 <script src="./user_card.js"></script>
 
-<style lang="scss">
-@import '../../_variables.scss';
-
-.user-card {
-  position: relative;
-  z-index: 1;
-
-  &:hover {
-    --_still-image-img-visibility: visible;
-    --_still-image-canvas-visibility: hidden;
-    --_still-image-label-visibility: hidden;
-  }
-
-  .panel-heading {
-    padding: .5em 0;
-    text-align: center;
-    box-shadow: none;
-    background: transparent;
-    flex-direction: column;
-    align-items: stretch;
-    // create new stacking context
-    position: relative;
-  }
-
-  .panel-body {
-    word-wrap: break-word;
-    border-bottom-right-radius: inherit;
-    border-bottom-left-radius: inherit;
-    // create new stacking context
-    position: relative;
-  }
-
-  .background-image {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    mask: linear-gradient(to top, white, transparent) bottom no-repeat,
-          linear-gradient(to top, white, white);
-    // Autoprefixed seem to ignore this one, and also syntax is different
-                                                 -webkit-mask-composite: xor;
-    mask-composite: exclude;
-    background-size: cover;
-    mask-size: 100% 60%;
-    border-top-left-radius: calc(var(--panelRadius) - 1px);
-    border-top-right-radius: calc(var(--panelRadius) - 1px);
-    background-color: var(--profileBg);
-    z-index: -2;
-
-    &.hide-bio {
-      mask-size: 100% 40px;
-    }
-  }
-
-  &-bio {
-    text-align: center;
-    display: block;
-    line-height: 18px;
-    padding: 1em;
-    margin: 0;
-
-    a {
-      color: $fallback--link;
-      color: var(--postLink, $fallback--link);
-    }
-
-    img {
-      object-fit: contain;
-      vertical-align: middle;
-      max-width: 100%;
-      max-height: 400px;
-    }
-  }
-
-  // Modifiers
-
-  &-rounded-t {
-    border-top-left-radius: $fallback--panelRadius;
-    border-top-left-radius: var(--panelRadius, $fallback--panelRadius);
-    border-top-right-radius: $fallback--panelRadius;
-    border-top-right-radius: var(--panelRadius, $fallback--panelRadius);
-  }
-
-  &-rounded {
-    border-radius: $fallback--panelRadius;
-    border-radius: var(--panelRadius, $fallback--panelRadius);
-  }
-
-  &-bordered {
-    border-width: 1px;
-    border-style: solid;
-    border-color: $fallback--border;
-    border-color: var(--border, $fallback--border);
-  }
-}
-
-.user-info {
-  color: $fallback--lightText;
-  color: var(--lightText, $fallback--lightText);
-  padding: 0 26px;
-
-  .container {
-    min-width: 0;
-    padding: 16px 0 6px;
-    display: flex;
-    align-items: flex-start;
-    max-height: 56px;
-
-    > * {
-      min-width: 0;
-    }
-
-    .Avatar {
-      --_avatarShadowBox: var(--avatarShadow);
-      --_avatarShadowFilter: var(--avatarShadowFilter);
-      --_avatarShadowInset: var(--avatarShadowInset);
-
-      flex: 1 0 100%;
-      width: 56px;
-      height: 56px;
-      object-fit: cover;
-    }
-  }
-
-  &-avatar-link {
-    position: relative;
-    cursor: pointer;
-
-    &-overlay {
-      position: absolute;
-      left: 0;
-      top: 0;
-      right: 0;
-      bottom: 0;
-      background-color: rgba(0, 0, 0, 0.3);
-      display: flex;
-      justify-content: center;
-      align-items: center;
-      border-radius: $fallback--avatarRadius;
-      border-radius: var(--avatarRadius, $fallback--avatarRadius);
-      opacity: 0;
-      transition: opacity .2s ease;
-
-      svg {
-        color: #FFF;
-      }
-    }
-
-    &:hover &-overlay {
-      opacity: 1;
-    }
-  }
-
-  .external-link-button, .edit-profile-button {
-    cursor: pointer;
-    width: 2.5em;
-    text-align: center;
-    margin: -0.5em 0;
-    padding: 0.5em 0;
-
-    &:not(:hover) .icon {
-      color: $fallback--lightText;
-      color: var(--lightText, $fallback--lightText);
-    }
-  }
-
-  .user-summary {
-    display: block;
-    margin-left: 0.6em;
-    text-align: left;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    flex: 1 1 0;
-    // This is so that text doesn't get overlapped by avatar's shadow if it has
-    // big one
-    z-index: 1;
-
-    .top-line {
-      display: flex;
-    }
-  }
-
-  .user-name {
-    text-overflow: ellipsis;
-    overflow: hidden;
-    flex: 1 1 auto;
-    margin-right: 1em;
-    font-size: 15px;
-
-    --emoji-size: 14px;
-  }
-
-  .bottom-line {
-    display: flex;
-    font-weight: light;
-    font-size: 15px;
-
-    .lock-icon {
-      margin-left: 0.5em;
-    }
-
-    .user-screen-name {
-      min-width: 1px;
-      flex: 0 1 auto;
-      text-overflow: ellipsis;
-      overflow: hidden;
-      color: $fallback--lightText;
-      color: var(--lightText, $fallback--lightText);
-    }
-
-    .dailyAvg {
-      min-width: 1px;
-      flex: 0 0 auto;
-      margin-left: 1em;
-      font-size: 0.7em;
-      color: $fallback--text;
-      color: var(--text, $fallback--text);
-    }
-
-    .user-role {
-      flex: none;
-      color: $fallback--text;
-      color: var(--alertNeutralText, $fallback--text);
-      background-color: $fallback--fg;
-      background-color: var(--alertNeutral, $fallback--fg);
-    }
-  }
-
-  .user-meta {
-    margin-bottom: .15em;
-    display: flex;
-    align-items: baseline;
-    font-size: 14px;
-    line-height: 22px;
-    flex-wrap: wrap;
-
-    .following {
-      flex: 1 0 auto;
-      margin: 0;
-      margin-bottom: .25em;
-      text-align: left;
-    }
-
-    .highlighter {
-      flex: 0 1 auto;
-      display: flex;
-      flex-wrap: wrap;
-      margin-right: -.5em;
-      align-self: start;
-
-      .userHighlightCl {
-        padding: 2px 10px;
-        flex: 1 0 auto;
-      }
-
-      .userHighlightSel {
-        padding-top: 0;
-        padding-bottom: 0;
-        flex: 1 0 auto;
-      }
-
-      .userHighlightText {
-        width: 70px;
-        flex: 1 0 auto;
-      }
-
-      .userHighlightCl,
-      .userHighlightText,
-      .userHighlightSel {
-        vertical-align: top;
-        margin-right: .5em;
-        margin-bottom: .25em;
-      }
-    }
-  }
-  .user-interactions {
-    position: relative;
-    display: flex;
-    flex-flow: row wrap;
-    margin-right: -.75em;
-
-    > * {
-      margin: 0 .75em .6em 0;
-      white-space: nowrap;
-      min-width: 95px;
-    }
-
-    button {
-      margin: 0;
-    }
-  }
-}
-
-.sidebar .edit-profile-button {
-  display: none;
-}
-
-.user-counts {
-  display: flex;
-  line-height:16px;
-  padding: .5em 1.5em 0em 1.5em;
-  text-align: center;
-  justify-content: space-between;
-  color: $fallback--lightText;
-  color: var(--lightText, $fallback--lightText);
-  flex-wrap: wrap;
-}
-
-.user-count {
-  flex: 1 0 auto;
-  padding: .5em 0 .5em 0;
-  margin: 0 .5em;
-
-  h5 {
-    font-size:1em;
-    font-weight: bolder;
-    margin: 0 0 0.25em;
-  }
-  a {
-    text-decoration: none;
-  }
-}
-</style>
+<style lang="scss" src="./user_card.scss" />
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 726216ff..f1e3cb72 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -192,24 +192,6 @@
     align-items: middle;
     padding: 2em;
   }
-
-  .timeline-heading {
-    display: flex;
-    justify-content: center;
-
-    .loadmore-button, .alert {
-      flex: 1;
-    }
-
-    .loadmore-button {
-      height: 28px;
-      margin: 10px .6em;
-    }
-
-    .title, .loadmore-text {
-      display: none
-    }
-  }
 }
 .user-profile-placeholder {
   .panel-body {
diff --git a/src/components/user_reporting_modal/user_reporting_modal.vue b/src/components/user_reporting_modal/user_reporting_modal.vue
index cc456365..ba12a246 100644
--- a/src/components/user_reporting_modal/user_reporting_modal.vue
+++ b/src/components/user_reporting_modal/user_reporting_modal.vue
@@ -76,17 +76,6 @@
   min-height: 20vh;
   max-height: 80vh;
 
-  .panel-heading {
-    .title {
-      text-align: center;
-      // TODO: Consider making these as default of panel
-      flex: 1;
-      overflow: hidden;
-      text-overflow: ellipsis;
-      white-space: nowrap;
-    }
-  }
-
   .panel-body {
     display: flex;
     flex-direction: column-reverse;
diff --git a/src/panel.scss b/src/panel.scss
index 147b17a9..167c60a6 100644
--- a/src/panel.scss
+++ b/src/panel.scss
@@ -39,7 +39,11 @@
 
   position: relative;
   box-sizing: border-box;
-  display: flex;
+  display: grid;
+  grid-auto-flow: column;
+  grid-template-columns: 1fr;
+  grid-auto-columns: auto;
+  grid-column-gap: 0.5em;
   flex: none;
   border-radius: $fallback--panelRadius $fallback--panelRadius 0 0;
   border-radius: var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius) 0 0;
@@ -89,7 +93,6 @@
   }
 
   .title {
-    flex: 1 0 auto;
     font-size: 1.3em;
   }
 
@@ -110,42 +113,44 @@
     overflow-x: hidden;
   }
 
-  > .button-default,
-  > .alert {
-    height: var(--__panel-heading-height-inner);
-    min-height: 0;
-    box-sizing: border-box;
-    margin: 0;
-    margin-left: 0.5em;
-    min-width: 1px;
-    padding-top: 0;
-    padding-bottom: 0;
-  }
-
-  > .button-default {
-    flex-shrink: 0;
-
-    &,
-    i[class*=icon-] {
-      color: $fallback--text;
-      color: var(--btnPanelText, $fallback--text);
-    }
-
-    &:active {
-      background-color: $fallback--fg;
-      background-color: var(--btnPressedPanel, $fallback--fg);
-      color: $fallback--text;
-      color: var(--btnPressedPanelText, $fallback--text);
-    }
-
-    &:disabled {
-      color: $fallback--text;
-      color: var(--btnDisabledPanelText, $fallback--text);
+  &:not(.-flexible-height) {
+    > .button-default,
+    > .alert {
+      height: var(--__panel-heading-height-inner);
+      min-height: 0;
+      box-sizing: border-box;
+      margin: 0;
+      min-width: 1px;
+      padding-top: 0;
+      padding-bottom: 0;
+      align-self: stretch;
     }
 
-    &.toggled {
-      color: $fallback--text;
-      color: var(--btnToggledPanelText, $fallback--text);
+    > .button-default {
+      flex-shrink: 0;
+
+      &,
+      i[class*=icon-] {
+        color: $fallback--text;
+        color: var(--btnPanelText, $fallback--text);
+      }
+
+      &:active {
+        background-color: $fallback--fg;
+        background-color: var(--btnPressedPanel, $fallback--fg);
+        color: $fallback--text;
+        color: var(--btnPressedPanelText, $fallback--text);
+      }
+
+      &:disabled {
+        color: $fallback--text;
+        color: var(--btnDisabledPanelText, $fallback--text);
+      }
+
+      &.toggled {
+        color: $fallback--text;
+        color: var(--btnToggledPanelText, $fallback--text);
+      }
     }
   }
 
-- 
cgit v1.2.3-70-g09d2


From 85c515b3952d819b4bb983426ac562c4c00a193d Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 20 Apr 2022 19:57:01 +0300
Subject: more fixes for timeline headers

---
 src/components/notifications/notification_filters.vue | 11 +++++++----
 src/components/popover/popover.vue                    |  2 +-
 src/components/timeline/timeline.vue                  |  2 +-
 src/components/timeline/timeline_quick_settings.vue   |  9 ++++++---
 4 files changed, 15 insertions(+), 9 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/notifications/notification_filters.vue b/src/components/notifications/notification_filters.vue
index 7418fc7c..d0b11a13 100644
--- a/src/components/notifications/notification_filters.vue
+++ b/src/components/notifications/notification_filters.vue
@@ -106,12 +106,15 @@ export default {
 .NotificationFilters {
   align-self: stretch;
 
-  .filter-trigger-button {
-    font-size: 1.2em;
-    padding-left: 0.7em;
-    padding-right: 0.2em;
+  > button {
     line-height: 100%;
     height: 100%;
+    width: var(--__panel-heading-height-inner);
+    text-align: center;
+
+    svg {
+      font-size: 1.2em;
+    }
   }
 }
 
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 0350daa1..d98ca8e7 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -5,7 +5,7 @@
   >
     <button
       ref="trigger"
-      class="button-unstyled -fullwidth popover-trigger-button"
+      class="button-unstyled popover-trigger-button"
       type="button"
       @click="onClick"
     >
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index ff3cd72d..958808f6 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -60,7 +60,7 @@
       </div>
       <button
         v-else-if="!timeline.loading"
-        class="button-unstyled -link -fullwidth"
+        class="button-unstyled -link"
         @click.prevent="fetchOlderStatuses()"
       >
         <div class="new-status-notification text-center">
diff --git a/src/components/timeline/timeline_quick_settings.vue b/src/components/timeline/timeline_quick_settings.vue
index c62d0fe9..5efc5d7c 100644
--- a/src/components/timeline/timeline_quick_settings.vue
+++ b/src/components/timeline/timeline_quick_settings.vue
@@ -96,11 +96,14 @@
   align-self: stretch;
 
   > button {
-    font-size: 1.2em;
-    padding-left: 0.7em;
-    padding-right: 0.2em;
     line-height: 100%;
     height: 100%;
+    width: var(--__panel-heading-height-inner);
+    text-align: center;
+
+    svg {
+      font-size: 1.2em;
+    }
   }
 }
 
-- 
cgit v1.2.3-70-g09d2


From 491449c41883c0ab3436c2ea16c5c49424097ce9 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 21 Apr 2022 00:21:46 +0300
Subject: undo mistake

---
 src/components/popover/popover.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index d98ca8e7..c2a3e801 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -95,7 +95,7 @@
     line-height: 21px;
     overflow: hidden;
     display: block;
-    padding: 0.25em 0.75em;
+    padding: 0.5em 0.75em;
     clear: both;
     font-weight: 400;
     text-align: inherit;
-- 
cgit v1.2.3-70-g09d2


From fd831a27f4e9c6bcd5c40f3449d63546fba2560d Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 20 May 2022 00:56:23 +0300
Subject: experimental disjointed popups

---
 src/App.vue                                  |  1 +
 src/components/popover/popover.js            | 10 +++++++++-
 src/components/popover/popover.vue           | 28 +++++++++++++++-------------
 src/components/react_button/react_button.vue |  1 +
 4 files changed, 26 insertions(+), 14 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/App.vue b/src/App.vue
index 5b448972..c217ade5 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -54,6 +54,7 @@
     <PostStatusModal />
     <SettingsModal />
     <div id="modal" />
+    <div id="popovers" />
     <GlobalNoticeList />
   </div>
 </template>
diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index a30a37c9..db283ef0 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -43,6 +43,7 @@ const Popover = {
   methods: {
     containerBoundingClientRect () {
       const container = this.boundToSelector ? this.$el.closest(this.boundToSelector) : this.$el.offsetParent
+      console.log(container)
       return container.getBoundingClientRect()
     },
     updateStyles () {
@@ -125,10 +126,17 @@ const Popover = {
 
       // Note, separate translateX and translateY avoids blurry text on chromium,
       // single translate or translate3d resulted in blurry text.
+      console.log(translateX + screenBox.x + screenBox.width)
+      console.log(Math.round(parentBounds.width))
       this.styles = {
         opacity: 1,
-        transform: `translateX(${Math.round(translateX)}px) translateY(${Math.round(translateY)}px)`
+        // transform: `translateX(${Math.round(translateX)}px) translateY(${Math.round(translateY)}px)`
+        left: `${Math.round(translateX + screenBox.x + screenBox.width / 2)}px`,
+        top: `${Math.round(translateY + screenBox.y + screenBox.height / 2)}px`,
+        maxWidth: `${Math.round(parentBounds.width)}px`,
+        position: 'fixed'
       }
+      console.log(this.styles)
     },
     showPopover () {
       const wasHidden = this.hidden
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index c2a3e801..8f6ef2e6 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -11,19 +11,21 @@
     >
       <slot name="trigger" />
     </button>
-    <div
-      v-if="!hidden"
-      ref="content"
-      :style="styles"
-      class="popover"
-      :class="popoverClass || 'popover-default'"
-    >
-      <slot
-        name="content"
-        class="popover-inner"
-        :close="hidePopover"
-      />
-    </div>
+    <teleport to="#popovers">
+      <div
+        v-if="!hidden"
+        ref="content"
+        :style="styles"
+        class="popover"
+        :class="popoverClass || 'popover-default'"
+      >
+        <slot
+          name="content"
+          class="popover-inner"
+          :close="hidePopover"
+        />
+      </div>
+    </teleport>
   </div>
 </template>
 
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index 7f35b7b5..8da691c0 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -6,6 +6,7 @@
     :offset="{ y: 5 }"
     :bound-to="{ x: 'container' }"
     remove-padding
+    popover-class="ReactButton popover-default"
     @show="focusInput"
   >
     <template v-slot:content="{close}">
-- 
cgit v1.2.3-70-g09d2


From 61d63b0e616392d841b78095ae8045e98d2b2fa6 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 12 Jun 2022 15:23:43 +0300
Subject: fix popovers so that all of them have shadows

---
 src/components/popover/popover.vue               | 2 ++
 src/components/status_popover/status_popover.vue | 2 --
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 8f6ef2e6..6103fbdc 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -42,6 +42,8 @@
   z-index: 500;
   position: absolute;
   min-width: 0;
+  box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
+  box-shadow: var(--popupShadow);
 }
 
 .popover-default {
diff --git a/src/components/status_popover/status_popover.vue b/src/components/status_popover/status_popover.vue
index fdca8c9c..b6a3be32 100644
--- a/src/components/status_popover/status_popover.vue
+++ b/src/components/status_popover/status_popover.vue
@@ -52,8 +52,6 @@
   border-width: 1px;
   border-radius: $fallback--tooltipRadius;
   border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
-  box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
-  box-shadow: var(--popupShadow);
 
   /* TODO cleanup this */
   .Status.Status {
-- 
cgit v1.2.3-70-g09d2


From 55adcd822e194be8aaeb9d6b649de90e9d5e1e45 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 12 Jun 2022 16:31:56 +0300
Subject: fix animations, replace ugly old mentionlink tooltips with new
 usercard ones

---
 src/App.scss                                       |   2 +-
 src/components/mention_link/mention_link.js        |   8 +-
 src/components/mention_link/mention_link.scss      |   7 +-
 src/components/mention_link/mention_link.vue       | 133 ++++++++++++---------
 src/components/popover/popover.js                  |  40 +++++--
 src/components/popover/popover.vue                 |  36 +++---
 src/components/settings_modal/tabs/general_tab.vue |   2 +-
 src/i18n/en.json                                   |   2 +-
 8 files changed, 140 insertions(+), 90 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/App.scss b/src/App.scss
index 5cd0b96e..79c07683 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -829,7 +829,7 @@ option {
 // Vue transitions
 .fade-enter-active,
 .fade-leave-active {
-  transition: opacity 0.2s;
+  transition: opacity 0.3s;
 }
 
 .fade-enter-from,
diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js
index 55eea195..4b088f88 100644
--- a/src/components/mention_link/mention_link.js
+++ b/src/components/mention_link/mention_link.js
@@ -2,6 +2,7 @@ import generateProfileLink from 'src/services/user_profile_link_generator/user_p
 import { mapGetters, mapState } from 'vuex'
 import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
 import UserAvatar from '../user_avatar/user_avatar.vue'
+import { defineAsyncComponent } from 'vue'
 import { library } from '@fortawesome/fontawesome-svg-core'
 import {
   faAt
@@ -14,7 +15,9 @@ library.add(
 const MentionLink = {
   name: 'MentionLink',
   components: {
-    UserAvatar
+    UserAvatar,
+    Popover: defineAsyncComponent(() => import('../popover/popover.vue')),
+    UserCard: defineAsyncComponent(() => import('../user_card/user_card.vue'))
   },
   props: {
     url: {
@@ -36,6 +39,7 @@ const MentionLink = {
   },
   methods: {
     onClick () {
+      if (this.shouldShowTooltip) return
       const link = generateProfileLink(
         this.userId || this.user.id,
         this.userScreenName || this.user.screen_name
@@ -110,7 +114,7 @@ const MentionLink = {
       }
     },
     shouldShowTooltip () {
-      return this.mergedConfig.mentionLinkShowTooltip && this.mergedConfig.mentionLinkDisplay === 'short' && this.isRemote
+      return this.mergedConfig.mentionLinkShowTooltip
     },
     shouldShowAvatar () {
       return this.mergedConfig.mentionLinkShowAvatar
diff --git a/src/components/mention_link/mention_link.scss b/src/components/mention_link/mention_link.scss
index 1d856ff9..3b3a05b1 100644
--- a/src/components/mention_link/mention_link.scss
+++ b/src/components/mention_link/mention_link.scss
@@ -101,7 +101,6 @@
   }
 
   &:hover .new .full {
-    opacity: 1;
     pointer-events: initial;
   }
 
@@ -113,3 +112,9 @@
     color: var(--faint, $fallback--faint);
   }
 }
+
+.mention-link-popover {
+  max-width: 70ch;
+  max-height: 20rem;
+  overflow: hidden;
+}
diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue
index 022f04c7..686ad27f 100644
--- a/src/components/mention_link/mention_link.vue
+++ b/src/components/mention_link/mention_link.vue
@@ -9,66 +9,85 @@
       class="original"
       target="_blank"
       v-html="content"
-    /><!-- eslint-enable vue/no-v-html --><span
-      v-if="user"
-      class="new"
-      :style="style"
-      :class="classnames"
+    /><!-- eslint-enable vue/no-v-html -->
+    <Popover
+      trigger="click"
+      :bound-to="{ x: 'container'}"
+      bound-to-selector=".column"
+      popover-class="popover-default mention-popover"
+      :disabled="!shouldShowTooltip"
     >
-      <a
-        class="short button-unstyled"
-        :class="{ '-with-tooltip': shouldShowTooltip }"
-        :href="url"
-        @click.prevent="onClick"
-      >
-        <!-- eslint-disable vue/no-v-html -->
-        <UserAvatar
-          v-if="shouldShowAvatar"
-          class="mention-avatar"
-          :user="user"
-        /><span
-          class="shortName"
-        ><FAIcon
-          v-if="useAtIcon"
-          size="sm"
-          icon="at"
-          class="at"
-        />{{ !useAtIcon ? '@' : '' }}<span
-          class="userName"
-          v-html="userName"
-        /><span
-          v-if="shouldShowFullUserName"
-          class="serverName"
-          :class="{ '-faded': shouldFadeDomain }"
-          v-html="'@' + serverName"
-        />
-        </span>
-        <span
-          v-if="isYou && shouldShowYous"
-          :class="{ '-you': shouldBoldenYou }"
-        > {{ ' ' + $t('status.you') }}</span>
-        <!-- eslint-enable vue/no-v-html -->
-      </a><span
-        v-if="shouldShowTooltip"
-        class="full popover-default"
-        :class="[highlightType]"
-      >
+      <template v-slot:trigger>
         <span
-          class="userNameFull"
+          v-if="user"
+          class="new"
+          :style="style"
+          :class="classnames"
         >
-          <!-- eslint-disable vue/no-v-html -->
-          @<span
-            class="userName"
-            v-html="userName"
-          /><span
-            class="serverName"
-            :class="{ '-faded': shouldFadeDomain }"
-            v-html="'@' + serverName"
-          />
-          <!-- eslint-enable vue/no-v-html -->
-        </span>
-      </span>
-    </span>
+          <a
+            class="short button-unstyled"
+            :class="{ '-with-tooltip': shouldShowTooltip }"
+            :href="url"
+            @click.prevent="onClick"
+          >
+            <!-- eslint-disable vue/no-v-html -->
+            <UserAvatar
+              v-if="shouldShowAvatar"
+              class="mention-avatar"
+              :user="user"
+            /><span
+              class="shortName"
+            ><FAIcon
+              v-if="useAtIcon"
+              size="sm"
+              icon="at"
+              class="at"
+            />{{ !useAtIcon ? '@' : '' }}<span
+              class="userName"
+              v-html="userName"
+            /><span
+              v-if="shouldShowFullUserName"
+              class="serverName"
+              :class="{ '-faded': shouldFadeDomain }"
+              v-html="'@' + serverName"
+            />
+            </span>
+            <span
+              v-if="isYou && shouldShowYous"
+              :class="{ '-you': shouldBoldenYou }"
+            > {{ ' ' + $t('status.you') }}</span>
+            <!-- eslint-enable vue/no-v-html -->
+          </a><span
+            v-if="shouldShowTooltip"
+            class="full"
+          >
+            <span
+              class="userNameFull"
+            >
+              <!-- eslint-disable vue/no-v-html -->
+              @<span
+                class="userName"
+                v-html="userName"
+              /><span
+                class="serverName"
+                :class="{ '-faded': shouldFadeDomain }"
+                v-html="'@' + serverName"
+              />
+              <!-- eslint-enable vue/no-v-html -->
+            </span>
+          </span>
+        </span></template>
+      <template v-slot:content>
+        <UserCard
+          class="mention-link-popover"
+          :user-id="user.id"
+          :hide-bio="true"
+          :bordered="false"
+          :allow-zooming-avatar="true"
+          :rounded="true"
+        />
+      </template>
+    </Popover>
   </span>
 </template>
 
diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index a91c084f..3c3a95bd 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -31,13 +31,18 @@ const Popover = {
 
     // If true, subtract padding when calculating position for the popover,
     // use it when popover offset looks to be different on top vs bottom.
-    removePadding: Boolean
+    removePadding: Boolean,
+
+    // self-explanatory (i hope)
+    disabled: Boolean
   },
   data () {
     return {
       hidden: true,
-      styles: { opacity: 0 },
-      oldSize: { width: 0, height: 0 }
+      styles: {},
+      oldSize: { width: 0, height: 0 },
+      // used to avoid blinking if hovered onto popover
+      graceTimeout: null
     }
   },
   methods: {
@@ -47,9 +52,7 @@ const Popover = {
     },
     updateStyles () {
       if (this.hidden) {
-        this.styles = {
-          opacity: 0
-        }
+        this.styles = {}
         return
       }
 
@@ -132,7 +135,6 @@ const Popover = {
       // Note, separate translateX and translateY avoids blurry text on chromium,
       // single translate or translate3d resulted in blurry text.
       this.styles = {
-        opacity: 1,
         left: `${Math.round(translateX)}px`,
         top: `${Math.round(translateY)}px`,
         position: 'fixed'
@@ -143,6 +145,7 @@ const Popover = {
       }
     },
     showPopover () {
+      if (this.disabled) return
       const wasHidden = this.hidden
       this.hidden = false
       this.$nextTick(() => {
@@ -153,13 +156,30 @@ const Popover = {
     hidePopover () {
       if (!this.hidden) this.$emit('close')
       this.hidden = true
-      this.styles = { opacity: 0 }
     },
     onMouseenter (e) {
-      if (this.trigger === 'hover') this.showPopover()
+      if (this.trigger === 'hover') {
+        clearTimeout(this.graceTimeout)
+        this.graceTimeout = null
+        this.showPopover()
+      }
     },
     onMouseleave (e) {
-      if (this.trigger === 'hover') this.hidePopover()
+      if (this.trigger === 'hover') {
+        this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
+      }
+    },
+    onMouseenterContent (e) {
+      if (this.trigger === 'hover') {
+        clearTimeout(this.graceTimeout)
+        this.graceTimeout = null
+        this.showPopover()
+      }
+    },
+    onMouseleaveContent (e) {
+      if (this.trigger === 'hover') {
+        this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
+      }
     },
     onClick (e) {
       if (this.trigger === 'click') {
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 6103fbdc..528c4fb2 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -1,5 +1,5 @@
 <template>
-  <div
+  <span
     @mouseenter="onMouseenter"
     @mouseleave="onMouseleave"
   >
@@ -12,21 +12,25 @@
       <slot name="trigger" />
     </button>
     <teleport to="#popovers">
-      <div
-        v-if="!hidden"
-        ref="content"
-        :style="styles"
-        class="popover"
-        :class="popoverClass || 'popover-default'"
-      >
-        <slot
-          name="content"
-          class="popover-inner"
-          :close="hidePopover"
-        />
-      </div>
+      <transition name="fade">
+        <div
+          v-if="!hidden"
+          ref="content"
+          :style="styles"
+          class="popover"
+          :class="popoverClass || 'popover-default'"
+          @mouseenter="onMouseenterContent"
+          @mouseleave="onMouseleaveContent"
+        >
+          <slot
+            name="content"
+            class="popover-inner"
+            :close="hidePopover"
+          />
+        </div>
+      </transition>
     </teleport>
-  </div>
+  </span>
 </template>
 
 <script src="./popover.js" />
@@ -47,8 +51,6 @@
 }
 
 .popover-default {
-  transition: opacity 0.3s;
-
   &:after {
     content: '';
     position: absolute;
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 1fe51b6d..5b4a126e 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -269,7 +269,7 @@
               path="mentionLinkShowTooltip"
               expert="1"
             >
-              {{ $t('settings.mention_link_show_tooltip') }}
+              {{ $t('settings.mention_link_use_tooltip') }}
             </BooleanSetting>
           </li>
         </ul>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 0cfda804..053e91ff 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -523,7 +523,7 @@
     "mention_link_display_short": "always as short names (e.g. {'@'}foo)",
     "mention_link_display_full_for_remote": "as full names only for remote users (e.g. {'@'}foo{'@'}example.org)",
     "mention_link_display_full": "always as full names (e.g. {'@'}foo{'@'}example.org)",
-    "mention_link_show_tooltip": "Show full user names as tooltip for remote users",
+    "mention_link_use_tooltip": "Show user card when clicking mention links",
     "mention_link_show_avatar": "Show user avatar beside the link",
     "mention_link_fade_domain": "Fade domains (e.g. {'@'}example.org in {'@'}foo{'@'}example.org)",
     "mention_link_bolden_you": "Highlight mention of you when you are mentioned",
-- 
cgit v1.2.3-70-g09d2


From 97e4a3d8e52bc2255f4be23967a2223f5e458a67 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 13 Jun 2022 01:36:41 +0300
Subject: fix popovers in modals

---
 src/App.js                         | 3 +--
 src/App.vue                        | 2 +-
 src/components/popover/popover.vue | 2 +-
 3 files changed, 3 insertions(+), 4 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/App.js b/src/App.js
index f01f8788..d5967685 100644
--- a/src/App.js
+++ b/src/App.js
@@ -4,7 +4,6 @@ import InstanceSpecificPanel from './components/instance_specific_panel/instance
 import FeaturesPanel from './components/features_panel/features_panel.vue'
 import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue'
 import ShoutPanel from './components/shout_panel/shout_panel.vue'
-import SettingsModal from './components/settings_modal/settings_modal.vue'
 import MediaModal from './components/media_modal/media_modal.vue'
 import SideDrawer from './components/side_drawer/side_drawer.vue'
 import MobilePostStatusButton from './components/mobile_post_status_button/mobile_post_status_button.vue'
@@ -32,7 +31,7 @@ export default {
     MobilePostStatusButton,
     MobileNav,
     DesktopNav,
-    SettingsModal,
+    SettingsModal: defineAsyncComponent(() => import('./components/settings_modal/settings_modal.vue')),
     UserReportingModal,
     PostStatusModal,
     GlobalNoticeList
diff --git a/src/App.vue b/src/App.vue
index c217ade5..5d7bb4e1 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -54,8 +54,8 @@
     <PostStatusModal />
     <SettingsModal />
     <div id="modal" />
-    <div id="popovers" />
     <GlobalNoticeList />
+    <div id="popovers" />
   </div>
 </template>
 
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 528c4fb2..25ce32fb 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -43,7 +43,7 @@
 }
 
 .popover {
-  z-index: 500;
+  z-index: 90000;
   position: absolute;
   min-width: 0;
   box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
-- 
cgit v1.2.3-70-g09d2


From 7c633aa9525c8a0533281947c587ff1a5ded75ec Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 13 Jun 2022 13:45:04 +0300
Subject: user popovers WIP

---
 src/components/popover/popover.js  | 91 ++++++++++++++++++++++----------------
 src/components/popover/popover.vue |  2 +-
 src/components/status/status.js    |  4 +-
 src/components/status/status.vue   | 38 +++++++++++-----
 4 files changed, 84 insertions(+), 51 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index dbd446a5..233572a4 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -34,7 +34,13 @@ const Popover = {
     removePadding: Boolean,
 
     // self-explanatory (i hope)
-    disabled: Boolean
+    disabled: Boolean,
+
+    // Instead of putting popover next to anchor, overlay popover's center on top of anchor's center
+    overlayCenters: Boolean,
+
+    // What selector (witin popover!) to use for determining center of popover
+    overlayCentersSelector: String
   },
   data () {
     return {
@@ -73,7 +79,9 @@ const Popover = {
         x: anchorScreenBox.left + anchorWidth * 0.5,
         y: anchorScreenBox.top + anchorHeight * 0.5
       }
-      const content = this.$refs.content
+      const content = this.overlayCentersSelector
+        ? this.$refs.content.querySelector(this.overlayCentersSelector)
+        : this.$refs.content
 
       // Minor optimization, don't call a slow reflow call if we don't have to
       const parentScreenBox = this.boundTo &&
@@ -100,44 +108,51 @@ const Popover = {
         max: window.innerHeight - (margin.bottom || 5)
       }
 
-      let horizOffset = content.offsetWidth * -0.5
-      const leftBorder = origin.x + horizOffset
-      const rightBorder = origin.x - horizOffset
-      // If overflowing from left, move it so that it doesn't
-      if (leftBorder < xBounds.min) {
-        horizOffset += xBounds.min - leftBorder
-      }
+      if (!this.overlayCenters) {
+        let horizOffset = content.offsetWidth * -0.5
+        const leftBorder = origin.x + horizOffset
+        const rightBorder = origin.x - horizOffset
+        // If overflowing from left, move it so that it doesn't
+        if (leftBorder < xBounds.min) {
+          horizOffset += xBounds.min - leftBorder
+        }
 
-      // If overflowing from right, move it so that it doesn't
-      if (rightBorder > xBounds.max) {
-        horizOffset -= rightBorder - xBounds.max
-      }
+        // If overflowing from right, move it so that it doesn't
+        if (rightBorder > xBounds.max) {
+          horizOffset -= rightBorder - xBounds.max
+        }
+
+        // Default to whatever user wished with placement prop
+        let usingTop = this.placement !== 'bottom'
 
-      // Default to whatever user wished with placement prop
-      let usingTop = this.placement !== 'bottom'
-
-      // Handle special cases, first force to displaying on top if there's not space on bottom,
-      // regardless of what placement value was. Then check if there's not space on top, and
-      // force to bottom, again regardless of what placement value was.
-      const topBoundary = origin.y - anchorHeight * 0.5 + (this.removePadding ? topPadding : 0)
-      const bottomBoundary = origin.y + anchorHeight * 0.5 - (this.removePadding ? bottomPadding : 0)
-      if (bottomBoundary + content.offsetHeight > yBounds.max) usingTop = true
-      if (topBoundary - content.offsetHeight < yBounds.min) usingTop = false
-
-      const yOffset = (this.offset && this.offset.y) || 0
-      const translateY = usingTop
-        ? topBoundary - yOffset - content.offsetHeight
-        : bottomBoundary + yOffset
-
-      const xOffset = (this.offset && this.offset.x) || 0
-      const translateX = origin.x + horizOffset + xOffset
-
-      // Note, separate translateX and translateY avoids blurry text on chromium,
-      // single translate or translate3d resulted in blurry text.
-      this.styles = {
-        left: `${Math.round(translateX)}px`,
-        top: `${Math.round(translateY)}px`,
-        position: 'fixed'
+        // Handle special cases, first force to displaying on top if there's not space on bottom,
+        // regardless of what placement value was. Then check if there's not space on top, and
+        // force to bottom, again regardless of what placement value was.
+        const topBoundary = origin.y - anchorHeight * 0.5 + (this.removePadding ? topPadding : 0)
+        const bottomBoundary = origin.y + anchorHeight * 0.5 - (this.removePadding ? bottomPadding : 0)
+        if (bottomBoundary + content.offsetHeight > yBounds.max) usingTop = true
+        if (topBoundary - content.offsetHeight < yBounds.min) usingTop = false
+
+        const yOffset = (this.offset && this.offset.y) || 0
+        const translateY = usingTop
+          ? topBoundary - yOffset - content.offsetHeight
+          : bottomBoundary + yOffset
+
+        const xOffset = (this.offset && this.offset.x) || 0
+        const translateX = origin.x + horizOffset + xOffset
+
+        this.styles = {
+          left: `${Math.round(translateX)}px`,
+          top: `${Math.round(translateY)}px`
+        }
+      } else {
+        const translateY = origin.y - content.offsetHeight
+        const translateX = origin.x - content.offsetWidth
+
+        this.styles = {
+          left: `${Math.round(translateX)}px`,
+          top: `${Math.round(translateY)}px`
+        }
       }
 
       if (parentScreenBox) {
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 25ce32fb..977c3559 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -44,7 +44,7 @@
 
 .popover {
   z-index: 90000;
-  position: absolute;
+  position: fixed;
   min-width: 0;
   box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
   box-shadow: var(--popupShadow);
diff --git a/src/components/status/status.js b/src/components/status/status.js
index a925f30b..06496258 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -11,6 +11,7 @@ import Timeago from '../timeago/timeago.vue'
 import StatusContent from '../status_content/status_content.vue'
 import RichContent from 'src/components/rich_content/rich_content.jsx'
 import StatusPopover from '../status_popover/status_popover.vue'
+import Popover from '../popover/popover.vue'
 import UserListPopover from '../user_list_popover/user_list_popover.vue'
 import EmojiReactions from '../emoji_reactions/emoji_reactions.vue'
 import MentionsLine from 'src/components/mentions_line/mentions_line.vue'
@@ -115,7 +116,8 @@ const Status = {
     StatusContent,
     RichContent,
     MentionLink,
-    MentionsLine
+    MentionsLine,
+    Popover
   },
   props: [
     'statusoid',
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 67ce999a..624960fe 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -122,17 +122,33 @@
           v-if="!noHeading"
           class="left-side"
         >
-          <a
-            :href="$router.resolve(userProfileLink).href"
-            @click.stop.prevent.capture="toggleUserExpanded"
-          >
-            <UserAvatar
-              class="post-avatar"
-              :bot="botIndicator"
-              :compact="compact"
-              :better-shadow="betterShadow"
-              :user="status.user"
-            />
+          <a :href="$router.resolve(userProfileLink).href" @click.prevent>
+            <Popover
+              trigger="click"
+              popover-class="popover-default user-popover"
+              :overlay-centers="true"
+              overlay-centers-selector=".user-info-avatar-link .Avatar"
+            >
+              <template v-slot:trigger>
+                <UserAvatar
+                  class="post-avatar"
+                  :bot="botIndicator"
+                  :compact="compact"
+                  :better-shadow="betterShadow"
+                  :user="status.user"
+                />
+              </template>
+              <template v-slot:content>
+                <UserCard
+                  class="mention-link-popover"
+                  :user-id="status.user.id"
+                  :hide-bio="true"
+                  :bordered="false"
+                  :allow-zooming-avatar="true"
+                  :rounded="true"
+                />
+              </template>
+            </Popover>
           </a>
         </div>
         <div class="right-side">
-- 
cgit v1.2.3-70-g09d2


From 770d12f7adda5659ff01b83ad3e172c27bae818d Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 15 Jun 2022 04:03:18 +0300
Subject: limit width of popover to slightly lesser than screen width

---
 src/components/popover/popover.vue | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 977c3559..5c45be73 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -46,6 +46,7 @@
   z-index: 90000;
   position: fixed;
   min-width: 0;
+  max-width: 90vw;
   box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
   box-shadow: var(--popupShadow);
 }
-- 
cgit v1.2.3-70-g09d2


From 78ced0c901d255bf99e096339da945b1b3cc0216 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 21 Jun 2022 01:05:42 +0300
Subject: proper horizontal limit

---
 src/components/popover/popover.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 5c45be73..0d37328e 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -46,7 +46,7 @@
   z-index: 90000;
   position: fixed;
   min-width: 0;
-  max-width: 90vw;
+  max-width: calc(100vw - 20px);
   box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
   box-shadow: var(--popupShadow);
 }
-- 
cgit v1.2.3-70-g09d2


From 872db65fd86aaa605789383e629321e32447a997 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 22 Jun 2022 00:30:10 +0300
Subject: slight z-index refactor and attempt at organizing it

---
 src/App.scss                                             |  9 ++++++++-
 src/boot/after_store.js                                  |  3 +++
 src/components/desktop_nav/desktop_nav.scss              |  1 +
 src/components/emoji_picker/emoji_picker.scss            |  3 ++-
 src/components/global_notice_list/global_notice_list.vue |  2 +-
 src/components/media_modal/media_modal.vue               |  2 +-
 src/components/mobile_nav/mobile_nav.vue                 |  6 ++++--
 src/components/modal/modal.vue                           |  5 ++++-
 src/components/notifications/notifications.js            | 10 ++++++++++
 src/components/popover/popover.js                        |  4 ++++
 src/components/popover/popover.vue                       |  4 ++--
 src/components/shout_panel/shout_panel.vue               |  2 +-
 src/components/side_drawer/side_drawer.vue               |  2 +-
 13 files changed, 42 insertions(+), 11 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/App.scss b/src/App.scss
index 79c07683..78835c61 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -4,6 +4,13 @@
 :root {
   --navbar-height: 3.5rem;
   --post-line-height: 1.4;
+  // Z-Index stuff
+  --ZI_media_modal: 90000;
+  --ZI_navbar_popovers: 85000;
+  --ZI_navbar: 80000;
+  --ZI_modals_popovers: 75000;
+  --ZI_modals: 70000;
+  --ZI_popovers: 60000;
 }
 
 html {
@@ -117,7 +124,7 @@ i[class*=icon-],
 }
 
 nav {
-  z-index: 1000;
+  z-index: var(--ZI_navbar);
   color: var(--topBarText);
   background-color: $fallback--fg;
   background-color: var(--topBar, $fallback--fg);
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index f655c38f..894a68e1 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -396,6 +396,9 @@ const afterStoreSetup = async ({ store, i18n }) => {
   app.component('FAIcon', FontAwesomeIcon)
   app.component('FALayers', FontAwesomeLayers)
 
+  // remove after vue 3.3
+  app.config.unwrapInjectedRef = true
+
   app.mount('#app')
 
   return app
diff --git a/src/components/desktop_nav/desktop_nav.scss b/src/components/desktop_nav/desktop_nav.scss
index 0ca9802e..e9a47632 100644
--- a/src/components/desktop_nav/desktop_nav.scss
+++ b/src/components/desktop_nav/desktop_nav.scss
@@ -2,6 +2,7 @@
 
 .DesktopNav {
   width: 100%;
+  z-index: var(--ZI_navbar);
 
   a {
     color: var(--topBarLink, $fallback--link);
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
index 2055e02e..a2f17c51 100644
--- a/src/components/emoji_picker/emoji_picker.scss
+++ b/src/components/emoji_picker/emoji_picker.scss
@@ -7,7 +7,8 @@
   right: 0;
   left: 0;
   margin: 0 !important;
-  z-index: 100;
+  // TODO: actually use popover in emoji picker
+  z-index: var(--ZI_popovers);
   background-color: $fallback--bg;
   background-color: var(--popover, $fallback--bg);
   color: $fallback--link;
diff --git a/src/components/global_notice_list/global_notice_list.vue b/src/components/global_notice_list/global_notice_list.vue
index ddc45b81..09904761 100644
--- a/src/components/global_notice_list/global_notice_list.vue
+++ b/src/components/global_notice_list/global_notice_list.vue
@@ -32,7 +32,7 @@
   top: 50px;
   width: 100%;
   pointer-events: none;
-  z-index: 1001;
+  z-index: var(--ZI_popovers);
   display: flex;
   flex-direction: column;
   align-items: center;
diff --git a/src/components/media_modal/media_modal.vue b/src/components/media_modal/media_modal.vue
index b93d3d84..d59055b3 100644
--- a/src/components/media_modal/media_modal.vue
+++ b/src/components/media_modal/media_modal.vue
@@ -121,7 +121,7 @@ $modal-view-button-icon-width: 3em;
 $modal-view-button-icon-margin: 0.5em;
 
 .modal-view.media-modal-view {
-  z-index: 900000;
+  z-index: var(--ZI_media_modal);
   flex-direction: column;
 
   .modal-view-button-arrow,
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index d2d48a03..c58d9e7c 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -86,6 +86,8 @@
 @import '../../_variables.scss';
 
 .MobileNav {
+  z-index: var(--ZI_navbar);
+
   .mobile-nav {
     display: grid;
     line-height: var(--navbar-height);
@@ -147,7 +149,7 @@
     transition-property: transform;
     transition-duration: 0.25s;
     transform: translateX(0);
-    z-index: 1001;
+    z-index: var(--ZI_navbar);
     -webkit-overflow-scrolling: touch;
 
     &.-closed {
@@ -160,7 +162,7 @@
     display: flex;
     align-items: center;
     justify-content: space-between;
-    z-index: 1;
+    z-index: calc(var(--ZI_navbar) + 100);
     width: 100%;
     height: 50px;
     line-height: 50px;
diff --git a/src/components/modal/modal.vue b/src/components/modal/modal.vue
index 9394efff..52d8d27e 100644
--- a/src/components/modal/modal.vue
+++ b/src/components/modal/modal.vue
@@ -22,6 +22,9 @@ export default {
       default: false
     }
   },
+  provide: {
+    popoversZLayer: 'modals'
+  },
   computed: {
     classes () {
       return {
@@ -35,7 +38,7 @@ export default {
 
 <style lang="scss">
 .modal-view {
-  z-index: 2000;
+  z-index: var(--ZI_modals);
   position: fixed;
   top: 0;
   left: 0;
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index fb2579a5..63d827d8 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -1,3 +1,4 @@
+import { computed } from 'vue'
 import { mapGetters } from 'vuex'
 import Notification from '../notification/notification.vue'
 import NotificationFilters from './notification_filters.vue'
@@ -38,6 +39,11 @@ const Notifications = {
       seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT
     }
   },
+  provide () {
+    return {
+      popoversZLayer: computed(() => this.popoversZLayer)
+    }
+  },
   computed: {
     mainClass () {
       return this.minimalMode ? '' : 'panel panel-default'
@@ -75,6 +81,10 @@ const Notifications = {
       }
       return map[layoutType] || '#notifs-sidebar'
     },
+    popoversZLayer () {
+      const { layoutType } = this.$store.state.interface
+      return layoutType === 'mobile' ? 'navbar' : null
+    },
     notificationsToDisplay () {
       return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount)
     },
diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index cff9b174..5dfcf810 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -42,6 +42,7 @@ const Popover = {
     // What selector (witin popover!) to use for determining center of popover
     overlayCentersSelector: String
   },
+  inject: ['popoversZLayer'], // override popover z layer
   data () {
     return {
       hidden: true,
@@ -168,6 +169,9 @@ const Popover = {
         top: `${Math.round(translateY)}px`
       }
 
+      if (this.popoversZLayer) {
+        this.styles['--ZI_popover_override'] = `var(--ZI_${this.popoversZLayer}_popovers)`
+      }
       if (parentScreenBox) {
         this.styles.maxWidth = `${Math.round(parentScreenBox.width)}px`
       }
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 0d37328e..f854515c 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -43,7 +43,7 @@
 }
 
 .popover {
-  z-index: 90000;
+  z-index: var(--ZI_popover_override, var(--ZI_popovers));
   position: fixed;
   min-width: 0;
   max-width: calc(100vw - 20px);
@@ -87,7 +87,7 @@
   text-align: left;
   list-style: none;
   max-width: 100vw;
-  z-index: 200;
+  z-index: var(--ZI_popover_override, var(--ZI_popovers));
   white-space: nowrap;
 
   .dropdown-divider {
diff --git a/src/components/shout_panel/shout_panel.vue b/src/components/shout_panel/shout_panel.vue
index 1eca88a7..688c2d61 100644
--- a/src/components/shout_panel/shout_panel.vue
+++ b/src/components/shout_panel/shout_panel.vue
@@ -80,7 +80,7 @@
 .floating-shout {
   position: fixed;
   bottom: 0.5em;
-  z-index: 1000;
+  z-index: var(--ZI_popovers);
   max-width: 25em;
 
   &.-left {
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index dd88de7d..aefd3915 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -211,7 +211,7 @@
 
 .side-drawer-container {
   position: fixed;
-  z-index: 1000;
+  z-index: var(--ZI_navbar);
   top: 0;
   left: 0;
   width: 100%;
-- 
cgit v1.2.3-70-g09d2


From d5bc825616858f8eccb4fb9786f0178bce44e979 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 31 Jul 2022 00:05:26 +0300
Subject: add stay-on-click prop to solve case of clicking user avatar in
 status popover

---
 src/components/popover/popover.js                | 18 ++++++++++++++----
 src/components/popover/popover.vue               | 21 +++++++++++++++++++++
 src/components/status_popover/status_popover.vue |  1 +
 3 files changed, 36 insertions(+), 4 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index c19e6904..843b22f3 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -40,7 +40,10 @@ const Popover = {
     overlayCenters: Boolean,
 
     // What selector (witin popover!) to use for determining center of popover
-    overlayCentersSelector: String
+    overlayCentersSelector: String,
+
+    // Lets hover popover stay when clicking inside of it
+    stayOnClick: Boolean
   },
   inject: ['popoversZLayer'], // override popover z layer
   data () {
@@ -50,6 +53,7 @@ const Popover = {
       // with popovers refusing to be hidden when user wants to interact with something in below popover
       lockReEntry: false,
       hidden: true,
+      pinned: false,
       styles: {},
       oldSize: { width: 0, height: 0 },
       scrollable: null,
@@ -196,9 +200,10 @@ const Popover = {
     },
     showPopover () {
       if (this.disabled) return
+      this.pinned = false
       const wasHidden = this.hidden
       this.hidden = false
-      if (this.trigger === 'click') {
+      if (this.trigger === 'click' || this.stayOnClick) {
         document.addEventListener('click', this.onClickOutside)
       }
       this.scrollable.addEventListener('scroll', this.onScroll)
@@ -227,7 +232,7 @@ const Popover = {
       }
     },
     onMouseleave (e) {
-      if (this.trigger === 'hover') {
+      if (this.trigger === 'hover' && !this.pinned) {
         this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
       }
     },
@@ -240,7 +245,7 @@ const Popover = {
       }
     },
     onMouseleaveContent (e) {
-      if (this.trigger === 'hover') {
+      if (this.trigger === 'hover' && !this.pinned) {
         this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
       }
     },
@@ -259,6 +264,11 @@ const Popover = {
       if (this.$el.contains(e.target)) return
       this.hidePopover()
     },
+    onClickContent (e) {
+      if (this.trigger === 'hover' && this.stayOnClick) {
+        this.pinned = true
+      }
+    },
     onScroll (e) {
       this.updateStyles()
     },
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index f854515c..9b67f400 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -21,12 +21,22 @@
           :class="popoverClass || 'popover-default'"
           @mouseenter="onMouseenterContent"
           @mouseleave="onMouseleaveContent"
+          @click="onClickContent"
         >
           <slot
             name="content"
             class="popover-inner"
             :close="hidePopover"
           />
+          <div
+            v-if="stayOnClick && pinned"
+            class="pinned-tooltip-icon popover popover-default"
+          >
+            <FAIcon
+              icon="thumbtack"
+              class="faint"
+            />
+          </div>
         </div>
       </transition>
     </teleport>
@@ -51,6 +61,17 @@
   box-shadow: var(--popupShadow);
 }
 
+.pinned-tooltip-icon {
+  position: absolute;
+  top: -1em;
+  left: -1em;
+  width: 2em;
+  height: 2em;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
 .popover-default {
   &:after {
     content: '';
diff --git a/src/components/status_popover/status_popover.vue b/src/components/status_popover/status_popover.vue
index 2c436d04..9cabb751 100644
--- a/src/components/status_popover/status_popover.vue
+++ b/src/components/status_popover/status_popover.vue
@@ -1,6 +1,7 @@
 <template>
   <Popover
     trigger="hover"
+    :stay-on-click="true"
     popover-class="popover-default status-popover"
     :bound-to="{ x: 'container' }"
     @show="enter"
-- 
cgit v1.2.3-70-g09d2


From 8ab30545b2b792ddae9cc439c3e617195e22d3ca Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 31 Jul 2022 01:45:38 +0300
Subject: pinned no longer needed

---
 src/components/popover/popover.js  | 11 ++---------
 src/components/popover/popover.vue | 20 --------------------
 2 files changed, 2 insertions(+), 29 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index e477051f..f23df826 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -53,7 +53,6 @@ const Popover = {
       // with popovers refusing to be hidden when user wants to interact with something in below popover
       lockReEntry: false,
       hidden: true,
-      pinned: false,
       styles: {},
       oldSize: { width: 0, height: 0 },
       scrollable: null,
@@ -202,7 +201,6 @@ const Popover = {
     },
     showPopover () {
       if (this.disabled) return
-      this.pinned = false
       const wasHidden = this.hidden
       this.hidden = false
       this.parentPopover && this.parentPopover.onChildPopoverState(this, true)
@@ -236,7 +234,7 @@ const Popover = {
       }
     },
     onMouseleave (e) {
-      if (this.trigger === 'hover' && !this.pinned && this.childrenShown.size > 0) {
+      if (this.trigger === 'hover' && this.childrenShown.size > 0) {
         this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
       }
     },
@@ -249,7 +247,7 @@ const Popover = {
       }
     },
     onMouseleaveContent (e) {
-      if (this.trigger === 'hover' && !this.pinned && this.childrenShown.size > 0) {
+      if (this.trigger === 'hover' && this.childrenShown.size === 0) {
         this.graceTimeout = setTimeout(() => this.hidePopover(), 1)
       }
     },
@@ -270,11 +268,6 @@ const Popover = {
       this.hidePopover()
       if (this.parentPopover) this.parentPopover.onClickOutside(e)
     },
-    onClickContent (e) {
-      if (this.trigger === 'hover' && this.stayOnClick) {
-        this.pinned = true
-      }
-    },
     onScroll (e) {
       this.updateStyles()
     },
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 9b67f400..bd59cade 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -28,15 +28,6 @@
             class="popover-inner"
             :close="hidePopover"
           />
-          <div
-            v-if="stayOnClick && pinned"
-            class="pinned-tooltip-icon popover popover-default"
-          >
-            <FAIcon
-              icon="thumbtack"
-              class="faint"
-            />
-          </div>
         </div>
       </transition>
     </teleport>
@@ -61,17 +52,6 @@
   box-shadow: var(--popupShadow);
 }
 
-.pinned-tooltip-icon {
-  position: absolute;
-  top: -1em;
-  left: -1em;
-  width: 2em;
-  height: 2em;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-}
-
 .popover-default {
   &:after {
     content: '';
-- 
cgit v1.2.3-70-g09d2


From 63f35509a79b8e9bc8bc301852847cf952a6a01f Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 23 Aug 2022 13:26:05 +0300
Subject: improve submenu and improve icon buttons hover effects

---
 src/App.scss                                     | 10 ++++++++++
 src/components/popover/popover.vue               |  7 +++++++
 src/components/user_list_menu/user_list_menu.vue |  5 +++--
 src/panel.scss                                   |  9 +++++++++
 4 files changed, 29 insertions(+), 2 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/App.scss b/src/App.scss
index 1f7a2b28..665d52ff 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -130,6 +130,16 @@ i[class*=icon-],
   color: var(--icon, $fallback--icon);
 }
 
+.button-unstyled:hover,
+a:hover {
+  i[class*=icon-],
+  .svg-inline--fa,
+  .iconLetter {
+    color: $fallback--text;
+    color: var(--text, $fallback--text);
+  }
+}
+
 nav {
   z-index: var(--ZI_navbar);
   color: var(--topBarText);
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index bd59cade..623af8d2 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -126,6 +126,13 @@
       }
     }
 
+    &.-has-submenu {
+      .chevron-icon {
+        margin-right: 0.25rem;
+        margin-left: 2rem;
+      }
+    }
+
     &:active, &:hover {
       background-color: $fallback--lightBg;
       background-color: var(--selectedMenuPopover, $fallback--lightBg);
diff --git a/src/components/user_list_menu/user_list_menu.vue b/src/components/user_list_menu/user_list_menu.vue
index d8da16ea..06947ab7 100644
--- a/src/components/user_list_menu/user_list_menu.vue
+++ b/src/components/user_list_menu/user_list_menu.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="UserListMenu">
     <Popover
-      trigger="click"
+      trigger="hover"
       placement="left"
       remove-padding
     >
@@ -22,9 +22,10 @@
         </div>
       </template>
       <template #trigger>
-        <button class="btn button-default dropdown-item">
+        <button class="btn button-default dropdown-item -has-submenu">
           {{ $t('lists.manage_lists') }}
           <FAIcon
+            class="chevron-icon"
             size="lg"
             icon="chevron-right"
           />
diff --git a/src/panel.scss b/src/panel.scss
index 1022758a..2e769e27 100644
--- a/src/panel.scss
+++ b/src/panel.scss
@@ -147,6 +147,15 @@
     color: var(--panelLink, $fallback--link);
   }
 
+  .button-unstyled:hover,
+  a:hover {
+    i[class*=icon-],
+    .svg-inline--fa,
+    .iconLetter {
+      color: var(--panelText);
+    }
+  }
+
   .faint {
     background-color: transparent;
     color: $fallback--faint;
-- 
cgit v1.2.3-70-g09d2


From 4631b1b9f7e7813cab65e0d0705cd1e265f23393 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 9 Oct 2022 22:09:50 +0300
Subject: suggestor popover

---
 src/components/emoji_input/emoji_input.js  |  80 +++++++++++-------
 src/components/emoji_input/emoji_input.vue | 128 +++++++++++++++--------------
 src/components/popover/popover.js          |  11 ++-
 src/components/popover/popover.vue         |   2 +-
 4 files changed, 127 insertions(+), 94 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/emoji_input/emoji_input.js b/src/components/emoji_input/emoji_input.js
index ffc0ffac..b365043c 100644
--- a/src/components/emoji_input/emoji_input.js
+++ b/src/components/emoji_input/emoji_input.js
@@ -1,5 +1,6 @@
 import Completion from '../../services/completion/completion.js'
 import EmojiPicker from '../emoji_picker/emoji_picker.vue'
+import Popover from 'src/components/popover/popover.vue'
 import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
 import { take } from 'lodash'
 import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
@@ -109,6 +110,7 @@ const EmojiInput = {
   data () {
     return {
       input: undefined,
+      caretEl: undefined,
       highlighted: 0,
       caret: 0,
       focused: false,
@@ -117,10 +119,12 @@ const EmojiInput = {
       temporarilyHideSuggestions: false,
       keepOpen: false,
       disableClickOutside: false,
-      suggestions: []
+      suggestions: [],
+      overlayStyle: {}
     }
   },
   components: {
+    Popover,
     EmojiPicker,
     UnicodeDomainIndicator
   },
@@ -128,7 +132,15 @@ const EmojiInput = {
     padEmoji () {
       return this.$store.getters.mergedConfig.padEmoji
     },
+    preText () {
+      return this.modelValue.slice(0, this.caret)
+    },
+    postText () {
+      return this.modelValue.slice(this.caret)
+    },
     showSuggestions () {
+      console.log(this.focused)
+      console.log(this.suggestions)
       return this.focused &&
         this.suggestions &&
         this.suggestions.length > 0 &&
@@ -191,10 +203,21 @@ const EmojiInput = {
     }
   },
   mounted () {
-    const { root } = this.$refs
+    const { root, hiddenOverlayCaret, suggestorPopover } = this.$refs
     const input = root.querySelector('.emoji-input > input') || root.querySelector('.emoji-input > textarea')
     if (!input) return
     this.input = input
+    this.caretEl = hiddenOverlayCaret
+    suggestorPopover.setAnchorEl(this.caretEl)
+    const style = getComputedStyle(this.input)
+    this.overlayStyle.padding = style.padding
+    this.overlayStyle.border = style.border
+    this.overlayStyle.margin = style.margin
+    this.overlayStyle.lineHeight = style.lineHeight
+    this.overlayStyle.fontFamily = style.fontFamily
+    this.overlayStyle.fontSize = style.fontSize
+    this.overlayStyle.wordWrap = style.wordWrap
+    this.overlayStyle.whiteSpace = style.whiteSpace
     this.resize()
     input.addEventListener('blur', this.onBlur)
     input.addEventListener('focus', this.onFocus)
@@ -204,6 +227,16 @@ const EmojiInput = {
     input.addEventListener('click', this.onClickInput)
     input.addEventListener('transitionend', this.onTransition)
     input.addEventListener('input', this.onInput)
+    input.addEventListener('scroll', (e) => {
+      console.log({
+        top: this.input.scrollTop,
+        left: this.input.scrollLeft
+      })
+      this.$refs.hiddenOverlay.scrollTo({
+        top: this.input.scrollTop,
+        left: this.input.scrollLeft
+      })
+    })
   },
   unmounted () {
     const { input } = this
@@ -219,22 +252,32 @@ const EmojiInput = {
     }
   },
   watch: {
-    showSuggestions: function (newValue) {
+    showSuggestions: function (newValue, oldValue) {
       this.$emit('shown', newValue)
+      if (newValue) {
+        this.$refs.suggestorPopover.showPopover()
+      } else {
+        this.$refs.suggestorPopover.hidePopover()
+      }
     },
     textAtCaret: async function (newWord) {
       const firstchar = newWord.charAt(0)
-      this.suggestions = []
-      if (newWord === firstchar) return
+      if (newWord === firstchar) {
+        this.suggestions = []
+        return
+      }
       const matchedSuggestions = await this.suggest(newWord, this.maybeLocalizedEmojiNamesAndKeywords)
       // Async: cancel if textAtCaret has changed during wait
-      if (this.textAtCaret !== newWord) return
-      if (matchedSuggestions.length <= 0) return
+      if (this.textAtCaret !== newWord || matchedSuggestions.length <= 0) {
+        this.suggestions = []
+        return
+      }
       this.suggestions = take(matchedSuggestions, 5)
         .map(({ imageUrl, ...rest }) => ({
           ...rest,
           img: imageUrl || ''
         }))
+      this.$refs.suggestorPopover.updateStyles()
     },
     suggestions: {
       handler (newValue) {
@@ -525,29 +568,6 @@ const EmojiInput = {
       this.caret = selectionStart
     },
     resize () {
-      const panel = this.$refs.panel
-      if (!panel) return
-      const picker = this.$refs.picker.$el
-      const panelBody = this.$refs['panel-body']
-      const { offsetHeight, offsetTop } = this.input
-      const offsetBottom = offsetTop + offsetHeight
-
-      this.setPlacement(panelBody, panel, offsetBottom)
-      this.setPlacement(picker, picker, offsetBottom)
-    },
-    setPlacement (container, target, offsetBottom) {
-      if (!container || !target) return
-
-      target.style.top = offsetBottom + 'px'
-      target.style.bottom = 'auto'
-
-      if (this.placement === 'top' || (this.placement === 'auto' && this.overflowsBottom(container))) {
-        target.style.top = 'auto'
-        target.style.bottom = this.input.offsetHeight + 'px'
-      }
-    },
-    overflowsBottom (el) {
-      return el.getBoundingClientRect().bottom > window.innerHeight
     }
   }
 }
diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index 43581dbf..8a4bc244 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -6,6 +6,12 @@
     :class="{ 'with-picker': !hideEmojiButton }"
   >
     <slot />
+    <!-- TODO: make the 'x' disappear if at the end maybe? -->
+    <div class="hidden-overlay" :style="overlayStyle" ref="hiddenOverlay">
+      <span>{{ preText }}</span>
+      <span class="caret" ref="hiddenOverlayCaret">x</span>
+      <span>{{ postText }}</span>
+    </div>
     <template v-if="enableEmojiPicker">
       <button
         v-if="!hideEmojiButton"
@@ -27,50 +33,52 @@
         @sticker-upload-failed="onStickerUploadFailed"
       />
     </template>
-    <div
-      ref="panel"
+    <Popover
       class="autocomplete-panel"
-      :class="{ hide: !showSuggestions }"
+      placement="bottom"
+      ref="suggestorPopover"
     >
-      <div
-        ref="panel-body"
-        class="autocomplete-panel-body"
-      >
+      <template #content>
         <div
-          v-for="(suggestion, index) in suggestions"
-          :key="index"
-          class="autocomplete-item"
-          :class="{ highlighted: index === highlighted }"
-          @click.stop.prevent="onClick($event, suggestion)"
+          ref="panel-body"
+          class="autocomplete-panel-body"
         >
-          <span class="image">
-            <img
-              v-if="suggestion.img"
-              :src="suggestion.img"
-            >
-            <span v-else>{{ suggestion.replacement }}</span>
-          </span>
-          <div class="label">
-            <span
-              v-if="suggestion.user"
-              class="displayText"
-            >
-              {{ suggestion.displayText }}<UnicodeDomainIndicator
-                :user="suggestion.user"
-                :at="false"
-              />
+          <div
+            v-for="(suggestion, index) in suggestions"
+            :key="index"
+            class="autocomplete-item"
+            :class="{ highlighted: index === highlighted }"
+            @click.stop.prevent="onClick($event, suggestion)"
+          >
+            <span class="image">
+              <img
+                v-if="suggestion.img"
+                :src="suggestion.img"
+              >
+              <span v-else>{{ suggestion.replacement }}</span>
             </span>
-            <span
-              v-if="!suggestion.user"
-              class="displayText"
-            >
-              {{ maybeLocalizedEmojiName(suggestion) }}
-            </span>
-            <span class="detailText">{{ suggestion.detailText }}</span>
+            <div class="label">
+              <span
+                v-if="suggestion.user"
+                class="displayText"
+              >
+                {{ suggestion.displayText }}<UnicodeDomainIndicator
+                  :user="suggestion.user"
+                  :at="false"
+                />
+              </span>
+              <span
+                v-if="!suggestion.user"
+                class="displayText"
+              >
+                {{ maybeLocalizedEmojiName(suggestion) }}
+              </span>
+              <span class="detailText">{{ suggestion.detailText }}</span>
+            </div>
           </div>
         </div>
-      </div>
-    </div>
+      </template>
+    </Popover>
   </div>
 </template>
 
@@ -102,6 +110,7 @@
       color: var(--text, $fallback--text);
     }
   }
+
   .emoji-picker-panel {
     position: absolute;
     z-index: 20;
@@ -115,31 +124,6 @@
   .autocomplete {
     &-panel {
       position: absolute;
-      z-index: 20;
-      margin-top: 2px;
-
-      &.hide {
-        display: none
-      }
-
-      &-body {
-        margin: 0 0.5em 0 0.5em;
-        border-radius: $fallback--tooltipRadius;
-        border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
-        box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
-        box-shadow: var(--popupShadow);
-        min-width: 75%;
-        background-color: $fallback--bg;
-        background-color: var(--popover, $fallback--bg);
-        color: $fallback--link;
-        color: var(--popoverText, $fallback--link);
-        --faint: var(--popoverFaintText, $fallback--faint);
-        --faintLink: var(--popoverFaintLink, $fallback--faint);
-        --lightText: var(--popoverLightText, $fallback--lightText);
-        --postLink: var(--popoverPostLink, $fallback--link);
-        --postFaintLink: var(--popoverPostFaintLink, $fallback--link);
-        --icon: var(--popoverIcon, $fallback--icon);
-      }
     }
 
     &-item {
@@ -196,5 +180,25 @@
   input, textarea {
     flex: 1 0 auto;
   }
+
+  .hidden-overlay {
+    opacity: 0;
+    pointer-events: none;
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    right: 0;
+    left: 0;
+    overflow: hidden;
+    /* DEBUG STUFF */
+    color: red;
+    /* set opacity to non-zero to see the overlay */
+
+    .caret {
+      width: 0;
+      margin-right: calc(-1ch - 1px);
+      border: 1px solid red;
+    }
+  }
 }
 </style>
diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index dd332c35..60c42f0f 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -51,6 +51,10 @@ const Popover = {
       // lockReEntry is a flag that is set when mouse cursor is leaving the popover's content
       // so that if mouse goes back into popover it won't be re-shown again to prevent annoyance
       // with popovers refusing to be hidden when user wants to interact with something in below popover
+      anchorEl: null,
+      // There's an issue where having teleport enabled by default causes things just...
+      // not render at all, i.e. main post status form and its emoji inputs
+      teleport: false,
       lockReEntry: false,
       hidden: true,
       styles: {},
@@ -63,6 +67,10 @@ const Popover = {
     }
   },
   methods: {
+    setAnchorEl (el) {
+      this.anchorEl = el
+      this.updateStyles()
+    },
     containerBoundingClientRect () {
       const container = this.boundToSelector ? this.$el.closest(this.boundToSelector) : this.$el.offsetParent
       return container.getBoundingClientRect()
@@ -75,7 +83,7 @@ const Popover = {
 
       // Popover will be anchored around this element, trigger ref is the container, so
       // its children are what are inside the slot. Expect only one v-slot:trigger.
-      const anchorEl = (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el
+      const anchorEl = this.anchorEl || (this.$refs.trigger && this.$refs.trigger.children[0]) || this.$el
       // SVGs don't have offsetWidth/Height, use fallback
       const anchorHeight = anchorEl.offsetHeight || anchorEl.clientHeight
       const anchorWidth = anchorEl.offsetWidth || anchorEl.clientWidth
@@ -319,6 +327,7 @@ const Popover = {
     }
   },
   mounted () {
+    this.teleport = true
     let scrollable = this.$refs.trigger.closest('.column.-scrollable') ||
         this.$refs.trigger.closest('.mobile-notifications')
     if (!scrollable) scrollable = window
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 623af8d2..217eba7c 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -11,7 +11,7 @@
     >
       <slot name="trigger" />
     </button>
-    <teleport to="#popovers">
+    <teleport :disabled="!teleport" to="#popovers">
       <transition name="fade">
         <div
           v-if="!hidden"
-- 
cgit v1.2.3-70-g09d2


From f715de43f2bae1593128f34f7362c1963a54e3a1 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Mon, 7 Nov 2022 13:22:40 -0500
Subject: Add labels for timeline header

---
 src/components/popover/popover.js                              | 7 ++++++-
 src/components/popover/popover.vue                             | 1 +
 src/components/quick_filter_settings/quick_filter_settings.vue | 5 ++---
 src/components/quick_view_settings/quick_view_settings.vue     | 5 ++---
 src/components/timeline/timeline.vue                           | 1 +
 src/i18n/en.json                                               | 4 +++-
 6 files changed, 15 insertions(+), 8 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/popover/popover.js b/src/components/popover/popover.js
index dd332c35..72b7c511 100644
--- a/src/components/popover/popover.js
+++ b/src/components/popover/popover.js
@@ -43,7 +43,12 @@ const Popover = {
     overlayCentersSelector: String,
 
     // Lets hover popover stay when clicking inside of it
-    stayOnClick: Boolean
+    stayOnClick: Boolean,
+
+    triggerAttrs: {
+      type: Object,
+      default: {}
+    }
   },
   inject: ['popoversZLayer'], // override popover z layer
   data () {
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 623af8d2..9506728e 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -7,6 +7,7 @@
       ref="trigger"
       class="button-unstyled popover-trigger-button"
       type="button"
+      v-bind="triggerAttrs"
       @click="onClick"
     >
       <slot name="trigger" />
diff --git a/src/components/quick_filter_settings/quick_filter_settings.vue b/src/components/quick_filter_settings/quick_filter_settings.vue
index 54ea037e..87fcd716 100644
--- a/src/components/quick_filter_settings/quick_filter_settings.vue
+++ b/src/components/quick_filter_settings/quick_filter_settings.vue
@@ -3,6 +3,7 @@
     trigger="click"
     class="QuickFilterSettings"
     :bound-to="{ x: 'container' }"
+    :triggerAttrs="{ title: $t('timeline.quick_filter_settings') }"
   >
     <template #content>
       <div class="dropdown-menu">
@@ -79,9 +80,7 @@
       </div>
     </template>
     <template #trigger>
-      <button class="button-unstyled">
-        <FAIcon icon="filter" />
-      </button>
+      <FAIcon icon="filter" />
     </template>
   </Popover>
 </template>
diff --git a/src/components/quick_view_settings/quick_view_settings.vue b/src/components/quick_view_settings/quick_view_settings.vue
index b0413cac..d7c9bf3b 100644
--- a/src/components/quick_view_settings/quick_view_settings.vue
+++ b/src/components/quick_view_settings/quick_view_settings.vue
@@ -3,6 +3,7 @@
     trigger="click"
     class="QuickViewSettings"
     :bound-to="{ x: 'container' }"
+    :triggerAttrs="{ title: $t('timeline.quick_view_settings') }"
   >
     <template #content>
       <div class="dropdown-menu">
@@ -66,9 +67,7 @@
       </div>
     </template>
     <template #trigger>
-      <button class="button-unstyled">
-        <FAIcon icon="bars" />
-      </button>
+      <FAIcon icon="bars" />
     </template>
   </Popover>
 </template>
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index 8a036fd0..15cf043e 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -47,6 +47,7 @@
           v-else-if="!embedded"
           class="loadmore-text faint veryfaint rightside-icon"
           :title="$t('timeline.up_to_date')"
+          :aria-disabled="true"
           @click.prevent
         >
           <FAIcon
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 246e22cf..f16f6380 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -807,7 +807,9 @@
     "no_more_statuses": "No more statuses",
     "no_statuses": "No statuses",
     "socket_reconnected": "Realtime connection established",
-    "socket_broke": "Realtime connection lost: CloseEvent code {0}"
+    "socket_broke": "Realtime connection lost: CloseEvent code {0}",
+    "quick_view_settings": "Quick view settings",
+    "quick_filter_settings": "Quick filter settings"
   },
   "status": {
     "favorites": "Favorites",
-- 
cgit v1.2.3-70-g09d2


From 3c0e7882b10989424c3ec98413b555373efa1719 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 21 Nov 2022 22:17:33 +0200
Subject: lint

---
 src/components/emoji_input/emoji_input.vue                 | 13 ++++++++++---
 src/components/emoji_picker/emoji_picker.vue               |  4 ++--
 src/components/mobile_nav/mobile_nav.vue                   |  6 +++---
 src/components/notifications/notifications.vue             |  2 +-
 src/components/popover/popover.vue                         |  5 ++++-
 .../quick_filter_settings/quick_filter_settings.vue        |  2 +-
 src/components/quick_view_settings/quick_view_settings.vue |  2 +-
 src/components/search/search.js                            |  4 ++--
 src/components/timeline/timeline.vue                       | 14 ++++++++++----
 9 files changed, 34 insertions(+), 18 deletions(-)

(limited to 'src/components/popover/popover.vue')

diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index 63bf856e..c9bbc18f 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -6,9 +6,16 @@
   >
     <slot />
     <!-- TODO: make the 'x' disappear if at the end maybe? -->
-    <div class="hidden-overlay" :style="overlayStyle" ref="hiddenOverlay">
+    <div
+      ref="hiddenOverlay"
+      class="hidden-overlay"
+      :style="overlayStyle"
+    >
       <span>{{ preText }}</span>
-      <span class="caret" ref="hiddenOverlayCaret">x</span>
+      <span
+        ref="hiddenOverlayCaret"
+        class="caret"
+      >x</span>
       <span>{{ postText }}</span>
     </div>
     <template v-if="enableEmojiPicker">
@@ -33,9 +40,9 @@
       />
     </template>
     <Popover
+      ref="suggestorPopover"
       class="autocomplete-panel"
       placement="bottom"
-      ref="suggestorPopover"
     >
       <template #content>
         <div
diff --git a/src/components/emoji_picker/emoji_picker.vue b/src/components/emoji_picker/emoji_picker.vue
index a2c99c16..ff56d637 100644
--- a/src/components/emoji_picker/emoji_picker.vue
+++ b/src/components/emoji_picker/emoji_picker.vue
@@ -1,8 +1,8 @@
 <template>
   <Popover
+    ref="popover"
     trigger="click"
     popover-class="emoji-picker popover-default"
-    ref="popover"
     @show="onPopoverShown"
     @close="onPopoverClosed"
   >
@@ -66,12 +66,12 @@
         >
           <div class="emoji-search">
             <input
+              ref="search"
               v-model="keyword"
               type="text"
               class="form-control"
               :placeholder="$t('emoji.search_emoji')"
               @input="$event.target.composing = false"
-              ref="search"
             >
           </div>
           <div
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index 6e732d1f..d642008b 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -11,7 +11,7 @@
         <button
           class="button-unstyled mobile-nav-button"
           :title="$t('nav.mobile_sidebar')"
-          :aria-expanaded="this.$refs.sideDrawer && !this.$refs.sideDrawer.closed"
+          :aria-expanaded="$refs.sideDrawer && !$refs.sideDrawer.closed"
           @click.stop.prevent="toggleMobileSidebar()"
         >
           <FAIcon
@@ -51,7 +51,7 @@
     >
       <div class="mobile-notifications-header">
         <span class="title">{{ $t('notifications.notifications') }}</span>
-        <span class="spacer"/>
+        <span class="spacer" />
         <button
           v-if="notificationsAtTop"
           class="button-unstyled mobile-nav-button"
@@ -79,8 +79,8 @@
       </div>
       <div
         id="mobile-notifications"
-        class="mobile-notifications"
         ref="mobileNotifications"
+        class="mobile-notifications"
         @scroll="onScroll"
       />
     </aside>
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 3d5878d4..633efca6 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -22,8 +22,8 @@
             >{{ unseenCount }}</span>
           </div>
           <div
-            class="rightside-button"
             v-if="showScrollTop"
+            class="rightside-button"
           >
             <button
               class="button-unstyled scroll-to-top-button"
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index c2cf2327..2869d736 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -12,7 +12,10 @@
     >
       <slot name="trigger" />
     </button>
-    <teleport :disabled="!teleport" to="#popovers">
+    <teleport
+      :disabled="!teleport"
+      to="#popovers"
+    >
       <transition name="fade">
         <div
           v-if="!hidden"
diff --git a/src/components/quick_filter_settings/quick_filter_settings.vue b/src/components/quick_filter_settings/quick_filter_settings.vue
index 87fcd716..f2aa61ee 100644
--- a/src/components/quick_filter_settings/quick_filter_settings.vue
+++ b/src/components/quick_filter_settings/quick_filter_settings.vue
@@ -3,7 +3,7 @@
     trigger="click"
     class="QuickFilterSettings"
     :bound-to="{ x: 'container' }"
-    :triggerAttrs="{ title: $t('timeline.quick_filter_settings') }"
+    :trigger-attrs="{ title: $t('timeline.quick_filter_settings') }"
   >
     <template #content>
       <div class="dropdown-menu">
diff --git a/src/components/quick_view_settings/quick_view_settings.vue b/src/components/quick_view_settings/quick_view_settings.vue
index d7c9bf3b..4bd81c5b 100644
--- a/src/components/quick_view_settings/quick_view_settings.vue
+++ b/src/components/quick_view_settings/quick_view_settings.vue
@@ -3,7 +3,7 @@
     trigger="click"
     class="QuickViewSettings"
     :bound-to="{ x: 'container' }"
-    :triggerAttrs="{ title: $t('timeline.quick_view_settings') }"
+    :trigger-attrs="{ title: $t('timeline.quick_view_settings') }"
   >
     <template #content>
       <div class="dropdown-menu">
diff --git a/src/components/search/search.js b/src/components/search/search.js
index 8d4212cd..877d6f30 100644
--- a/src/components/search/search.js
+++ b/src/components/search/search.js
@@ -83,11 +83,11 @@ const Search = {
         this.lastStatusFetchCount = 0
       }
 
-      this.$store.dispatch('search', { q: query, resolve: true, offset: this.statusesOffset, 'type': searchType })
+      this.$store.dispatch('search', { q: query, resolve: true, offset: this.statusesOffset, type: searchType })
         .then(data => {
           this.loading = false
 
-          let oldLength = this.statuses.length
+          const oldLength = this.statuses.length
 
           // Always append to old results. If new results are empty, this doesn't change anything
           this.userIds = this.userIds.concat(map(data.accounts, 'id'))
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index 877a0cc0..2279f21a 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -6,8 +6,8 @@
         :timeline-name="timelineName"
       />
       <div
-        class="rightside-button"
         v-if="showScrollTop && !embedded"
+        class="rightside-button"
       >
         <button
           class="button-unstyled scroll-to-top-button"
@@ -26,8 +26,8 @@
       </div>
       <template v-if="mobileLayout && !embedded">
         <div
-          class="rightside-button"
           v-if="showLoadButton"
+          class="rightside-button"
         >
           <button
             class="button-unstyled loadmore-button"
@@ -72,8 +72,14 @@
           {{ $t('timeline.up_to_date') }}
         </div>
       </template>
-      <QuickFilterSettings v-if="!embedded" class="rightside-button"/>
-      <QuickViewSettings v-if="!embedded" class="rightside-button"/>
+      <QuickFilterSettings
+        v-if="!embedded"
+        class="rightside-button"
+      />
+      <QuickViewSettings
+        v-if="!embedded"
+        class="rightside-button"
+      />
     </div>
     <div :class="classes.body">
       <div
-- 
cgit v1.2.3-70-g09d2

