From 1d3b1ac934e5dacb05d227ddc1ab0cbd8e16e169 Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Sat, 2 Mar 2019 16:57:32 +0200
Subject: start working on one tap notifications

---
 src/App.vue | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

(limited to 'src/App.vue')

diff --git a/src/App.vue b/src/App.vue
index acbbeb75..aad84804 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -10,7 +10,6 @@
         <div class='item'>
           <a href="#" class="menu-button" @click.stop.prevent="toggleMobileSidebar()">
             <i class="button-icon icon-menu"></i>
-            <div class="alert-dot" v-if="unseenNotificationsCount"></div>
           </a>
           <router-link class="site-name" :to="{ name: 'root' }" active-class="home">{{sitename}}</router-link>
         </div>
@@ -18,11 +17,18 @@
           <user-finder class="button-icon nav-icon mobile-hidden" @toggled="onFinderToggled"></user-finder>
           <router-link class="mobile-hidden" :to="{ name: 'settings'}"><i class="button-icon icon-cog nav-icon" :title="$t('nav.preferences')"></i></router-link>
           <a href="#" class="mobile-hidden" v-if="currentUser" @click.prevent="logout"><i class="button-icon icon-logout nav-icon" :title="$t('login.logout')"></i></a>
+          <a href="#" class="menu-button" @click.stop.prevent="toggleMobileNotifications()">
+            <i class="button-icon icon-bell-alt"></i>
+            <div class="alert-dot" v-if="unseenNotificationsCount"></div>
+          </a>
         </div>
       </div>
     </nav>
     <div v-if="" class="container" id="content">
       <side-drawer ref="sideDrawer" :logout="logout"></side-drawer>
+      <div class="mobile-notifications" :class="{ 'closed': !notificationsOpen }">
+        <notifications/>
+      </div>
       <div class="sidebar-flexer mobile-hidden">
         <div class="sidebar-bounds">
           <div class="sidebar-scroller">
-- 
cgit v1.2.3-70-g09d2


From c7e180080afd0e255e439030df800f79d33ff5de Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Sun, 3 Mar 2019 16:33:40 +0200
Subject: more work with notifications drawer

---
 src/App.js               | 14 +++++++++++++-
 src/App.scss             |  2 +-
 src/App.vue              | 10 ++++++----
 src/boot/after_store.js  |  3 +++
 src/modules/interface.js | 10 +++++++++-
 5 files changed, 32 insertions(+), 7 deletions(-)

(limited to 'src/App.vue')

diff --git a/src/App.js b/src/App.js
index 5e5b6eea..b6234a08 100644
--- a/src/App.js
+++ b/src/App.js
@@ -39,6 +39,10 @@ export default {
   created () {
     // Load the locale from the storage
     this.$i18n.locale = this.$store.state.config.interfaceLanguage
+    window.addEventListener('resize', this.updateMobileState)
+  },
+  destroyed () {
+    window.removeEventListener('resize', this.updateMobileState)
   },
   computed: {
     currentUser () { return this.$store.state.users.currentUser },
@@ -87,7 +91,8 @@ export default {
     unseenNotificationsCount () {
       return this.unseenNotifications.length
     },
-    showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel }
+    showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
+    isMobileLayout () { return this.$store.state.interface.mobileLayout }
   },
   methods: {
     scrollToTop () {
@@ -105,6 +110,13 @@ export default {
     },
     toggleMobileNotifications () {
       this.notificationsOpen = !this.notificationsOpen
+    },
+    updateMobileState () {
+      const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
+      const changed = width <= 800 !== this.isMobileLayout
+      if (changed) {
+        this.$store.dispatch('setMobileLayout', width <= 800)
+      }
     }
   }
 }
diff --git a/src/App.scss b/src/App.scss
index 3edc41a0..775bc1c8 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -667,7 +667,7 @@ nav {
   height: 100vh;
   top: 50px;
   left: 0;
-  z-index: 1001;
+  z-index: 9;
   overflow-x: hidden;
   overflow-y: scroll;
   transition-property: transform;
diff --git a/src/App.vue b/src/App.vue
index aad84804..d83d5dbe 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -25,11 +25,13 @@
       </div>
     </nav>
     <div v-if="" class="container" id="content">
-      <side-drawer ref="sideDrawer" :logout="logout"></side-drawer>
-      <div class="mobile-notifications" :class="{ 'closed': !notificationsOpen }">
-        <notifications/>
+      <div v-if="isMobileLayout">
+        <side-drawer ref="sideDrawer" :logout="logout"></side-drawer>
+        <div class="mobile-notifications" :class="{ 'closed': !notificationsOpen }">
+          <notifications/>
+        </div>
       </div>
-      <div class="sidebar-flexer mobile-hidden">
+      <div class="sidebar-flexer mobile-hidden" v-if="!isMobileLayout">
         <div class="sidebar-bounds">
           <div class="sidebar-scroller">
             <div class="sidebar">
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 53ecc083..ad72ce04 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -5,6 +5,9 @@ import routes from './routes'
 import App from '../App.vue'
 
 const afterStoreSetup = ({ store, i18n }) => {
+  const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
+  store.dispatch('setMobileLayout', width <= 800)
+
   window.fetch('/api/statusnet/config.json')
     .then((res) => res.json())
     .then((data) => {
diff --git a/src/modules/interface.js b/src/modules/interface.js
index 956c9cb3..71554787 100644
--- a/src/modules/interface.js
+++ b/src/modules/interface.js
@@ -11,7 +11,8 @@ const defaultState = {
       window.CSS.supports('filter', 'drop-shadow(0 0)') ||
       window.CSS.supports('-webkit-filter', 'drop-shadow(0 0)')
     )
-  }
+  },
+  mobileLayout: false
 }
 
 const interfaceMod = {
@@ -31,6 +32,9 @@ const interfaceMod = {
     },
     setNotificationPermission (state, permission) {
       state.notificationPermission = permission
+    },
+    setMobileLayout (state, value) {
+      state.mobileLayout = value
     }
   },
   actions: {
@@ -42,6 +46,10 @@ const interfaceMod = {
     },
     setNotificationPermission ({ commit }, permission) {
       commit('setNotificationPermission', permission)
+    },
+    setMobileLayout ({ commit }, value) {
+      console.log('setMobileLayout called')
+      commit('setMobileLayout', value)
     }
   }
 }
-- 
cgit v1.2.3-70-g09d2


From f19284357e94968cdc9d4034c5e33ef9d6f6d9d7 Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Thu, 14 Mar 2019 17:46:04 +0200
Subject: make nav bar slide, move mobile post status to mobile nav

---
 src/App.scss                                   | 72 --------------------
 src/App.vue                                    |  7 --
 src/components/mobile_nav/mobile_nav.js        | 14 +++-
 src/components/mobile_nav/mobile_nav.vue       | 91 +++++++++++++++++++++++++-
 src/components/notifications/notifications.js  |  3 +
 src/components/notifications/notifications.vue |  2 +-
 6 files changed, 105 insertions(+), 84 deletions(-)

(limited to 'src/App.vue')

diff --git a/src/App.scss b/src/App.scss
index 8f727cf8..539c9787 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -484,24 +484,6 @@ nav {
   }
 }
 
