diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/App.js | 26 | ||||
| -rw-r--r-- | src/App.scss | 32 | ||||
| -rw-r--r-- | src/App.vue | 11 | ||||
| -rw-r--r-- | src/boot/after_store.js | 3 | ||||
| -rw-r--r-- | src/components/mobile_nav/mobile_nav.js | 62 | ||||
| -rw-r--r-- | src/components/mobile_nav/mobile_nav.vue | 135 | ||||
| -rw-r--r-- | src/components/notifications/notifications.js | 3 | ||||
| -rw-r--r-- | src/components/notifications/notifications.vue | 2 | ||||
| -rw-r--r-- | src/components/side_drawer/side_drawer.vue | 5 | ||||
| -rw-r--r-- | src/modules/interface.js | 10 |
10 files changed, 231 insertions, 58 deletions
@@ -9,7 +9,7 @@ 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' export default { name: 'app', @@ -24,7 +24,8 @@ export default { ChatPanel, MediaModal, SideDrawer, - MobilePostStatusModal + MobilePostStatusModal, + MobileNav }, data: () => ({ mobileActivePanel: 'timeline', @@ -40,6 +41,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 +87,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 +101,12 @@ export default { onFinderToggled (hidden) { this.finderHidden = hidden }, - toggleMobileSidebar () { - this.$refs.sideDrawer.toggleDrawer() + 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 244b3474..dcc913d6 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 a5f8c978..549de497 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -229,6 +229,9 @@ const afterStoreSetup = async ({ store, i18n }) => { }) } + const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth + 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..c1f5c2a9 --- /dev/null +++ b/src/components/mobile_nav/mobile_nav.js @@ -0,0 +1,62 @@ +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, + MobilePostStatusModal + }, + data: () => ({ + notificationsOpen: false + }), + 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() + } + }, + 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..39622fad --- /dev/null +++ b/src/components/mobile_nav/mobile_nav.vue @@ -0,0 +1,135 @@ +<template> + <nav class='nav-bar container asd' 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 }"> + <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 95ee21b4..27db12d7 100644 --- a/src/components/side_drawer/side_drawer.vue +++ b/src/components/side_drawer/side_drawer.vue @@ -21,11 +21,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) } } } |
