aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/App.js27
-rw-r--r--src/App.scss32
-rw-r--r--src/App.vue11
-rw-r--r--src/boot/after_store.js5
-rw-r--r--src/components/mobile_nav/mobile_nav.js77
-rw-r--r--src/components/mobile_nav/mobile_nav.vue140
-rw-r--r--src/components/notifications/notifications.js3
-rw-r--r--src/components/notifications/notifications.vue2
-rw-r--r--src/components/side_drawer/side_drawer.vue5
-rw-r--r--src/modules/interface.js10
-rw-r--r--src/services/window_utils/window_utils.js5
11 files changed, 258 insertions, 59 deletions
diff --git a/src/App.js b/src/App.js
index 5c27a3df..46145b16 100644
--- a/src/App.js
+++ b/src/App.js
@@ -9,7 +9,8 @@ import ChatPanel from './components/chat_panel/chat_panel.vue'
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 { unseenNotificationsFromStore } from './services/notification_utils/notification_utils'
+import MobileNav from './components/mobile_nav/mobile_nav.vue'
+import { windowWidth } from './services/window_utils/window_utils'
export default {
name: 'app',
@@ -24,7 +25,8 @@ export default {
ChatPanel,
MediaModal,
SideDrawer,
- MobilePostStatusModal
+ MobilePostStatusModal,
+ MobileNav
},
data: () => ({
mobileActivePanel: 'timeline',
@@ -40,6 +42,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 },
@@ -82,13 +88,8 @@ export default {
chat () { return this.$store.state.chat.channel.state === 'joined' },
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
showInstanceSpecificPanel () { return this.$store.state.instance.showInstanceSpecificPanel },
- unseenNotifications () {
- return unseenNotificationsFromStore(this.$store)
- },
- 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 () {
@@ -101,8 +102,12 @@ export default {
onFinderToggled (hidden) {
this.finderHidden = hidden
},
- toggleMobileSidebar () {
- this.$refs.sideDrawer.toggleDrawer()
+ updateMobileState () {
+ const mobileLayout = windowWidth() <= 800
+ const changed = mobileLayout !== this.isMobileLayout
+ if (changed) {
+ this.$store.dispatch('setMobileLayout', mobileLayout)
+ }
}
}
}
diff --git a/src/App.scss b/src/App.scss
index ae068e4f..5fc0dd27 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;
diff --git a/src/App.vue b/src/App.vue
index 4fff3d1d..3b8623ad 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,17 +1,14 @@
<template>
<div id="app" v-bind:style="bgAppStyle">
<div class="app-bg-wrapper" v-bind:style="bgStyle"></div>
- <nav class='nav-bar container' @click="scrollToTop()" id="nav">
+ <MobileNav v-if="isMobileLayout" />
+ <nav v-else class='nav-bar container' @click="scrollToTop()" id="nav">
<div class='logo' :style='logoBgStyle'>
<div class='mask' :style='logoMaskStyle'></div>
<img :src='logo' :style='logoStyle'>
</div>
<div class='inner-nav'>
<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>
<div class='item right'>
@@ -22,8 +19,7 @@
</div>
</nav>
<div v-if="" class="container" id="content">
- <side-drawer ref="sideDrawer" :logout="logout"></side-drawer>
- <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">
@@ -50,7 +46,6 @@
<media-modal></media-modal>
</div>
<chat-panel :floating="true" v-if="currentUser && chat" class="floating-chat mobile-hidden"></chat-panel>
- <MobilePostStatusModal />
</div>
</template>
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 3138cdc4..66169546 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -1,8 +1,8 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'
-
import App from '../App.vue'
+import { windowWidth } from '../services/window_utils/window_utils'
const getStatusnetConfig = async ({ store }) => {
try {
@@ -230,6 +230,9 @@ const afterStoreSetup = async ({ store, i18n }) => {
})
}
+ const width = windowWidth()
+ store.dispatch('setMobileLayout', width <= 800)
+
const apiConfig = await getStatusnetConfig({ store })
const staticConfig = await getStaticConfig()
await setSettings({ store, apiConfig, staticConfig })
diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js
new file mode 100644
index 00000000..bc63d2ba
--- /dev/null
+++ b/src/components/mobile_nav/mobile_nav.js
@@ -0,0 +1,77 @@
+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'
+import GestureService from '../../services/gesture_service/gesture_service'
+
+const MobileNav = {
+ components: {
+ SideDrawer,
+ Notifications,
+ MobilePostStatusModal
+ },
+ data: () => ({
+ notificationsCloseGesture: undefined,
+ notificationsOpen: false
+ }),
+ created () {
+ this.notificationsCloseGesture = GestureService.swipeGesture(
+ GestureService.DIRECTION_RIGHT,
+ this.closeMobileNotifications,
+ 50
+ )
+ },
+ computed: {
+ currentUser () {
+ return this.$store.state.users.currentUser
+ },
+ unseenNotifications () {
+ return unseenNotificationsFromStore(this.$store)
+ },
+ unseenNotificationsCount () {
+ return this.unseenNotifications.length
+ },
+ sitename () { return this.$store.state.instance.name }
+ },
+ methods: {
+ toggleMobileSidebar () {
+ this.$refs.sideDrawer.toggleDrawer()
+ },
+ openMobileNotifications () {
+ this.notificationsOpen = true
+ },
+ closeMobileNotifications () {
+ if (this.notificationsOpen) {
+ // make sure to mark notifs seen only when the notifs were open and not
+ // from close-calls.
+ this.notificationsOpen = false
+ this.markNotificationsAsSeen()
+ }
+ },
+ notificationsTouchStart (e) {
+ GestureService.beginSwipe(e, this.notificationsCloseGesture)
+ },
+ notificationsTouchMove (e) {
+ GestureService.updateSwipe(e, this.notificationsCloseGesture)
+ },
+ scrollToTop () {
+ window.scrollTo(0, 0)
+ },
+ logout () {
+ this.$router.replace('/main/public')
+ this.$store.dispatch('logout')
+ },
+ markNotificationsAsSeen () {
+ this.$refs.notifications.markAsSeen()
+ }
+ },
+ watch: {
+ $route () {
+ // handles closing notificaitons when you press any router-link on the
+ // notifications.
+ this.closeMobileNotifications()
+ }
+ }
+}
+
+export default MobileNav
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
new file mode 100644
index 00000000..5fa41638
--- /dev/null
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -0,0 +1,140 @@
+<template>
+ <nav class='nav-bar container' id="nav">
+ <div class='mobile-inner-nav' @click="scrollToTop()">
+ <div class='item'>
+ <a href="#" class="mobile-nav-button" @click.stop.prevent="toggleMobileSidebar()">
+ <i class="button-icon icon-menu"></i>
+ </a>
+ <router-link class="site-name" :to="{ name: 'root' }" active-class="home">{{sitename}}</router-link>
+ </div>
+ <div class='item right'>
+ <a class="mobile-nav-button" v-if="currentUser" href="#" @click.stop.prevent="openMobileNotifications()">
+ <i class="button-icon icon-bell-alt"></i>
+ <div class="alert-dot" v-if="unseenNotificationsCount"></div>
+ </a>
+ </div>
+ </div>
+ <SideDrawer ref="sideDrawer" :logout="logout"/>
+ <div v-if="currentUser"
+ class="mobile-notifications-drawer"
+ :class="{ 'closed': !notificationsOpen }"
+ @touchstart="notificationsTouchStart"
+ @touchmove="notificationsTouchMove"
+ >
+ <div class="mobile-notifications-header">
+ <span class="title">{{$t('notifications.notifications')}}</span>
+ <a class="mobile-nav-button" @click.stop.prevent="closeMobileNotifications()">
+ <i class="button-icon icon-cancel"/>
+ </a>
+ </div>
+ <div v-if="currentUser" class="mobile-notifications">
+ <Notifications ref="notifications" noHeading="true"/>
+ </div>
+ </div>
+ <MobilePostStatusModal />
+ </nav>
+</template>
+
+<script src="./mobile_nav.js"></script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+
+.mobile-inner-nav {
+ width: 100%;
+ display: flex;
+ align-items: center;
+}
+
+.mobile-nav-button {
+ display: flex;
+ justify-content: center;
+ width: 50px;
+ position: relative;
+ cursor: pointer;
+}
+
+.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-drawer {
+ width: 100%;
+ height: 100vh;
+ overflow-x: hidden;
+ position: fixed;
+ top: 0;
+ left: 0;
+ box-shadow: 1px 1px 4px rgba(0,0,0,.6);
+ box-shadow: var(--panelShadow);
+ transition-property: transform;
+ transition-duration: 0.25s;
+ transform: translateX(0);
+
+ &.closed {
+ transform: translateX(100%);
+ }
+}
+
+.mobile-notifications-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ z-index: 1;
+ width: 100%;
+ height: 50px;
+ line-height: 50px;
+ position: absolute;
+ color: var(--topBarText);
+ background-color: $fallback--fg;
+ background-color: var(--topBar, $fallback--fg);
+ box-shadow: 0px 0px 4px rgba(0,0,0,.6);
+ box-shadow: var(--topBarShadow);
+
+ .title {
+ font-size: 1.3em;
+ margin-left: 0.6em;
+ }
+}
+
+.mobile-notifications {
+ margin-top: 50px;
+ width: 100vw;
+ height: calc(100vh - 50px);
+ overflow-x: hidden;
+ overflow-y: scroll;
+
+ color: $fallback--text;
+ color: var(--text, $fallback--text);
+ background-color: $fallback--bg;
+ background-color: var(--bg, $fallback--bg);
+
+ .notifications {
+ 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;
+ }
+ }
+}
+
+</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>
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index e5046496..9abb8cef 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -22,11 +22,6 @@
</router-link>
</li>
<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" @click="toggleDrawer">
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
{{ $t("nav.dms") }}
</router-link>
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)
}
}
}
diff --git a/src/services/window_utils/window_utils.js b/src/services/window_utils/window_utils.js
new file mode 100644
index 00000000..faff6cb9
--- /dev/null
+++ b/src/services/window_utils/window_utils.js
@@ -0,0 +1,5 @@
+
+export const windowWidth = () =>
+ window.innerWidth ||
+ document.documentElement.clientWidth ||
+ document.body.clientWidth