-.menu-button {
-  display: none;
-  position: relative;
-}
-
-.alert-dot {
-  border-radius: 100%;
-  height: 8px;
-  width: 8px;
-  position: absolute;
-  left: calc(50% - 4px);
-  top: calc(50% - 4px);
-  margin-left: 6px;
-  margin-top: -6px;
-  background-color: $fallback--cRed;
-  background-color: var(--badgeNotification, $fallback--cRed);
-}
-
 .fade-enter-active, .fade-leave-active {
   transition: opacity .2s
 }
@@ -530,20 +512,6 @@ nav {
   display: none;
 }
 
-.panel-switcher {
-  display: none;
-  width: 100%;
-  height: 46px;
-
-  button {
-    display: block;
-    flex: 1;
-    max-height: 32px;
-    margin: 0.5em;
-    padding: 0.5em;
-  }
-}
-
 @media all and (min-width: 800px) {
   body {
     overflow-y: scroll;
@@ -671,46 +639,6 @@ nav {
   border-radius: var(--inputRadius, $fallback--inputRadius);
 }
 
-.mobile-notifications {
-  position: fixed;
-  width: 100vw;
-  height: 100vh;
-  top: calc(50px - 28px - 1.2em);
-  left: 0;
-  z-index: 999;
-  overflow-x: hidden;
-  overflow-y: scroll;
-  transition-property: transform;
-  transition-duration: 0.25s;
-  transform: translate(0);
-
-  background-color: $fallback--bg;
-  background-color: var(--bg, $fallback--bg);
-
-  .notifications {
-    margin: 0;
-    padding: 0;
-    border-radius: 0;
-    box-shadow: none;
-    .panel {
-      border-radius: 0;
-      margin: 0;
-      box-shadow: none;
-    }
-    .panel:after {
-      border-radius: 0;
-    }
-    .panel .panel-heading {
-      border-radius: 0;
-      box-shadow: none;
-    }
-  }
-
-  &.closed {
-    transform: translate(100%);
-  }
-}
-
 @keyframes modal-background-fadein {
   from {
     background-color: rgba(0, 0, 0, 0);
diff --git a/src/App.vue b/src/App.vue
index 54155831..3b8623ad 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -46,13 +46,6 @@
       <media-modal></media-modal>
     </div>
     <chat-panel :floating="true" v-if="currentUser && chat" class="floating-chat mobile-hidden"></chat-panel>
-    <div v-if="isMobileLayout">
-      <side-drawer ref="sideDrawer" :logout="logout"></side-drawer>
-      <div class="mobile-notifications" :class="{ 'closed': !notificationsOpen }">
-        <notifications/>
-      </div>
-    </div>
-    <MobilePostStatusModal />
   </div>
 </template>
 
diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js
index a79aa636..88fab656 100644
--- a/src/components/mobile_nav/mobile_nav.js
+++ b/src/components/mobile_nav/mobile_nav.js
@@ -1,11 +1,13 @@
 import SideDrawer from '../side_drawer/side_drawer.vue'
 import Notifications from '../notifications/notifications.vue'
+import MobilePostStatusModal from '../mobile_post_status_modal/mobile_post_status_modal.vue'
 import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils'
 
 const MobileNav = {
   components: {
     SideDrawer,
-    Notifications
+    Notifications,
+    MobilePostStatusModal
   },
   data: () => ({
     notificationsOpen: false
@@ -25,9 +27,19 @@ const MobileNav = {
     },
     toggleMobileNotifications () {
       this.notificationsOpen = !this.notificationsOpen
+      if (!this.notificationsOpen) {
+        this.markNotificationsAsSeen()
+      }
     },
     scrollToTop () {
       window.scrollTo(0, 0)
+    },
+    logout () {
+      this.$router.replace('/main/public')
+      this.$store.dispatch('logout')
+    },
+    markNotificationsAsSeen () {
+      this.$refs.notifications.markAsSeen()
     }
   }
 }
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index 8f682c39..af2d6d5a 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -1,6 +1,6 @@
 <template>
-  <nav class='nav-bar container' @click="scrollToTop()" id="nav">
-    <div class='inner-nav'>
+  <nav class='nav-bar container asd' id="nav">
+    <div class='inner-nav mobile-inner-nav' @click="scrollToTop()" :class="{ 'shifted': notificationsOpen }">
       <div class='item'>
         <a href="#" class="menu-button" @click.stop.prevent="toggleMobileSidebar()">
           <i class="button-icon icon-menu"></i>
@@ -13,17 +13,102 @@
           <div class="alert-dot" v-if="unseenNotificationsCount"></div>
         </a>
       </div>
+      <div class="mobile-notifications-header">
+        <span>Notifications</span>
+        <i class="icon-cancel" @click.stop.prevent="toggleMobileNotifications()"/>
+      </div>
     </div>
     <SideDrawer ref="sideDrawer" :logout="logout"/>
     <div class="mobile-notifications" :class="{ 'closed': !notificationsOpen }">
-      <Notifications/>
+      <Notifications ref="notifications" noHeading="true"/>
     </div>
+    <MobilePostStatusModal />
   </nav>
 </template>
 
 <script src="./mobile_nav.js"></script>
 
 <style lang="scss">
+@import '../../_variables.scss';
+
+.mobile-inner-nav {
+  transition: transform 0.25s;
+  &.shifted {
+    transform: translateX(-100%);
+  }
+}
+
+.mobile-notifications-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: calc(100% - 1.6em);
+  height: 100%;
+  margin: 0 0.8em 0 0.8em;
+  position: absolute;
+  font-size: 1.3em;
+  color: $fallback--text;
+  color: var(--text, $fallback--text);
+  top: 0;
+  left: 100%;
+}
+
+.menu-button {
+  position: relative;
+}
+
+.alert-dot {
+  border-radius: 100%;
+  height: 8px;
+  width: 8px;
+  position: absolute;
+  left: calc(50% - 4px);
+  top: calc(50% - 4px);
+  margin-left: 6px;
+  margin-top: -6px;
+  background-color: $fallback--cRed;
+  background-color: var(--badgeNotification, $fallback--cRed);
+}
+
+.mobile-notifications {
+  position: fixed;
+  width: 100vw;
+  height: calc(100vh - 50px);
+  top: 50px;
+  left: 0;
+  overflow-x: hidden;
+  overflow-y: scroll;
+  transition-property: transform;
+  transition-duration: 0.25s;
+  transform: translate(0);
+
+  color: $fallback--text;
+  color: var(--text, $fallback--text);
+  background-color: $fallback--bg;
+  background-color: var(--bg, $fallback--bg);
+
+  .notifications {
+    margin: 0;
+    padding: 0;
+    border-radius: 0;
+    box-shadow: none;
+    .panel {
+      border-radius: 0;
+      margin: 0;
+      box-shadow: none;
+    }
+    .panel:after {
+      border-radius: 0;
+    }
+    .panel .panel-heading {
+      border-radius: 0;
+      box-shadow: none;
+    }
+  }
 
+  &.closed {
+    transform: translate(100%);
+  }
+}
 
 </style>
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 9fc5e38a..d3db4b29 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -7,6 +7,9 @@ import {
 } from '../../services/notification_utils/notification_utils.js'
 
 const Notifications = {
+  props: [
+    'noHeading'
+  ],
   created () {
     const store = this.$store
     const credentials = store.state.users.currentUser.credentials
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 6f162b62..634a03ac 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="notifications">
     <div class="panel panel-default">
-      <div class="panel-heading">
+      <div v-if="!noHeading" class="panel-heading">
         <div class="title">
           {{$t('notifications.notifications')}}
           <span class="badge badge-notification unseen-count" v-if="unseenCount">{{unseenCount}}</span>
-- 
cgit v1.2.3-70-g09d2


From 2cda9010df6192b008515b2138a2e071473bc40b Mon Sep 17 00:00:00 2001
From: taehoon <th.dev91@gmail.com>
Date: Tue, 19 Mar 2019 04:53:11 -0400
Subject: add user reporting modal

---
 src/App.js                                         |   4 +-
 src/App.vue                                        |   1 +
 src/components/checkbox/checkbox.js                |  44 ++++++++
 src/components/checkbox/checkbox.scss              |  48 +++++++++
 src/components/user_card/user_card.js              |   3 +
 src/components/user_card/user_card.vue             |  10 +-
 .../user_reporting_modal/user_reporting_modal.js   |  81 +++++++++++++++
 .../user_reporting_modal/user_reporting_modal.vue  | 111 +++++++++++++++++++++
 src/i18n/en.json                                   |   1 +
 src/main.js                                        |   4 +-
 src/modules/reports.js                             |  33 ++++++
 11 files changed, 336 insertions(+), 4 deletions(-)
 create mode 100644 src/components/checkbox/checkbox.js
 create mode 100644 src/components/checkbox/checkbox.scss
 create mode 100644 src/components/user_reporting_modal/user_reporting_modal.js
 create mode 100644 src/components/user_reporting_modal/user_reporting_modal.vue
 create mode 100644 src/modules/reports.js

(limited to 'src/App.vue')

diff --git a/src/App.js b/src/App.js
index 46145b16..e72c73e3 100644
--- a/src/App.js
+++ b/src/App.js
@@ -10,6 +10,7 @@ import MediaModal from './components/media_modal/media_modal.vue'
 import SideDrawer from './components/side_drawer/side_drawer.vue'
 import MobilePostStatusModal from './components/mobile_post_status_modal/mobile_post_status_modal.vue'
 import MobileNav from './components/mobile_nav/mobile_nav.vue'
+import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue'
 import { windowWidth } from './services/window_utils/window_utils'
 
 export default {
@@ -26,7 +27,8 @@ export default {
     MediaModal,
     SideDrawer,
     MobilePostStatusModal,
-    MobileNav
+    MobileNav,
+    UserReportingModal
   },
   data: () => ({
     mobileActivePanel: 'timeline',
diff --git a/src/App.vue b/src/App.vue
index 3b8623ad..cb7e8d78 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -46,6 +46,7 @@
       <media-modal></media-modal>
     </div>
     <chat-panel :floating="true" v-if="currentUser && chat" class="floating-chat mobile-hidden"></chat-panel>
+    <UserReportingModal />
   </div>
 </template>
 
diff --git a/src/components/checkbox/checkbox.js b/src/components/checkbox/checkbox.js
new file mode 100644
index 00000000..324a7597
--- /dev/null
+++ b/src/components/checkbox/checkbox.js
@@ -0,0 +1,44 @@
+// TODO: Template-based functional component is supported in vue-loader 13.3.0+.
+// Also, somehow, props are not provided through 'context' even though they are defined.
+// Need to upgrade vue-loader
+
+import './checkbox.scss'
+
+export default {
+  functional: true,
+  name: 'Checkbox',
+  model: {
+    prop: 'checked',
+    event: 'change'
+  },
+  render (createElement, { data, children }) {
+    const { props = {}, attrs = {}, on = {}, ...rest } = data
+    const { name, checked, disabled, readonly, ...restAttrs } = attrs
+    const { change, ...restListeners } = on
+    const wrapperProps = {
+      attrs: restAttrs,
+      on: restListeners,
+      ...rest
+    }
+    const inputProps = {
+      attrs: {
+        name,
+        checked,
+        disabled,
+        readonly,
+        ...props
+      },
+      on: {}
+    }
+    if (change) {
+      inputProps.on.change = e => change(e.target.checked)
+    }
+    return (
+      <label class="checkbox" {...wrapperProps}>
+        <input type="checkbox" {...inputProps} />
+        <i />
+        {children && <span>{children}</span>}
+      </label>
+    )
+  }
+}
diff --git a/src/components/checkbox/checkbox.scss b/src/components/checkbox/checkbox.scss
new file mode 100644
index 00000000..07b3f39e
--- /dev/null
+++ b/src/components/checkbox/checkbox.scss
@@ -0,0 +1,48 @@
+@import '../../_variables.scss';
+
+.checkbox {
+  position: relative;
+  display: inline-block;
+  padding-left: 1.2em;
+
+  input[type=checkbox] {
+    display: none;
+
+    & + i::before {
+      position: absolute;
+      left: 0;
+      top: 0;
+      display: block;
+      content: '✔';
+      transition: color 200ms;
+      width: 1.1em;
+      height: 1.1em;
+      border-radius: $fallback--checkboxRadius;
+      border-radius: var(--checkboxRadius, $fallback--checkboxRadius);
+      box-shadow: 0px 0px 2px black inset;
+      box-shadow: var(--inputShadow);
+      background-color: $fallback--fg;
+      background-color: var(--input, $fallback--fg);
+      vertical-align: top;
+      text-align: center;
+      line-height: 1.1em;
+      font-size: 1.1em;
+      color: transparent;
+      overflow: hidden;
+      box-sizing: border-box;
+    }
+
+    &:checked + i::before {
+      color: $fallback--text;
+      color: var(--text, $fallback--text);
+    }
+
+    &:disabled + i::before {
+      opacity: .5;
+    }
+  }
+
+  & > span {
+    margin-left: .5em;
+  }
+}
\ No newline at end of file
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
index 1a100de3..7c6ffa89 100644
--- a/src/components/user_card/user_card.js
+++ b/src/components/user_card/user_card.js
@@ -151,6 +151,9 @@ export default {
     },
     userProfileLink (user) {
       return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
+    },
+    reportUser () {
+      this.$store.dispatch('openUserReportingModal', this.user.id)
     }
   }
 }
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index e62b384d..2d02ca03 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -99,8 +99,14 @@
             </button>
           </span>
         </div>
-        <ModerationTools :user='user' v-if='loggedIn.role === "admin"'>
-        </ModerationTools>
+        <div class='block' v-if='isOtherUser && loggedIn'>
+          <span>
+            <button @click="reportUser">
+              {{ $t('user_card.report') }}
+            </button>
+          </span>
+        </div>
+        <ModerationTools :user='user' v-if='loggedIn.role === "admin"'/>
       </div>
     </div>
   </div>
diff --git a/src/components/user_reporting_modal/user_reporting_modal.js b/src/components/user_reporting_modal/user_reporting_modal.js
new file mode 100644
index 00000000..fb9ea16d
--- /dev/null
+++ b/src/components/user_reporting_modal/user_reporting_modal.js
@@ -0,0 +1,81 @@
+
+import Status from '../status/status.vue'
+import Checkbox from '../checkbox/checkbox.js'
+
+const UserReportingModal = {
+  components: {
+    Status,
+    Checkbox
+  },
+  data () {
+    return {
+      comment: '',
+      forward: false,
+      statusIdsToReport: []
+    }
+  },
+  computed: {
+    isLoggedIn () {
+      return !!this.$store.state.users.currentUser
+    },
+    isOpen () {
+      return this.isLoggedIn && this.$store.state.reports.modalActivated
+    },
+    userId () {
+      return this.$store.state.reports.userId
+    },
+    user () {
+      return this.$store.getters.findUser(this.userId)
+    },
+    remoteInstance () {
+      return !this.user.is_local && this.user.screen_name.substr(this.user.screen_name.indexOf('@') + 1)
+    },
+    statuses () {
+      return this.$store.state.reports.statuses
+    }
+  },
+  watch: {
+    userId (value) {
+      this.statusIdsToReport = []
+    }
+  },
+  methods: {
+    closeModal () {
+      this.$store.dispatch('closeUserReportingModal')
+    },
+    reportUser () {
+      const payload = {
+        comment: this.comment,
+        forward: this.forward,
+        statusIdsToReport: this.statusIdsToReport
+      }
+      this.$store.dispatch('reportUser', payload)
+    },
+    isChecked (statusId) {
+      return this.statusIdsToReport.indexOf(statusId) !== -1
+    },
+    toggleStatus (checked, statusId) {
+      if (checked === this.isChecked(statusId)) {
+        return
+      }
+
+      if (checked) {
+        this.statusIdsToReport.push(statusId)
+      } else {
+        this.statusIdsToReport.splice(this.statusIdsToReport.indexOf(statusId), 1)
+      }
+    },
+    resize (e) {
+      const target = e.target || e
+      if (!(target instanceof window.Element)) { return }
+      // Auto is needed to make textbox shrink when removing lines
+      target.style.height = 'auto'
+      target.style.height = `${target.scrollHeight}px`
+      if (target.value === '') {
+        target.style.height = null
+      }
+    }
+  }
+}
+
+export default UserReportingModal
diff --git a/src/components/user_reporting_modal/user_reporting_modal.vue b/src/components/user_reporting_modal/user_reporting_modal.vue
new file mode 100644
index 00000000..49839da3
--- /dev/null
+++ b/src/components/user_reporting_modal/user_reporting_modal.vue
@@ -0,0 +1,111 @@
+<template>
+<div class="modal-view" @click="closeModal" v-if="isOpen">
+  <div class="user-reporting-panel panel" @click.stop="">
+    <div class="panel-heading">Reporting {{user.screen_name}}</div>
+    <div class="panel-body">
+      <div class="user-reporting-panel-left">
+        <div>
+          <p>The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:</p>
+          <textarea
+            v-model="comment"
+            class="form-control"
+            placeholder="Additional comments"
+            rows="1"
+            @input="resize"
+          />
+        </div>
+        <div v-if="!user.is_local">
+          <p>The account is from another server. Send an anonymized copy of the report there as well?</p>
+          <Checkbox v-model="forward">Forward to {{remoteInstance}}</Checkbox>
+        </div>
+        <div>
+          <button class="btn btn-default" @click="reportUser">Submit</button>
+        </div>
+      </div>
+      <div class="user-reporting-panel-right">
+        <div v-for="status in statuses" :key="status.id" class="status-fadein">
+          <Status :inConversation="false" :focused="false" :statusoid="status" />
+          <Checkbox :checked="isChecked(status.id)" @change="checked => toggleStatus(checked, status.id)" />
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+</template>
+
+<script src="./user_reporting_modal.js"></script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+
+.user-reporting-panel {
+  width: 90vw;
+  max-width: 700px;
+
+  .panel-body {
+    display: flex;
+    border-top: 1px solid;
+    border-color: $fallback--border;
+    border-color: var(--border, $fallback--border);
+  }
+
+  &-left {
+    width: 50%;
+    padding: 1.1em;
+    border-right: 1px solid;
+    border-color: $fallback--border;
+    border-color: var(--border, $fallback--border);
+    max-width: 320px;
+    line-height: 1.4em;
+    box-sizing: border-box;
+
+    > div {
+      margin-bottom: 2em;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+    }
+
+    p {
+      margin-top: 0;
+    }
+
+    textarea.form-control {
+      line-height: 16px;
+      resize: none;
+      overflow: hidden;
+      transition: min-height 200ms 100ms;
+      min-height: 44px;
+      width: 100%;
+    }
+
+    .btn {
+      min-width: 10em;
+      padding: 0 2em;
+    }
+  }
+
+  &-right {
+    width: 50%;
+    flex: 1 1 auto;
+    min-height: 20vh;
+    max-height: 80vh;
+    overflow-y: auto;
+    overflow-x: hidden;
+
+    > div {
+      display: flex;
+      justify-content: space-between;
+      border-bottom-width: 1px;
+      border-bottom-style: solid;
+      border-color: $fallback--border;
+      border-color: var(--border, $fallback--border);
+
+      .checkbox {
+        margin: 0.75em;
+      }
+    }
+  }
+}
+</style>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index b07af5e5..8292c921 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -420,6 +420,7 @@
     "muted": "Muted",
     "per_day": "per day",
     "remote_follow": "Remote follow",
+    "report": "Report",
     "statuses": "Statuses",
     "unblock": "Unblock",
     "unblock_progress": "Unblocking...",
diff --git a/src/main.js b/src/main.js
index 725f5806..92f843b1 100644
--- a/src/main.js
+++ b/src/main.js
@@ -12,6 +12,7 @@ import chatModule from './modules/chat.js'
 import oauthModule from './modules/oauth.js'
 import mediaViewerModule from './modules/media_viewer.js'
 import oauthTokensModule from './modules/oauth_tokens.js'
+import reportsModule from './modules/reports.js'
 
 import VueTimeago from 'vue-timeago'
 import VueI18n from 'vue-i18n'
@@ -75,7 +76,8 @@ const persistedStateOptions = {
       chat: chatModule,
       oauth: oauthModule,
       mediaViewer: mediaViewerModule,
-      oauthTokens: oauthTokensModule
+      oauthTokens: oauthTokensModule,
+      reports: reportsModule
     },
     plugins: [persistedState, pushNotifications],
     strict: false // Socket modifies itself, let's ignore this for now.
diff --git a/src/modules/reports.js b/src/modules/reports.js
new file mode 100644
index 00000000..b712cfeb
--- /dev/null
+++ b/src/modules/reports.js
@@ -0,0 +1,33 @@
+import filter from 'lodash/filter'
+
+const reports = {
+  state: {
+    userId: null,
+    statuses: [],
+    modalActivated: false
+  },
+  mutations: {
+    openUserReportingModal (state, { userId, statuses }) {
+      state.userId = userId
+      state.statuses = statuses
+      state.modalActivated = true
+    },
+    closeUserReportingModal (state) {
+      state.modalActivated = false
+    }
+  },
+  actions: {
+    openUserReportingModal ({ rootState, commit }, userId) {
+      const statuses = filter(rootState.statuses.allStatuses, status => status.user.id === userId)
+      commit('openUserReportingModal', { userId, statuses })
+    },
+    closeUserReportingModal ({ commit }) {
+      commit('closeUserReportingModal')
+    },
+    reportUser ({ commit }, payload) {
+      console.log('payload', payload)
+    }
+  }
+}
+
+export default reports
-- 
cgit v1.2.3-70-g09d2


From 0bb82478229b19adae998b9a32b05bcaa4ed0a4f Mon Sep 17 00:00:00 2001
From: taehoon <th.dev91@gmail.com>
Date: Thu, 28 Mar 2019 15:50:53 -0400
Subject: fix double scrollbar display bug in mobile

---
 src/App.js                                                   |  9 ++++++++-
 src/App.scss                                                 | 11 +++++++++++
 src/App.vue                                                  |  2 +-
 src/components/user_reporting_modal/user_reporting_modal.vue |  4 ++--
 4 files changed, 22 insertions(+), 4 deletions(-)

(limited to 'src/App.vue')

diff --git a/src/App.js b/src/App.js
index e72c73e3..87f00989 100644
--- a/src/App.js
+++ b/src/App.js
@@ -39,7 +39,14 @@ export default {
         window.CSS.supports('-moz-mask-size', 'contain') ||
         window.CSS.supports('-ms-mask-size', 'contain') ||
         window.CSS.supports('-o-mask-size', 'contain')
-    )
+    ),
+    isMobile: navigator.userAgent.match(/Android/i) ||
+      navigator.userAgent.match(/webOS/i) ||
+      navigator.userAgent.match(/iPhone/i) ||
+      navigator.userAgent.match(/iPad/i) ||
+      navigator.userAgent.match(/iPod/i) ||
+      navigator.userAgent.match(/BlackBerry/i) ||
+      navigator.userAgent.match(/Windows Phone/i)
   }),
   created () {
     // Load the locale from the storage
diff --git a/src/App.scss b/src/App.scss
index 6d16c7c9..c72529ac 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -839,3 +839,14 @@ nav {
 .vb.vb-dragging-phantom > .vb-dragger > .vb-dragger-styler {
   opacity: .5;
 }
+
+// Disable vuebar and use native scrollbar in mobile device
+#app.mobile {
+  .vb-content {
+    width: 100% !important;
+    padding-right: 0 !important;
+  }
+  .vb-dragger {
+    display: none;
+  }
+}
diff --git a/src/App.vue b/src/App.vue
index cb7e8d78..229bf62b 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,5 +1,5 @@
 <template>
-  <div id="app" v-bind:style="bgAppStyle">
+  <div id="app" v-bind:style="bgAppStyle" v-bind:class="{ mobile: isMobile }">
     <div class="app-bg-wrapper" v-bind:style="bgStyle"></div>
     <MobileNav v-if="isMobileLayout" />
     <nav v-else class='nav-bar container' @click="scrollToTop()" id="nav">
diff --git a/src/components/user_reporting_modal/user_reporting_modal.vue b/src/components/user_reporting_modal/user_reporting_modal.vue
index bf668efc..41c01919 100644
--- a/src/components/user_reporting_modal/user_reporting_modal.vue
+++ b/src/components/user_reporting_modal/user_reporting_modal.vue
@@ -102,8 +102,8 @@
   }
 
   &-right {
-    overflow-y: auto;
-    overflow-x: hidden;
+    display: flex;
+    flex-direction: column;
   }
 
   &-sitem {
-- 
cgit v1.2.3-70-g09d2


From 220a7e89d5087af3989975cb326cd4d8f60cbc6a Mon Sep 17 00:00:00 2001
From: taehoon <th.dev91@gmail.com>
Date: Mon, 29 Apr 2019 14:37:08 -0400
Subject: use native scrollbar

---
 package.json                                       |  1 -
 src/App.js                                         |  9 +---
 src/App.scss                                       | 50 ----------------------
 src/App.vue                                        |  2 +-
 .../user_reporting_modal/user_reporting_modal.vue  |  5 ++-
 src/main.js                                        |  2 -
 yarn.lock                                          |  4 --
 7 files changed, 5 insertions(+), 68 deletions(-)

(limited to 'src/App.vue')

diff --git a/package.json b/package.json
index 36dfda31..fcdea2c1 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,6 @@
     "vue-router": "^3.0.1",
     "vue-template-compiler": "^2.3.4",
     "vue-timeago": "^3.1.2",
-    "vuebar": "^0.0.20",
     "vuelidate": "^0.7.4",
     "vuex": "^3.0.1",
     "whatwg-fetch": "^2.0.3"
diff --git a/src/App.js b/src/App.js
index 87f00989..e72c73e3 100644
--- a/src/App.js
+++ b/src/App.js
@@ -39,14 +39,7 @@ export default {
         window.CSS.supports('-moz-mask-size', 'contain') ||
         window.CSS.supports('-ms-mask-size', 'contain') ||
         window.CSS.supports('-o-mask-size', 'contain')
-    ),
-    isMobile: navigator.userAgent.match(/Android/i) ||
-      navigator.userAgent.match(/webOS/i) ||
-      navigator.userAgent.match(/iPhone/i) ||
-      navigator.userAgent.match(/iPad/i) ||
-      navigator.userAgent.match(/iPod/i) ||
-      navigator.userAgent.match(/BlackBerry/i) ||
-      navigator.userAgent.match(/Windows Phone/i)
+    )
   }),
   created () {
     // Load the locale from the storage
diff --git a/src/App.scss b/src/App.scss
index adbe949c..921f2c3b 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -795,53 +795,3 @@ nav {
     }
   }
 }
-
-// Vuebar default style
-.vb > .vb-dragger {
-  z-index: 5;
-  width: 12px;
-  right: 0;
-}
-
-.vb > .vb-dragger > .vb-dragger-styler {
-  backface-visibility: hidden;
-  transform: rotate3d(0,0,0,0);
-  background-color: $fallback--text;
-  background-color: var(--text, $fallback--text);
-  opacity: .1;
-  margin: 5px 5px 5px 0;
-  border-radius: 20px;
-  height: calc(100% - 10px);
-  display: block;
-}
-
-.vb.vb-scrolling-phantom > .vb-dragger > .vb-dragger-styler {
-  opacity: .3;
-}
-
-.vb > .vb-dragger:hover > .vb-dragger-styler {
-  opacity: .5;
-  margin: 0px;
-  height: 100%;
-}
-
-.vb.vb-dragging > .vb-dragger > .vb-dragger-styler {
-  opacity: .5;
-  margin: 0px;
-  height: 100%;
-}
-
-.vb.vb-dragging-phantom > .vb-dragger > .vb-dragger-styler {
-  opacity: .5;
-}
-
-// Disable vuebar and use native scrollbar in mobile device
-#app.mobile {
-  .vb-content {
-    width: 100% !important;
-    padding-right: 0 !important;
-  }
-  .vb-dragger {
-    display: none;
-  }
-}
diff --git a/src/App.vue b/src/App.vue
index 229bf62b..cb7e8d78 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,5 +1,5 @@
 <template>
