From bd2ed617a740ef3b37dedf3bed608e433dc0ec09 Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Sat, 15 Dec 2018 19:13:01 +0200
Subject: Remove panel switcher, add rudimentary drawer

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

(limited to 'src/App.vue')

diff --git a/src/App.vue b/src/App.vue
index a3a7ecf6..fddc63da 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -13,27 +13,33 @@
           <router-link class="site-name" :to="{ name: 'root' }" active-class="home">{{sitename}}</router-link>
         </div>
         <div class='item right'>
+          <a href="#" @click.prevent="toggleMobileSidebar()"><i class="icon-menu"></i></a>
           <user-finder class="nav-icon" @toggled="onFinderToggled"></user-finder>
           <router-link @click.native="activatePanel('timeline')" :to="{ name: 'settings'}"><i class="icon-cog nav-icon" :title="$t('nav.preferences')"></i></router-link>
           <a href="#" v-if="currentUser" @click.prevent="logout"><i class="icon-logout nav-icon" :title="$t('login.logout')"></i></a>
         </div>
       </div>
     </nav>
-    <div class="container" id="content">
-      <div class="panel-switcher">
-        <button @click="activatePanel('sidebar')">Sidebar</button>
-        <button @click="activatePanel('timeline')">Timeline</button>
-      </div>
-      <div class="sidebar-flexer" :class="{ 'mobile-hidden': mobileActivePanel != 'sidebar'}">
+
+
+
+    <div v-if="" class="container" id="content">
+      <side-drawer :activatePanel="activatePanel" :closed="!showMobileSidebar"></side-drawer>
+      <!--
+        <button @click="activatePanel(mobileViews.postStatus)">post status</button>
+        <button @click="activatePanel(mobileViews.notifications)">notifs</button>
+        <button @click="activatePanel(mobileViews.timeline)">timeline</button>
+      -->
+      <div class="sidebar-flexer">
         <div class="sidebar-bounds">
           <div class="sidebar-scroller">
             <div class="sidebar">
-              <user-panel :activatePanel="activatePanel"></user-panel>
-              <nav-panel :activatePanel="activatePanel"></nav-panel>
-              <instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
+              <user-panel :activatePanel="activatePanel" :class="mobileShowOnlyIn(mobileViews.postStatus)"></user-panel>
+              <nav-panel :activatePanel="activatePanel" class="mobile-hidden"></nav-panel>
+              <instance-specific-panel v-if="showInstanceSpecificPanel" class="mobile-hidden"></instance-specific-panel>
               <features-panel v-if="!currentUser"></features-panel>
               <who-to-follow-panel v-if="currentUser && suggestionsEnabled"></who-to-follow-panel>
-              <notifications :activatePanel="activatePanel" v-if="currentUser"></notifications>
+              <notifications :activatePanel="activatePanel" v-if="currentUser" :class="mobileShowOnlyIn(mobileViews.notifications)"></notifications>
             </div>
           </div>
         </div>
-- 
cgit v1.2.3-70-g09d2


From 4836c8ac74569668001f1adc39fe84377ddb7dba Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Sat, 22 Dec 2018 17:32:07 +0200
Subject: Add some more routes to side drawer

---
 src/App.vue                                 |  8 +++++++-
 src/components/side_drawer/side_drawer.js   |  6 +++++-
 src/components/side_drawer/side_drawer.vue  | 30 ++++++++++++++++++++---------
 src/components/user_profile/user_profile.js |  1 -
 src/i18n/en.json                            |  1 +
 5 files changed, 34 insertions(+), 12 deletions(-)

(limited to 'src/App.vue')

diff --git a/src/App.vue b/src/App.vue
index 2effc983..55cac52c 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -24,7 +24,13 @@
 
 
     <div v-if="" class="container" id="content">
-      <side-drawer :activatePanel="activatePanel" :closed="!showMobileSidebar" :clickoutside="toggleMobileSidebar"></side-drawer>
+      <side-drawer
+        :activatePanel="activatePanel"
+        :closed="!showMobileSidebar"
+        :clickoutside="toggleMobileSidebar"
+        :logout="logout"
+        >
+      </side-drawer>
       <!--
         <button @click="activatePanel(mobileViews.postStatus)">post status</button>
         <button @click="activatePanel(mobileViews.notifications)">notifs</button>
diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js
index b1b7701c..6541077b 100644
--- a/src/components/side_drawer/side_drawer.js
+++ b/src/components/side_drawer/side_drawer.js
@@ -1,5 +1,5 @@
 const SideDrawer = {
-  props: [ 'activatePanel', 'closed', 'clickoutside' ],
+  props: [ 'activatePanel', 'closed', 'clickoutside', 'logout' ],
   computed: {
     currentUser () {
       return this.$store.state.users.currentUser
@@ -14,6 +14,10 @@ const SideDrawer = {
       if (typeof this.clickoutside === 'function') {
         this.clickoutside()
       }
+    },
+    doLogout () {
+      this.logout()
+      this.gotoPanel('timeline')
     }
   }
 }
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index b5f399b5..1593ae65 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -3,21 +3,25 @@
     <div class="panel panel-default side-drawer" :class="{'side-drawer-closed': closed}">
       <ul>
         <li v-if='currentUser'>
-          <a href="#" @click="gotoPanel('poststatus')">poststatus</a>
+          <a href="#" @click="gotoPanel('poststatus')">
+            {{ $t("post_status.new_status") }}
+          </a>
+        </li>
+        <li v-else>
+          <a href="#" @click="gotoPanel('poststatus')">
+            {{ $t("login.login") }}
+          </a>
         </li>
         <li v-if='currentUser'>
-          <a href="#" @click="gotoPanel('notifications')">notifications</a>
+          <a href="#" @click="gotoPanel('notifications')">
+            {{ $t("notifications.notifications") }}
+          </a>
         </li>
         <li v-if='currentUser'>
           <router-link @click.native="gotoPanel('timeline')" to='/main/friends'>
             {{ $t("nav.timeline") }}
           </router-link>
         </li>
-        <li v-if='currentUser'>
-          <router-link @click.native="gotoPanel('timeline')" :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
-            {{ $t("nav.mentions") }}
-          </router-link>
-        </li>
         <li v-if='currentUser'>
           <router-link @click.native="gotoPanel('timeline')" :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
             {{ $t("nav.dms") }}
@@ -38,6 +42,16 @@
             {{ $t("nav.twkn") }}
           </router-link>
         </li>
+        <li>
+          <router-link @click.native="gotoPanel('timeline')" :to="{ name: 'settings'}">
+            {{ $t("settings.settings") }}
+          </router-link>
+        </li>
+        <li v-if="currentUser">
+          <a @click="doLogout" href="#">
+            {{ $t("login.logout") }}
+          </a>
+        </li>
       </ul>
     </div>
     <div class="side-drawer-click-outside" @click.stop.prevent="clickedOutside" :class="{'side-drawer-click-outside-closed': closed}"></div>
@@ -139,8 +153,6 @@
 
   &.router-link-active {
     font-weight: bolder;
-    background-color: $fallback--lightBg;
-    background-color: var(--lightBg, $fallback--lightBg);
 
     &:hover {
       text-decoration: underline;
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index deee77dd..d8d0c532 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -4,7 +4,6 @@ import Timeline from '../timeline/timeline.vue'
 
 const UserProfile = {
   created () {
-    debugger
     this.$store.commit('clearTimeline', { timeline: 'user' })
     this.$store.dispatch('startFetching', ['user', this.fetchBy])
     if (!this.user) {
diff --git a/src/i18n/en.json b/src/i18n/en.json
index f445bfc2..f9262f08 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -50,6 +50,7 @@
     "repeated_you": "repeated your status"
   },
   "post_status": {
+    "new_status": "Post new status",
     "account_not_locked_warning": "Your account is not {0}. Anyone can follow you to view your follower-only posts.",
     "account_not_locked_warning_link": "locked",
     "attachments_sensitive": "Mark attachments as sensitive",
-- 
cgit v1.2.3-70-g09d2


From e46b560ead02ab5d9df8edbb997c56b835aa21d4 Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Sun, 23 Dec 2018 19:50:19 +0200
Subject: move closing logic to drawer, add swipe to close

---
 src/App.js                                 |  5 +--
 src/App.vue                                | 14 ++-----
 src/components/side_drawer/side_drawer.js  | 32 ++++++++++----
 src/components/side_drawer/side_drawer.vue | 67 ++++++++++++++++--------------
 src/components/user_finder/user_finder.vue | 22 +++++-----
 5 files changed, 78 insertions(+), 62 deletions(-)

(limited to 'src/App.vue')

diff --git a/src/App.js b/src/App.js
index 728c8e54..68fae50e 100644
--- a/src/App.js
+++ b/src/App.js
@@ -30,8 +30,7 @@ export default {
         window.CSS.supports('-moz-mask-size', 'contain') ||
         window.CSS.supports('-ms-mask-size', 'contain') ||
         window.CSS.supports('-o-mask-size', 'contain')
-    ),
-    showMobileSidebar: false
+    )
   }),
   created () {
     // Load the locale from the storage
@@ -93,7 +92,7 @@ export default {
       this.finderHidden = hidden
     },
     toggleMobileSidebar () {
-      this.showMobileSidebar = !this.showMobileSidebar
+      this.$refs.sideDrawer.toggleDrawer()
     }
   }
 }
diff --git a/src/App.vue b/src/App.vue
index 55cac52c..59398a34 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -14,9 +14,9 @@
         </div>
         <div class='item right'>
           <a href="#" @click.stop.prevent="toggleMobileSidebar()"><i class="button-icon icon-menu"></i></a>
-          <user-finder class="button-icon nav-icon" @toggled="onFinderToggled"></user-finder>
-          <router-link @click.native="activatePanel('timeline')" :to="{ name: 'settings'}"><i class="button-icon icon-cog nav-icon" :title="$t('nav.preferences')"></i></router-link>
-          <a href="#" v-if="currentUser" @click.prevent="logout"><i class="button-icon icon-logout nav-icon" :title="$t('login.logout')"></i></a>
+          <user-finder class="button-icon nav-icon mobile-hidden" @toggled="onFinderToggled"></user-finder>
+          <router-link class="mobile-hidden" @click.native="activatePanel('timeline')" :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>
         </div>
       </div>
     </nav>
@@ -25,17 +25,11 @@
 
     <div v-if="" class="container" id="content">
       <side-drawer
+        ref="sideDrawer"
         :activatePanel="activatePanel"
-        :closed="!showMobileSidebar"
-        :clickoutside="toggleMobileSidebar"
         :logout="logout"
         >
       </side-drawer>
-      <!--
-        <button @click="activatePanel(mobileViews.postStatus)">post status</button>
-        <button @click="activatePanel(mobileViews.notifications)">notifs</button>
-        <button @click="activatePanel(mobileViews.timeline)">timeline</button>
-      -->
       <div class="sidebar-flexer">
         <div class="sidebar-bounds">
           <div class="sidebar-scroller">
diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js
index 6541077b..2064dfa5 100644
--- a/src/components/side_drawer/side_drawer.js
+++ b/src/components/side_drawer/side_drawer.js
@@ -1,23 +1,41 @@
+import UserCardContent from '../user_card_content/user_card_content.vue'
+
+const deltaX = (oldX, newX) => newX - oldX
+
+const touchEventX = e => e.touches[0].screenX
+
 const SideDrawer = {
-  props: [ 'activatePanel', 'closed', 'clickoutside', 'logout' ],
+  props: [ 'activatePanel', 'logout' ],
+  data: () => ({
+    closed: true,
+    touchX: 0
+  }),
+  components: { UserCardContent },
   computed: {
     currentUser () {
       return this.$store.state.users.currentUser
     }
   },
   methods: {
+    toggleDrawer () {
+      this.closed = !this.closed
+    },
     gotoPanel (panel) {
       this.activatePanel(panel)
-      this.clickoutside && this.clickoutside()
-    },
-    clickedOutside () {
-      if (typeof this.clickoutside === 'function') {
-        this.clickoutside()
-      }
+      this.toggleDrawer()
     },
     doLogout () {
       this.logout()
       this.gotoPanel('timeline')
+    },
+    touchStart (e) {
+      this.touchX = touchEventX(e)
+    },
+    touchMove (e) {
+      const delta = deltaX(this.touchX, touchEventX(e))
+      if (delta < -30) {
+        this.toggleDrawer()
+      }
     }
   }
 }
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index 1593ae65..99ea3dd3 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -1,6 +1,10 @@
 <template>
-  <div class="side-drawer-container" :class="{'side-drawer-container-closed': closed, 'side-drawer-container-open': !closed}">
-    <div class="panel panel-default side-drawer" :class="{'side-drawer-closed': closed}">
+  <div class="side-drawer-container" :class="{ 'side-drawer-container-closed': closed, 'side-drawer-container-open': !closed }">
+    <div class="panel panel-default side-drawer" :class="{'side-drawer-closed': closed}" @touchstart="touchStart" @touchmove.prevent="touchMove">
+      <div class="side-drawer-heading">
+        <user-card-content :activatePanel="activatePanel" :user="currentUser" :switcher="false" :hideBio="true">
+        </user-card-content>
+      </div>
       <ul>
         <li v-if='currentUser'>
           <a href="#" @click="gotoPanel('poststatus')">
@@ -54,7 +58,7 @@
         </li>
       </ul>
     </div>
-    <div class="side-drawer-click-outside" @click.stop.prevent="clickedOutside" :class="{'side-drawer-click-outside-closed': closed}"></div>
+    <div class="side-drawer-click-outside" @click.stop.prevent="toggleDrawer" :class="{'side-drawer-click-outside-closed': closed}"></div>
   </div>
 </template>
 
@@ -110,7 +114,28 @@
 .side-drawer .panel {
   overflow: hidden;
   margin: 0;
+  display: flex;
+}
+
+.side-drawer-heading {
+  background: transparent;
+  flex-direction: column;
+  align-items: stretch;
+  display: flex;
+  min-height: 8em;
+  padding: 0;
+  margin: 0;
+
+  .profile-panel-background {
+    border-radius: 0;
+    .panel-heading {
+      background: transparent;
+      flex-direction: column;
+      align-items: stretch;
+    }
+  }
 }
+
 .side-drawer ul {
   list-style: none;
   margin: 0;
@@ -123,40 +148,18 @@
   border-color: var(--border, $fallback--border);
   padding: 0;
 
-  &:first-child a {
-    border-top-right-radius: $fallback--panelRadius;
-    border-top-right-radius: var(--panelRadius, $fallback--panelRadius);
-    border-top-left-radius: $fallback--panelRadius;
-    border-top-left-radius: var(--panelRadius, $fallback--panelRadius);
-  }
+  a {
+    display: block;
+    padding: 0.8em 0.85em;
 
-  &:last-child a {
-    border-bottom-right-radius: $fallback--panelRadius;
-    border-bottom-right-radius: var(--panelRadius, $fallback--panelRadius);
-    border-bottom-left-radius: $fallback--panelRadius;
-    border-bottom-left-radius: var(--panelRadius, $fallback--panelRadius);
+    &:hover {
+      background-color: $fallback--lightBg;
+      background-color: var(--lightBg, $fallback--lightBg);
+    }
   }
 }
 
 .side-drawer li:last-child {
   border: none;
 }
-
-.side-drawer a {
-  display: block;
-  padding: 0.8em 0.85em;
-
-  &:hover {
-    background-color: $fallback--lightBg;
-    background-color: var(--lightBg, $fallback--lightBg);
-  }
-
-  &.router-link-active {
-    font-weight: bolder;
-
-    &:hover {
-      text-decoration: underline;
-    }
-  }
-}
 </style>
diff --git a/src/components/user_finder/user_finder.vue b/src/components/user_finder/user_finder.vue
index eeb76c35..37d628fa 100644
--- a/src/components/user_finder/user_finder.vue
+++ b/src/components/user_finder/user_finder.vue
@@ -1,14 +1,16 @@
 <template>
-  <div class="user-finder-container">
-    <i class="icon-spin4 user-finder-icon animate-spin-slow" v-if="loading" />
-    <a href="#" v-if="hidden" :title="$t('finder.find_user')"><i class="icon-user-plus user-finder-icon" @click.prevent.stop="toggleHidden" /></a>
-    <template v-else>
-      <input class="user-finder-input" @keyup.enter="findUser(username)" v-model="username" :placeholder="$t('finder.find_user')" id="user-finder-input" type="text"/>
-      <button class="btn search-button" @click="findUser(username)">
-        <i class="icon-search"/>
-      </button>
-      <i class="button-icon icon-cancel user-finder-icon" @click.prevent.stop="toggleHidden"/>
-    </template>
+  <div>
+    <div class="user-finder-container">
+      <i class="icon-spin4 user-finder-icon animate-spin-slow" v-if="loading" />
+      <a href="#" v-if="hidden" :title="$t('finder.find_user')"><i class="icon-user-plus user-finder-icon" @click.prevent.stop="toggleHidden" /></a>
+      <template v-else>
+        <input class="user-finder-input" @keyup.enter="findUser(username)" v-model="username" :placeholder="$t('finder.find_user')" id="user-finder-input" type="text"/>
+        <button class="btn search-button" @click="findUser(username)">
+          <i class="icon-search"/>
+        </button>
+        <i class="button-icon icon-cancel user-finder-icon" @click.prevent.stop="toggleHidden"/>
+      </template>
+    </div>
   </div>
 </template>
 
-- 
cgit v1.2.3-70-g09d2


From 85c058e95c04245dacf3ffb6b45a6eceb3253e7b Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Fri, 28 Dec 2018 21:39:54 +0200
Subject: New routes, notifications, other impovements in side drwaer

---
 src/App.js                                         |  12 ++-
 src/App.scss                                       |  26 +++++-
 src/App.vue                                        |  35 +++----
 src/boot/routes.js                                 |  10 +-
 src/components/chat_panel/chat_panel.js            |   3 +-
 src/components/chat_panel/chat_panel.vue           |  14 ++-
 src/components/nav_panel/nav_panel.js              |   1 -
 src/components/nav_panel/nav_panel.vue             |  12 +--
 src/components/notification/notification.js        |   5 +-
 src/components/notification/notification.vue       |   8 +-
 src/components/notifications/notifications.js      |  25 ++---
 src/components/notifications/notifications.vue     |   2 +-
 src/components/side_drawer/side_drawer.js          |  28 +++---
 src/components/side_drawer/side_drawer.vue         | 103 ++++++++++++---------
 src/components/status/status.js                    |   3 +-
 src/components/status/status.vue                   |  10 +-
 .../user_card_content/user_card_content.js         |   2 +-
 .../user_card_content/user_card_content.vue        |   6 +-
 src/components/user_panel/user_panel.js            |   1 -
 src/components/user_panel/user_panel.vue           |   2 +-
 src/components/user_search/user_search.js          |   8 ++
 src/components/user_search/user_search.vue         |  18 ++++
 .../notification_utils/notification_utils.js       |  20 ++++
 test/unit/specs/components/user_profile.spec.js    |   3 +-
 .../notification_utils/notification_utils.spec.js  |  88 ++++++++++++++++++
 25 files changed, 310 insertions(+), 135 deletions(-)
 create mode 100644 src/services/notification_utils/notification_utils.js
 create mode 100644 test/unit/specs/services/notification_utils/notification_utils.spec.js

(limited to 'src/App.vue')

diff --git a/src/App.js b/src/App.js
index 68fae50e..1132110c 100644
--- a/src/App.js
+++ b/src/App.js
@@ -7,6 +7,7 @@ import FeaturesPanel from './components/features_panel/features_panel.vue'
 import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue'
 import ChatPanel from './components/chat_panel/chat_panel.vue'
 import SideDrawer from './components/side_drawer/side_drawer.vue'
+import { unseenNotificationsFromStore } from './services/notification_utils/notification_utils'
 
 export default {
   name: 'app',
@@ -75,12 +76,15 @@ export default {
     sitename () { return this.$store.state.instance.name },
     chat () { return this.$store.state.chat.channel.state === 'joined' },
     suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
-    showInstanceSpecificPanel () { return this.$store.state.instance.showInstanceSpecificPanel }
+    showInstanceSpecificPanel () { return this.$store.state.instance.showInstanceSpecificPanel },
+    unseenNotifications () {
+      return unseenNotificationsFromStore(this.$store)
+    },
+    unseenNotificationsCount () {
+      return this.unseenNotifications.length
+    }
   },
   methods: {
-    activatePanel (panelName) {
-      this.mobileActivePanel = panelName
-    },
     scrollToTop () {
       window.scrollTo(0, 0)
     },
diff --git a/src/App.scss b/src/App.scss
index 9c8e2ad3..ed06bbbc 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -473,6 +473,24 @@ 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
 }
@@ -524,9 +542,6 @@ nav {
     .back-button {
       display: none;
     }
-    .site-name {
-      padding-left: 20px;
-    }
   }
 
   .sidebar-bounds {
@@ -665,4 +680,9 @@ nav {
       max-width: 4em;
     }
   }
+
+  .menu-button {
+    display: block;
+    margin-right: 0.8em;
+  }
 }
diff --git a/src/App.vue b/src/App.vue
index 59398a34..9d4616bc 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -7,50 +7,45 @@
       </div>
       <div class='inner-nav'>
         <div class='item'>
-          <router-link class="back-button" @click.native="activatePanel('timeline')" :to="{ name: 'root' }" active-class="hidden">
+          <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="back-button" @click.native="activatePanel('timeline')" :to="{ name: 'root' }" active-class="hidden">
             <i class="icon-left-open" :title="$t('nav.back')"></i>
-          </router-link>
+          </router-link> -->
           <router-link class="site-name" :to="{ name: 'root' }" active-class="home">{{sitename}}</router-link>
         </div>
         <div class='item right'>
-          <a href="#" @click.stop.prevent="toggleMobileSidebar()"><i class="button-icon icon-menu"></i></a>
           <user-finder class="button-icon nav-icon mobile-hidden" @toggled="onFinderToggled"></user-finder>
-          <router-link class="mobile-hidden" @click.native="activatePanel('timeline')" :to="{ name: 'settings'}"><i class="button-icon icon-cog nav-icon" :title="$t('nav.preferences')"></i></router-link>
+          <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>
         </div>
       </div>
     </nav>
-
-
-
     <div v-if="" class="container" id="content">
-      <side-drawer
-        ref="sideDrawer"
-        :activatePanel="activatePanel"
-        :logout="logout"
-        >
-      </side-drawer>
-      <div class="sidebar-flexer">
+      <side-drawer ref="sideDrawer" :logout="logout"></side-drawer>
+      <div class="sidebar-flexer mobile-hidden">
         <div class="sidebar-bounds">
           <div class="sidebar-scroller">
             <div class="sidebar">
-              <user-panel :activatePanel="activatePanel" :class="mobileShowOnlyIn('poststatus')"></user-panel>
-              <nav-panel :activatePanel="activatePanel" class="mobile-hidden"></nav-panel>
-              <instance-specific-panel v-if="showInstanceSpecificPanel" class="mobile-hidden"></instance-specific-panel>
+              <user-panel></user-panel>
+              <nav-panel></nav-panel>
+              <instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
               <features-panel v-if="!currentUser"></features-panel>
               <who-to-follow-panel v-if="currentUser && suggestionsEnabled"></who-to-follow-panel>
-              <notifications :activatePanel="activatePanel" v-if="currentUser" :class="mobileShowOnlyIn('notifications')"></notifications>
+              <notifications v-if="currentUser"></notifications>
             </div>
           </div>
         </div>
       </div>
-      <div class="main" :class="{ 'mobile-hidden': mobileActivePanel != 'timeline' }">
+      <div class="main">
         <transition name="fade">
           <router-view></router-view>
         </transition>
       </div>
     </div>
-    <chat-panel v-if="currentUser && chat" class="floating-chat mobile-hidden"></chat-panel>
+    <chat-panel :floating="true" v-if="currentUser && chat" class="floating-chat mobile-hidden"></chat-panel>
   </div>
 </template>
 
diff --git a/src/boot/routes.js b/src/boot/routes.js
index 8ea8cc7f..4de0e104 100644
--- a/src/boot/routes.js
+++ b/src/boot/routes.js
@@ -12,6 +12,10 @@ import UserSettings from 'components/user_settings/user_settings.vue'
 import FollowRequests from 'components/follow_requests/follow_requests.vue'
 import OAuthCallback from 'components/oauth_callback/oauth_callback.vue'
 import UserSearch from 'components/user_search/user_search.vue'
+import Notifications from 'components/notifications/notifications.vue'
+import UserPanel from 'components/user_panel/user_panel.vue'
+import LoginForm from 'components/login_form/login_form.vue'
+import ChatPanel from 'components/chat_panel/chat_panel.vue'
 
 export default (store) => {
   return [
@@ -62,6 +66,10 @@ export default (store) => {
     { name: 'friend-requests', path: '/~/friend-requests', component: FollowRequests },
     { name: 'user-settings', path: '/~/user-settings', component: UserSettings },
     { name: 'oauth-callback', path: '/~/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) },
-    { name: 'user-search', path: '/~/user-search', component: UserSearch, props: (route) => ({ query: route.query.query }) }
+    { name: 'user-search', path: '/~/user-search', component: UserSearch, props: (route) => ({ query: route.query.query }) },
+    { name: 'notifications', path: '/:username/notifications', component: Notifications },
+    { name: 'new-status', path: '/:username/new-status', component: UserPanel },
+    { name: 'login', path: '/~/login', component: LoginForm },
+    { name: 'chat', path: '/~/chat', component: ChatPanel, props: () => ({ floating: false }) }
   ]
 }
diff --git a/src/components/chat_panel/chat_panel.js b/src/components/chat_panel/chat_panel.js
index e175e90c..d7238641 100644
--- a/src/components/chat_panel/chat_panel.js
+++ b/src/components/chat_panel/chat_panel.js
@@ -1,6 +1,7 @@
 import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
 
 const chatPanel = {
+  props: [ 'floating' ],
   data () {
     return {
       currentMessage: '',
@@ -22,7 +23,7 @@ const chatPanel = {
       this.collapsed = !this.collapsed
     },
     userProfileLink (user) {
-      return generateProfileLink(user.id, user.screen_name)
+      return generateProfileLink(user.id, user.username)
     }
   }
 }
diff --git a/src/components/chat_panel/chat_panel.vue b/src/components/chat_panel/chat_panel.vue
index 1b9c63ff..bf65efc5 100644
--- a/src/components/chat_panel/chat_panel.vue
+++ b/src/components/chat_panel/chat_panel.vue
@@ -1,10 +1,10 @@
 <template>
-  <div class="chat-panel" v-if="!this.collapsed">
+  <div class="chat-panel" v-if="!this.collapsed || !this.floating">
     <div class="panel panel-default">
-      <div class="panel-heading timeline-heading chat-heading" @click.stop.prevent="togglePanel">
+      <div class="panel-heading timeline-heading" :class="{ 'chat-heading': floating }" @click.stop.prevent="togglePanel">
         <div class="title">
           {{$t('chat.title')}}
-          <i class="icon-cancel" style="float: right;"></i>
+          <i class="icon-cancel" style="float: right;" v-if="floating"></i>
         </div>
       </div>
       <div class="chat-window" v-chat-scroll>
@@ -52,6 +52,7 @@
   right: 0px;
   bottom: 0px;
   z-index: 1000;
+  max-width: 25em;
 }
 
 .chat-heading {
@@ -63,10 +64,13 @@
 }
 
 .chat-window {
-  width: 345px;
-  max-height: 40vh;
   overflow-y: auto;
   overflow-x: hidden;
+  max-height: 20em;
+}
+
+.chat-window-container {
+  height: 100%;
 }
 
 .chat-message {
diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js
index 19ce56c3..ea5d7ea4 100644
--- a/src/components/nav_panel/nav_panel.js
+++ b/src/components/nav_panel/nav_panel.js
@@ -1,5 +1,4 @@
 const NavPanel = {
-  props: [ 'activatePanel' ],
   computed: {
     currentUser () {
       return this.$store.state.users.currentUser
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
index c52d1e52..ad7c53f9 100644
--- a/src/components/nav_panel/nav_panel.vue
+++ b/src/components/nav_panel/nav_panel.vue
@@ -3,32 +3,32 @@
     <div class="panel panel-default">
       <ul>
         <li v-if='currentUser'>
-          <router-link @click.native="activatePanel('timeline')" :to="{ name: 'friends' }">
+          <router-link :to="{ name: 'friends' }">
             {{ $t("nav.timeline") }}
           </router-link>
         </li>
         <li v-if='currentUser'>
-          <router-link @click.native="activatePanel('timeline')" :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
+          <router-link :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
             {{ $t("nav.mentions") }}
           </router-link>
         </li>
         <li v-if='currentUser'>
-          <router-link @click.native="activatePanel('timeline')" :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
+          <router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
             {{ $t("nav.dms") }}
           </router-link>
         </li>
         <li v-if='currentUser && currentUser.locked'>
-          <router-link @click.native="activatePanel('timeline')" :to="{ name: 'friend-requests' }">
+          <router-link :to="{ name: 'friend-requests' }">
             {{ $t("nav.friend_requests") }}
           </router-link>
         </li>
         <li>
-          <router-link @click.native="activatePanel('timeline')" :to="{ name: 'public-timeline' }">
+          <router-link :to="{ name: 'public-timeline' }">
             {{ $t("nav.public_tl") }}
           </router-link>
         </li>
         <li>
-          <router-link @click.native="activatePanel('timeline')" :to="{ name: 'public-external-timeline' }">
+          <router-link :to="{ name: 'public-external-timeline' }">
             {{ $t("nav.twkn") }}
           </router-link>
         </li>
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index 9ab870b6..8b48ef1d 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -11,10 +11,7 @@ const Notification = {
       betterShadow: this.$store.state.interface.browserSupport.cssFilter
     }
   },
-  props: [
-    'notification',
-    'activatePanel'
-  ],
+  props: [ 'notification' ],
   components: {
     Status, StillImage, UserCardContent
   },
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 56791d45..f91c90cc 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -1,5 +1,5 @@
 <template>
-  <status :activatePanel="activatePanel" v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status>
+  <status v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status>
   <div class="non-mention" :class="[userClass, { highlighted: userStyle }]" :style="[ userStyle ]"v-else>
     <a class='avatar-container' :href="notification.action.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded">
       <StillImage class='avatar-compact' :class="{'better-shadow': betterShadow}" :src="notification.action.user.profile_image_url_original"/>
@@ -25,15 +25,15 @@
             <small>{{$t('notifications.followed_you')}}</small>
           </span>
         </div>
-        <small class="timeago"><router-link @click.native="activatePanel('timeline')" v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small>
+        <small class="timeago"><router-link v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small>
       </span>
       <div class="follow-text" v-if="notification.type === 'follow'">
-        <router-link @click.native="activatePanel('timeline')" :to="userProfileLink(notification.action.user)">
+        <router-link :to="userProfileLink(notification.action.user)">
           @{{notification.action.user.screen_name}}
         </router-link>
       </div>
       <template v-else>
-        <status :activatePanel="activatePanel" class="faint" :compact="true" :statusoid="notification.status" :noHeading="true"></status>
+        <status class="faint" :compact="true" :statusoid="notification.status" :noHeading="true"></status>
       </template>
     </div>
   </div>
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 4b7a591d..ea32bbd0 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -1,10 +1,12 @@
 import Notification from '../notification/notification.vue'
 import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js'
-
-import { sortBy, filter } from 'lodash'
+import {
+  notificationsFromStore,
+  visibleNotificationsFromStore,
+  unseenNotificationsFromStore
+} from '../../services/notification_utils/notification_utils.js'
 
 const Notifications = {
-  props: [ 'activatePanel' ],
   created () {
     const store = this.$store
     const credentials = store.state.users.currentUser.credentials
@@ -12,28 +14,17 @@ const Notifications = {
     notificationsFetcher.startFetching({ store, credentials })
   },
   computed: {
-    visibleTypes () {
-      return [
-        this.$store.state.config.notificationVisibility.likes && 'like',
-        this.$store.state.config.notificationVisibility.mentions && 'mention',
-        this.$store.state.config.notificationVisibility.repeats && 'repeat',
-        this.$store.state.config.notificationVisibility.follows && 'follow'
-      ].filter(_ => _)
-    },
     notifications () {
-      return this.$store.state.statuses.notifications.data
+      return notificationsFromStore(this.$store)
     },
     error () {
       return this.$store.state.statuses.notifications.error
     },
     unseenNotifications () {
-      return filter(this.visibleNotifications, ({seen}) => !seen)
+      return unseenNotificationsFromStore(this.$store)
     },
     visibleNotifications () {
-      // Don't know why, but sortBy([seen, -action.id]) doesn't work.
-      let sortedNotifications = sortBy(this.notifications, ({action}) => -action.id)
-      sortedNotifications = sortBy(sortedNotifications, 'seen')
-      return sortedNotifications.filter((notification) => this.visibleTypes.includes(notification.type))
+      return visibleNotificationsFromStore(this.$store)
     },
     unseenCount () {
       return this.unseenNotifications.length
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index bef48567..64f18720 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -14,7 +14,7 @@
       <div class="panel-body">
         <div v-for="notification in visibleNotifications" :key="notification.action.id" class="notification" :class='{"unseen": !notification.seen}'>
           <div class="notification-overlay"></div>
-          <notification :activatePanel="activatePanel" :notification="notification"></notification>
+          <notification :notification="notification"></notification>
         </div>
       </div>
       <div class="panel-footer">
diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js
index 96297bb4..82d6d209 100644
--- a/src/components/side_drawer/side_drawer.js
+++ b/src/components/side_drawer/side_drawer.js
@@ -1,39 +1,43 @@
 import UserCardContent from '../user_card_content/user_card_content.vue'
+import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils'
 
-const deltaX = (oldX, newX) => newX - oldX
+const deltaCoord = (oldCoord, newCoord) => [newCoord[0] - oldCoord[0], newCoord[1] - oldCoord[1]]
 
-const touchEventX = e => e.touches[0].screenX
+const touchEventCoord = e => ([e.touches[0].screenX, e.touches[0].screenY])
 
 const SideDrawer = {
-  props: [ 'activatePanel', 'logout' ],
+  props: [ 'logout' ],
   data: () => ({
     closed: true,
-    touchX: 0
+    touchCoord: [0, 0]
   }),
   components: { UserCardContent },
   computed: {
     currentUser () {
       return this.$store.state.users.currentUser
+    },
+    chat () { return this.$store.state.chat.channel.state === 'joined' },
+    unseenNotifications () {
+      return unseenNotificationsFromStore(this.$store)
+    },
+    unseenNotificationsCount () {
+      return this.unseenNotifications.length
     }
   },
   methods: {
     toggleDrawer () {
       this.closed = !this.closed
     },
-    gotoPanel (panel) {
-      this.activatePanel(panel)
-      this.toggleDrawer()
-    },
     doLogout () {
       this.logout()
-      this.gotoPanel('timeline')
+      this.toggleDrawer()
     },
     touchStart (e) {
-      this.touchX = touchEventX(e)
+      this.touchCoord = touchEventCoord(e)
     },
     touchMove (e) {
-      const delta = deltaX(this.touchX, touchEventX(e))
-      if (delta < -30 && !this.closed) {
+      const delta = deltaCoord(this.touchCoord, touchEventCoord(e))
+      if (delta[0] < -30 && Math.abs(delta[1]) < Math.abs(delta[0]) && !this.closed) {
         this.toggleDrawer()
       }
     }
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index b540e5d8..156c4934 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -1,61 +1,77 @@
 <template>
   <div class="side-drawer-container" :class="{ 'side-drawer-container-closed': closed, 'side-drawer-container-open': !closed }">
-    <div class="panel panel-default side-drawer"
+    <div class="side-drawer"
       :class="{'side-drawer-closed': closed}"
       @touchstart="touchStart"
-      @touchmove.prevent="touchMove"
+      @touchmove="touchMove"
     >
-      <div class="side-drawer-heading">
-        <user-card-content :activatePanel="activatePanel" :user="currentUser" :switcher="false" :hideBio="true">
+      <div class="side-drawer-heading" @click="toggleDrawer">
+        <user-card-content :user="currentUser" :switcher="false" :hideBio="true">
         </user-card-content>
       </div>
       <ul>
-        <li v-if='currentUser'>
-          <a href="#" @click="gotoPanel('poststatus')">
+        <li v-if="currentUser" @click="toggleDrawer">
+          <router-link :to="{ name: 'new-status', params: { username: currentUser.screen_name } }">
             {{ $t("post_status.new_status") }}
-          </a>
+          </router-link>
         </li>
-        <li v-else>
-          <a href="#" @click="gotoPanel('poststatus')">
+        <li v-else @click="toggleDrawer">
+          <router-link :to="{ name: 'login' }">
             {{ $t("login.login") }}
-          </a>
-        </li>
-        <li v-if='currentUser'>
-          <a href="#" @click="gotoPanel('notifications')">
-            {{ $t("notifications.notifications") }}
-          </a>
+          </router-link>
         </li>
-        <li v-if='currentUser'>
-          <router-link @click.native="gotoPanel('timeline')" to='/main/friends'>
-            {{ $t("nav.timeline") }}
+        <li v-if="currentUser" @click="toggleDrawer">
+          <router-link :to="{ name: 'notifications', params: { username: currentUser.screen_name } }">
+            {{ $t("notifications.notifications") }} {{ unseenNotificationsCount > 0 ? `(${unseenNotificationsCount})` : '' }}
           </router-link>
         </li>
-        <li v-if='currentUser'>
-          <router-link @click.native="gotoPanel('timeline')" :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
+        <li v-if="currentUser" @click="toggleDrawer">
+          <router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
             {{ $t("nav.dms") }}
           </router-link>
         </li>
-        <li v-if='currentUser && currentUser.locked'>
-          <router-link @click.native="gotoPanel('timeline')" to='/friend-requests'>
+        <li>
+          <div class="divider"></div>
+        </li>
+        <li v-if="currentUser" @click="toggleDrawer">
+          <router-link :to="{ name: 'friends' }">
+            {{ $t("nav.timeline") }}
+          </router-link>
+        </li>
+        <li v-if="currentUser && currentUser.locked" @click="toggleDrawer">
+          <router-link to='/friend-requests'>
             {{ $t("nav.friend_requests") }}
           </router-link>
         </li>
-        <li>
-          <router-link @click.native="gotoPanel('timeline')" to='/main/public'>
+        <li @click="toggleDrawer">
+          <router-link to='/main/public'>
             {{ $t("nav.public_tl") }}
           </router-link>
         </li>
-        <li>
-          <router-link @click.native="gotoPanel('timeline')" to='/main/all'>
+        <li @click="toggleDrawer">
+          <router-link to='/main/all'>
             {{ $t("nav.twkn") }}
           </router-link>
         </li>
+        <li v-if="currentUser && chat" @click="toggleDrawer">
+          <router-link :to="{ name: 'chat' }">
+            {{ $t("nav.chat") }}
+          </router-link>
+        </li>
         <li>
-          <router-link @click.native="gotoPanel('timeline')" :to="{ name: 'settings'}">
+          <div class="divider"></div>
+        </li>
+        <li @click="toggleDrawer">
+          <router-link :to="{ name: 'user-search'}">
+            {{ $t("nav.user_search") }}
+          </router-link>
+        </li>
+        <li @click="toggleDrawer">
+          <router-link :to="{ name: 'settings'}">
             {{ $t("settings.settings") }}
           </router-link>
         </li>
-        <li v-if="currentUser">
+        <li v-if="currentUser" @click="toggleDrawer">
           <a @click="doLogout" href="#">
             {{ $t("login.logout") }}
           </a>
@@ -102,9 +118,14 @@
   transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
   transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
   margin: 0 0 0 -100px;
-  padding: 0 0 0 100px;
-  width: 75%;
-  flex: 0 0 75%;
+  padding: 0 0 1em 100px;
+  width: 80%;
+  max-width: 20em;
+  flex: 0 0 80%;
+  box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
+  box-shadow: var(--panelShadow);
+  background-color: $fallback--bg;
+  background-color: var(--bg, $fallback--bg);
 }
 
 .side-drawer-click-outside-closed {
@@ -115,18 +136,12 @@
   margin: 0 0 0 calc(-100% - 100px);
 }
 
-.side-drawer .panel {
-  overflow: hidden;
-  margin: 0;
-  display: flex;
-}
-
 .side-drawer-heading {
   background: transparent;
   flex-direction: column;
   align-items: stretch;
   display: flex;
-  min-height: 8em;
+  min-height: 7em;
   padding: 0;
   margin: 0;
 
@@ -147,14 +162,18 @@
 }
 
 .side-drawer li {
-  border-bottom: 1px solid;
-  border-color: $fallback--border;
-  border-color: var(--border, $fallback--border);
   padding: 0;
 
+  .divider {
+    border-top: 1px solid;
+    border-color: $fallback--border;
+    border-color: var(--border, $fallback--border);
+    margin: 0.2em 0;
+  }
+
   a {
     display: block;
-    padding: 0.8em 0.85em;
+    padding: 0.5em 0.85em;
 
     &:hover {
       background-color: $fallback--lightBg;
diff --git a/src/components/status/status.js b/src/components/status/status.js
index e683056f..71fd0af6 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -21,8 +21,7 @@ const Status = {
     'replies',
     'noReplyLinks',
     'noHeading',
-    'inlineExpanded',
-    'activatePanel'
+    'inlineExpanded'
   ],
   data () {
     return {
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 1b102d93..af756801 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -3,7 +3,7 @@
     <template v-if="muted && !noReplyLinks">
       <div class="media status container muted">
         <small>
-          <router-link @click.native="activatePanel('timeline')" :to="userProfileLink(status.user.id, status.user.screen_name)">
+          <router-link :to="userProfileLink(status.user.id, status.user.screen_name)">
             {{status.user.screen_name}}
           </router-link>
         </small>
@@ -38,12 +38,12 @@
                 <h4 class="user-name" v-if="status.user.name_html" v-html="status.user.name_html"></h4>
                 <h4 class="user-name" v-else>{{status.user.name}}</h4>
                 <span class="links">
-                  <router-link @click.native="activatePanel('timeline')" :to="userProfileLink(status.user.id, status.user.screen_name)">
+                  <router-link :to="userProfileLink(status.user.id, status.user.screen_name)">
                     {{status.user.screen_name}}
                   </router-link>
                   <span v-if="status.in_reply_to_screen_name" class="faint reply-info">
                     <i class="icon-right-open"></i>
-                    <router-link @click.native="activatePanel('timeline')" :to="userProfileLink(status.in_reply_to_user_id, status.in_reply_to_screen_name)">
+                    <router-link :to="userProfileLink(status.in_reply_to_user_id, status.in_reply_to_screen_name)">
                       {{status.in_reply_to_screen_name}}
                     </router-link>
                   </span>
@@ -60,7 +60,7 @@
               </h4>
             </div>
             <div class="media-heading-right">
-              <router-link class="timeago" @click.native="activatePanel('timeline')" :to="{ name: 'conversation', params: { id: status.id } }">
+              <router-link class="timeago" :to="{ name: 'conversation', params: { id: status.id } }">
                 <timeago :since="status.created_at" :auto-update="60"></timeago>
               </router-link>
               <div class="button-icon visibility-icon" v-if="status.visibility">
@@ -79,7 +79,7 @@
           </div>
 
           <div v-if="showPreview" class="status-preview-container">
-            <status :activatePanel="activatePanel" class="status-preview" v-if="preview" :noReplyLinks="true" :statusoid="preview" :compact=true></status>
+            <status class="status-preview" v-if="preview" :noReplyLinks="true" :statusoid="preview" :compact=true></status>
             <div class="status-preview status-preview-loading" v-else>
               <i class="icon-spin4 animate-spin"></i>
             </div>
diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js
index 75185053..c0d5c515 100644
--- a/src/components/user_card_content/user_card_content.js
+++ b/src/components/user_card_content/user_card_content.js
@@ -3,7 +3,7 @@ import { hex2rgb } from '../../services/color_convert/color_convert.js'
 import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
 
 export default {
-  props: [ 'user', 'switcher', 'selected', 'hideBio', 'activatePanel' ],
+  props: [ 'user', 'switcher', 'selected', 'hideBio' ],
   data () {
     return {
       followRequestInProgress: false,
diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
index c5222519..1f5c9ab6 100644
--- a/src/components/user_card_content/user_card_content.vue
+++ b/src/components/user_card_content/user_card_content.vue
@@ -2,20 +2,20 @@
 <div id="heading" class="profile-panel-background" :style="headingStyle">
   <div class="panel-heading text-center">
     <div class='user-info'>
-      <router-link @click.native="activatePanel && activatePanel('timeline')" :to="{ name: 'user-settings' }" style="float: right; margin-top:16px;" v-if="!isOtherUser">
+      <router-link :to="{ name: 'user-settings' }" style="float: right; margin-top:16px;" v-if="!isOtherUser">
         <i class="button-icon icon-cog usersettings" :title="$t('tool_tip.user_settings')"></i>
       </router-link>
       <a :href="user.statusnet_profile_url" target="_blank" class="floater" v-if="isOtherUser">
         <i class="icon-link-ext usersettings"></i>
       </a>
       <div class='container'>
-        <router-link @click.native="activatePanel && activatePanel('timeline')" :to="userProfileLink(user)">
+        <router-link :to="userProfileLink(user)">
           <StillImage class="avatar" :class='{ "better-shadow": betterShadow }' :src="user.profile_image_url_original"/>
         </router-link>
         <div class="name-and-screen-name">
           <div :title="user.name" class='user-name' v-if="user.name_html" v-html="user.name_html"></div>
           <div :title="user.name" class='user-name' v-else>{{user.name}}</div>
-          <router-link @click.native="activatePanel && activatePanel('timeline')" class='user-screen-name' :to="userProfileLink(user)">
+          <router-link class='user-screen-name' :to="userProfileLink(user)">
             <span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span>
             <span v-if="!hideUserStatsLocal" class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span>
           </router-link>
diff --git a/src/components/user_panel/user_panel.js b/src/components/user_panel/user_panel.js
index eb7cb09c..15804b88 100644
--- a/src/components/user_panel/user_panel.js
+++ b/src/components/user_panel/user_panel.js
@@ -3,7 +3,6 @@ import PostStatusForm from '../post_status_form/post_status_form.vue'
 import UserCardContent from '../user_card_content/user_card_content.vue'
 
 const UserPanel = {
-  props: [ 'activatePanel' ],
   computed: {
     user () { return this.$store.state.users.currentUser }
   },
diff --git a/src/components/user_panel/user_panel.vue b/src/components/user_panel/user_panel.vue
index 83eb099f..2d5cb500 100644
--- a/src/components/user_panel/user_panel.vue
+++ b/src/components/user_panel/user_panel.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="user-panel">
     <div v-if='user' class="panel panel-default" style="overflow: visible;">
-      <user-card-content :activatePanel="activatePanel" :user="user" :switcher="false" :hideBio="true"></user-card-content>
+      <user-card-content :user="user" :switcher="false" :hideBio="true"></user-card-content>
       <div class="panel-footer">
         <post-status-form v-if='user'></post-status-form>
       </div>
diff --git a/src/components/user_search/user_search.js b/src/components/user_search/user_search.js
index 1e488f0c..9c026276 100644
--- a/src/components/user_search/user_search.js
+++ b/src/components/user_search/user_search.js
@@ -9,6 +9,7 @@ const userSearch = {
   ],
   data () {
     return {
+      username: '',
       users: []
     }
   },
@@ -21,7 +22,14 @@ const userSearch = {
     }
   },
   methods: {
+    newQuery (query) {
+      this.$router.push({ name: 'user-search', query: { query } })
+    },
     search (query) {
+      if (!query) {
+        this.users = []
+        return
+      }
       userSearchApi.search({query, store: this.$store})
         .then((res) => {
           this.users = res
diff --git a/src/components/user_search/user_search.vue b/src/components/user_search/user_search.vue
index 20ae84fc..3c2bd3fb 100644
--- a/src/components/user_search/user_search.vue
+++ b/src/components/user_search/user_search.vue
@@ -3,6 +3,12 @@
     <div class="panel-heading">
       {{$t('nav.user_search')}}
     </div>
+    <div class="user-search-input-container">
+      <input class="user-finder-input" @keyup.enter="newQuery(username)" v-model="username" :placeholder="$t('finder.find_user')"/>
+      <button class="btn search-button" @click="newQuery(username)">
+        <i class="icon-search"/>
+      </button>
+    </div>
     <div class="panel-body">
       <user-card v-for="user in users" :key="user.id" :user="user" :showFollows="true"></user-card>
     </div>
@@ -10,3 +16,15 @@
 </template>
 
 <script src="./user_search.js"></script>
+
+<style lang="scss">
+.user-search-input-container {
+  margin: 0.5em;
+  display: flex;
+  justify-content: center;
+
+  .search-button {
+    margin-left: 0.5em;
+  }
+}
+</style>
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
new file mode 100644
index 00000000..f5ac0d47
--- /dev/null
+++ b/src/services/notification_utils/notification_utils.js
@@ -0,0 +1,20 @@
+import { filter, sortBy } from 'lodash'
+
+export const notificationsFromStore = store => store.state.statuses.notifications.data
+
+export const visibleTypes = store => ([
+  store.state.config.notificationVisibility.likes && 'like',
+  store.state.config.notificationVisibility.mentions && 'mention',
+  store.state.config.notificationVisibility.repeats && 'repeat',
+  store.state.config.notificationVisibility.follows && 'follow'
+].filter(_ => _))
+
+export const visibleNotificationsFromStore = store => {
+  // Don't know why, but sortBy([seen, -action.id]) doesn't work.
+  let sortedNotifications = sortBy(notificationsFromStore(store), ({action}) => -action.id)
+  sortedNotifications = sortBy(sortedNotifications, 'seen')
+  return sortedNotifications.filter((notification) => visibleTypes(store).includes(notification.type))
+}
+
+export const unseenNotificationsFromStore = store =>
+  filter(visibleNotificationsFromStore(store), ({seen}) => !seen)
diff --git a/test/unit/specs/components/user_profile.spec.js b/test/unit/specs/components/user_profile.spec.js
index b7743f1f..613f65af 100644
--- a/test/unit/specs/components/user_profile.spec.js
+++ b/test/unit/specs/components/user_profile.spec.js
@@ -7,7 +7,8 @@ const localVue = createLocalVue()
 localVue.use(Vuex)
 
 const mutations = {
-  clearTimeline: () => {}
+  clearTimeline: () => {},
+  setError: () => {}
 }
 
 const externalProfileStore = new Vuex.Store({
diff --git a/test/unit/specs/services/notification_utils/notification_utils.spec.js b/test/unit/specs/services/notification_utils/notification_utils.spec.js
new file mode 100644
index 00000000..c44b8c9e
--- /dev/null
+++ b/test/unit/specs/services/notification_utils/notification_utils.spec.js
@@ -0,0 +1,88 @@
+import * as NotificationUtils from 'src/services/notification_utils/notification_utils.js'
+
+describe('NotificationUtils', () => {
+  describe('visibleNotificationsFromStore', () => {
+    it('should return sorted notifications with configured types', () => {
+      const store = {
+        state: {
+          statuses: {
+            notifications: {
+              data: [
+                {
+                  action: { id: 1 },
+                  type: 'like'
+                },
+                {
+                  action: { id: 2 },
+                  type: 'mention'
+                },
+                {
+                  action: { id: 3 },
+                  type: 'repeat'
+                }
+              ]
+            }
+          },
+          config: {
+            notificationVisibility: {
+              likes: true,
+              repeats: true,
+              mentions: false
+            }
+          }
+        }
+      }
+      const expected = [
+        {
+          action: { id: 3 },
+          type: 'repeat'
+        },
+        {
+          action: { id: 1 },
+          type: 'like'
+        }
+      ]
+      expect(NotificationUtils.visibleNotificationsFromStore(store)).to.eql(expected)
+    })
+  })
+
+  describe('unseenNotificationsFromStore', () => {
+    it('should return only notifications not marked as seen', () => {
+      const store = {
+        state: {
+          statuses: {
+            notifications: {
+              data: [
+                {
+                  action: { id: 1 },
+                  type: 'like',
+                  seen: false
+                },
+                {
+                  action: { id: 2 },
+                  type: 'mention',
+                  seen: true
+                }
+              ]
+            }
+          },
+          config: {
+            notificationVisibility: {
+              likes: true,
+              repeats: true,
+              mentions: false
+            }
+          }
+        }
+      }
+      const expected = [
+        {
+          action: { id: 1 },
+          type: 'like',
+          seen: false
+        }
+      ]
+      expect(NotificationUtils.unseenNotificationsFromStore(store)).to.eql(expected)
+    })
+  })
+})
-- 
cgit v1.2.3-70-g09d2


From ace042015e77e507d6323c493596943dd8c657bb Mon Sep 17 00:00:00 2001
From: shpuld <shp@cock.li>
Date: Sat, 29 Dec 2018 23:42:01 +0200
Subject: Remove commented out back button

---
 src/App.vue | 3 ---
 1 file changed, 3 deletions(-)

(limited to 'src/App.vue')

diff --git a/src/App.vue b/src/App.vue
index 9d4616bc..feadb009 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -11,9 +11,6 @@
             <i class="button-icon icon-menu"></i>
             <div class="alert-dot" v-if="unseenNotificationsCount"></div>
           </a>
-          <!-- <router-link class="back-button" @click.native="activatePanel('timeline')" :to="{ name: 'root' }" active-class="hidden">
-            <i class="icon-left-open" :title="$t('nav.back')"></i>
-          </router-link> -->
           <router-link class="site-name" :to="{ name: 'root' }" active-class="home">{{sitename}}</router-link>
         </div>
         <div class='item right'>
-- 
cgit v1.2.3-70-g09d2