-  <div id="app" v-bind:style="bgAppStyle" v-bind:class="{ mobile: isMobile }">
+  <div id="app" v-bind:style="bgAppStyle">
     <div class="app-bg-wrapper" v-bind:style="bgStyle"></div>
     <MobileNav v-if="isMobileLayout" />
     <nav v-else class='nav-bar container' @click="scrollToTop()" id="nav">
diff --git a/src/components/user_reporting_modal/user_reporting_modal.vue b/src/components/user_reporting_modal/user_reporting_modal.vue
index 1cf25e8f..432dd14d 100644
--- a/src/components/user_reporting_modal/user_reporting_modal.vue
+++ b/src/components/user_reporting_modal/user_reporting_modal.vue
@@ -27,7 +27,7 @@
           </div>
         </div>
       </div>
-      <div class="user-reporting-panel-right" v-bar="{preventParentScroll: true}">
+      <div class="user-reporting-panel-right">
         <List :items="statuses">
           <template slot="item" slot-scope="{item}">
             <div class="status-fadein user-reporting-panel-sitem">
@@ -113,12 +113,12 @@
   &-right {
     display: flex;
     flex-direction: column;
+    overflow-y: auto;
   }
 
   &-sitem {
     display: flex;
     justify-content: space-between;
-    padding-right: 15px;
 
     > .status-el {
       flex: 1;
@@ -150,6 +150,7 @@
     &-right {
       width: 50%;
       flex: 1 1 auto;
+      margin-bottom: 12px;
     }
   }
 }
diff --git a/src/main.js b/src/main.js
index e01c921c..92f843b1 100644
--- a/src/main.js
+++ b/src/main.js
@@ -16,7 +16,6 @@ import reportsModule from './modules/reports.js'
 
 import VueTimeago from 'vue-timeago'
 import VueI18n from 'vue-i18n'
-import Vuebar from 'vuebar'
 
 import createPersistedState from './lib/persisted_state.js'
 import pushNotifications from './lib/push_notifications_plugin.js'
@@ -43,7 +42,6 @@ Vue.use(VueTimeago, {
 Vue.use(VueI18n)
 Vue.use(VueChatScroll)
 Vue.use(VueClickOutside)
-Vue.use(Vuebar)
 
 const i18n = new VueI18n({
   // By default, use the browser locale, we will update it if neccessary
diff --git a/yarn.lock b/yarn.lock
index 0dd2173e..69951563 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6491,10 +6491,6 @@ vue@^2.5.13:
   version "2.5.21"
   resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.21.tgz#3d33dcd03bb813912ce894a8303ab553699c4a85"
 
-vuebar@^0.0.20:
-  version "0.0.20"
-  resolved "https://registry.yarnpkg.com/vuebar/-/vuebar-0.0.20.tgz#fd6313c2d3a2202c49e42419fe1d9ef126134200"
-
 vuelidate@^0.7.4:
   version "0.7.4"
   resolved "https://registry.yarnpkg.com/vuelidate/-/vuelidate-0.7.4.tgz#5a0e54be09ac0192f1aa3387d74b92e0945bf8aa"
-- 
cgit v1.2.3-70-g09d2


From 489927bdc93d58ee3966609a60a25a38816aad6a Mon Sep 17 00:00:00 2001
From: taehoon <th.dev91@gmail.com>
Date: Sun, 5 May 2019 23:00:45 -0400
Subject: toggle showing new status form instead of toggle mouting

---
 src/App.vue | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

(limited to 'src/App.vue')

diff --git a/src/App.vue b/src/App.vue
index cb7e8d78..21abd694 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -18,17 +18,19 @@
         </div>
       </div>
     </nav>
-    <div v-if="" class="container" id="content">
-      <div class="sidebar-flexer mobile-hidden" v-if="!isMobileLayout">
+    <div class="container" id="content">
+      <div class="sidebar-flexer mobile-hidden">
         <div class="sidebar-bounds">
           <div class="sidebar-scroller">
             <div class="sidebar">
               <user-panel></user-panel>
-              <nav-panel></nav-panel>
-              <instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
-              <features-panel v-if="!currentUser && showFeaturesPanel"></features-panel>
-              <who-to-follow-panel v-if="currentUser && suggestionsEnabled"></who-to-follow-panel>
-              <notifications v-if="currentUser"></notifications>
+              <div v-if="!isMobileLayout">
+                <nav-panel></nav-panel>
+                <instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
+                <features-panel v-if="!currentUser && showFeaturesPanel"></features-panel>
+                <who-to-follow-panel v-if="currentUser && suggestionsEnabled"></who-to-follow-panel>
+                <notifications v-if="currentUser"></notifications>
+              </div>
             </div>
           </div>
         </div>
-- 
cgit v1.2.3-70-g09d2


From 9c8af14908aca2ff278f16c9e71088570f2eb562 Mon Sep 17 00:00:00 2001
From: taehoon <th.dev91@gmail.com>
Date: Mon, 20 May 2019 16:21:53 -0400
Subject: render modal at the root level using portal

---
 src/App.vue                                        |  1 +
 src/components/dialog_modal/dialog_modal.vue       |  2 ++
 .../moderation_tools/moderation_tools.vue          | 26 ++++++++++++----------
 3 files changed, 17 insertions(+), 12 deletions(-)

(limited to 'src/App.vue')

diff --git a/src/App.vue b/src/App.vue
index 21abd694..769e075d 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -49,6 +49,7 @@
     </div>
     <chat-panel :floating="true" v-if="currentUser && chat" class="floating-chat mobile-hidden"></chat-panel>
     <UserReportingModal />
+    <portal-target name="modal" />
   </div>
 </template>
 
diff --git a/src/components/dialog_modal/dialog_modal.vue b/src/components/dialog_modal/dialog_modal.vue
index 7621fb20..3da543de 100644
--- a/src/components/dialog_modal/dialog_modal.vue
+++ b/src/components/dialog_modal/dialog_modal.vue
@@ -62,6 +62,7 @@
 
     .title {
       margin-bottom: 0;
+      text-align: center;
     }
   }
 
@@ -80,6 +81,7 @@
     background-color: var(--lightBg, $fallback--lightBg);
     border-top: 1px solid $fallback--bg;
     border-top: 1px solid var(--bg, $fallback--bg);
+    display: flex;
     justify-content: flex-end;
 
     button {
diff --git a/src/components/moderation_tools/moderation_tools.vue b/src/components/moderation_tools/moderation_tools.vue
index 146673a5..6a5e8cc0 100644
--- a/src/components/moderation_tools/moderation_tools.vue
+++ b/src/components/moderation_tools/moderation_tools.vue
@@ -65,18 +65,20 @@
       {{ $t('user_card.admin_menu.moderation') }}
     </button>
   </Popper>
-  <DialogModal v-if="showDeleteUserDialog" :onCancel='deleteUserDialog.bind(this, false)'>
-    <span slot="header">{{ $t('user_card.admin_menu.delete_user') }}</span>
-    <p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
-    <span slot="footer">
-      <button @click='deleteUserDialog(false)'>
-        {{ $t('general.cancel') }}
-      </button>
-      <button class="danger" @click='deleteUser()'>
-        {{ $t('user_card.admin_menu.delete_user') }}
-      </button>
-    </span>
-  </DialogModal>
+  <portal to="modal">
+    <DialogModal v-if="showDeleteUserDialog" :onCancel='deleteUserDialog.bind(this, false)'>
+      <template slot="header">{{ $t('user_card.admin_menu.delete_user') }}</template>
+      <p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
+      <template slot="footer">
+        <button class="btn btn-default" @click='deleteUserDialog(false)'>
+          {{ $t('general.cancel') }}
+        </button>
+        <button class="btn btn-default danger" @click='deleteUser()'>
+          {{ $t('user_card.admin_menu.delete_user') }}
+        </button>
+      </template>
+    </DialogModal>
+  </portal>
 </div>
 </template>
 
-- 
cgit v1.2.3-70-g09d2

