Move slideout menu logic to Vue.
This commit is contained in:
parent
ee92de0ff7
commit
2b602ca333
@ -49,6 +49,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
notified: this.$store.state.isNotified,
|
notified: this.$store.state.isNotified,
|
||||||
"menu-open": this.$store.state.sidebarOpen,
|
"menu-open": this.$store.state.sidebarOpen,
|
||||||
|
"menu-dragging": this.$store.state.sidebarDragging,
|
||||||
"userlist-open": this.$store.state.userlistOpen,
|
"userlist-open": this.$store.state.userlistOpen,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<aside id="sidebar">
|
<aside id="sidebar" ref="sidebar">
|
||||||
<div class="scrollable-area">
|
<div class="scrollable-area">
|
||||||
<div class="logo-container">
|
<div class="logo-container">
|
||||||
<img
|
<img
|
||||||
@ -63,7 +63,7 @@
|
|||||||
/></span>
|
/></span>
|
||||||
</footer>
|
</footer>
|
||||||
</aside>
|
</aside>
|
||||||
<div id="sidebar-overlay" @click="$root.setSidebar(false)" />
|
<div id="sidebar-overlay" ref="overlay" @click="$root.setSidebar(false)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -79,6 +79,106 @@ export default {
|
|||||||
activeChannel: Object,
|
activeChannel: Object,
|
||||||
networks: Array,
|
networks: Array,
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.touchStartPos = null;
|
||||||
|
this.touchCurPos = null;
|
||||||
|
this.touchStartTime = 0;
|
||||||
|
this.menuWidth = 0;
|
||||||
|
this.menuIsMoving = false;
|
||||||
|
this.menuIsAbsolute = false;
|
||||||
|
|
||||||
|
this.onTouchStart = (e) => {
|
||||||
|
this.touchStartPos = this.touchCurPos = e.touches.item(0);
|
||||||
|
|
||||||
|
if (e.touches.length !== 1) {
|
||||||
|
this.onTouchEnd();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = window.getComputedStyle(this.$refs.sidebar);
|
||||||
|
|
||||||
|
this.menuWidth = parseFloat(styles.width);
|
||||||
|
this.menuIsAbsolute = styles.position === "absolute";
|
||||||
|
|
||||||
|
if (!this.$store.state.sidebarOpen || this.touchStartPos.screenX > this.menuWidth) {
|
||||||
|
this.touchStartTime = Date.now();
|
||||||
|
|
||||||
|
document.body.addEventListener("touchmove", this.onTouchMove, {passive: true});
|
||||||
|
document.body.addEventListener("touchend", this.onTouchEnd, {passive: true});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onTouchMove = (e) => {
|
||||||
|
const touch = (this.touchCurPos = e.touches.item(0));
|
||||||
|
let distX = touch.screenX - this.touchStartPos.screenX;
|
||||||
|
const distY = touch.screenY - this.touchStartPos.screenY;
|
||||||
|
|
||||||
|
if (!this.menuIsMoving) {
|
||||||
|
// tan(45°) is 1. Gestures in 0°-45° (< 1) are considered horizontal, so
|
||||||
|
// menu must be open; gestures in 45°-90° (>1) are considered vertical, so
|
||||||
|
// chat windows must be scrolled.
|
||||||
|
if (Math.abs(distY / distX) >= 1) {
|
||||||
|
this.onTouchEnd();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const devicePixelRatio = window.devicePixelRatio || 2;
|
||||||
|
|
||||||
|
if (Math.abs(distX) > devicePixelRatio) {
|
||||||
|
this.$store.commit("sidebarDragging", true);
|
||||||
|
this.menuIsMoving = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not animate the menu on desktop view
|
||||||
|
if (!this.menuIsAbsolute) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.$store.state.sidebarOpen) {
|
||||||
|
distX += this.menuWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distX > this.menuWidth) {
|
||||||
|
distX = this.menuWidth;
|
||||||
|
} else if (distX < 0) {
|
||||||
|
distX = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.sidebar.style.transform = "translate3d(" + distX + "px, 0, 0)";
|
||||||
|
this.$refs.overlay.style.opacity = distX / this.menuWidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onTouchEnd = () => {
|
||||||
|
const diff = this.touchCurPos.screenX - this.touchStartPos.screenX;
|
||||||
|
const absDiff = Math.abs(diff);
|
||||||
|
|
||||||
|
if (
|
||||||
|
absDiff > this.menuWidth / 2 ||
|
||||||
|
(Date.now() - this.touchStartTime < 180 && absDiff > 50)
|
||||||
|
) {
|
||||||
|
this.toggle(diff > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeEventListener("touchmove", this.onTouchMove);
|
||||||
|
document.body.removeEventListener("touchend", this.onTouchEnd);
|
||||||
|
this.$store.commit("sidebarDragging", false);
|
||||||
|
|
||||||
|
this.$refs.sidebar.style.transform = null;
|
||||||
|
this.$refs.overlay.style.opacity = null;
|
||||||
|
|
||||||
|
this.touchStartPos = null;
|
||||||
|
this.touchCurPos = null;
|
||||||
|
this.touchStartTime = 0;
|
||||||
|
this.menuIsMoving = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.toggle = (state) => {
|
||||||
|
this.$store.commit("sidebarOpen", state);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.body.addEventListener("touchstart", this.onTouchStart, {passive: true});
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isPublic: () => document.body.classList.contains("public"),
|
isPublic: () => document.body.classList.contains("public"),
|
||||||
},
|
},
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
class SlideoutMenu {
|
|
||||||
enable() {
|
|
||||||
this.viewport = document.getElementById("viewport");
|
|
||||||
this.menu = document.getElementById("sidebar");
|
|
||||||
this.sidebarOverlay = document.getElementById("sidebar-overlay");
|
|
||||||
|
|
||||||
this.touchStartPos = null;
|
|
||||||
this.touchCurPos = null;
|
|
||||||
this.touchStartTime = 0;
|
|
||||||
this.menuWidth = 0;
|
|
||||||
this.menuIsOpen = false;
|
|
||||||
this.menuIsMoving = false;
|
|
||||||
this.menuIsAbsolute = false;
|
|
||||||
|
|
||||||
this.onTouchStart = (e) => {
|
|
||||||
this.touchStartPos = this.touchCurPos = e.touches.item(0);
|
|
||||||
|
|
||||||
if (e.touches.length !== 1) {
|
|
||||||
this.onTouchEnd();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = window.getComputedStyle(this.menu);
|
|
||||||
|
|
||||||
this.menuWidth = parseFloat(styles.width);
|
|
||||||
this.menuIsAbsolute = styles.position === "absolute";
|
|
||||||
|
|
||||||
if (!this.menuIsOpen || this.touchStartPos.screenX > this.menuWidth) {
|
|
||||||
this.touchStartTime = Date.now();
|
|
||||||
|
|
||||||
document.body.addEventListener("touchmove", this.onTouchMove, {passive: true});
|
|
||||||
document.body.addEventListener("touchend", this.onTouchEnd, {passive: true});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onTouchMove = (e) => {
|
|
||||||
const touch = (this.touchCurPos = e.touches.item(0));
|
|
||||||
let distX = touch.screenX - this.touchStartPos.screenX;
|
|
||||||
const distY = touch.screenY - this.touchStartPos.screenY;
|
|
||||||
|
|
||||||
if (!this.menuIsMoving) {
|
|
||||||
// tan(45°) is 1. Gestures in 0°-45° (< 1) are considered horizontal, so
|
|
||||||
// menu must be open; gestures in 45°-90° (>1) are considered vertical, so
|
|
||||||
// chat windows must be scrolled.
|
|
||||||
if (Math.abs(distY / distX) >= 1) {
|
|
||||||
this.onTouchEnd();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const devicePixelRatio = window.devicePixelRatio || 2;
|
|
||||||
|
|
||||||
if (Math.abs(distX) > devicePixelRatio) {
|
|
||||||
this.viewport.classList.toggle("menu-dragging", true);
|
|
||||||
this.menuIsMoving = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not animate the menu on desktop view
|
|
||||||
if (!this.menuIsAbsolute) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.menuIsOpen) {
|
|
||||||
distX += this.menuWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (distX > this.menuWidth) {
|
|
||||||
distX = this.menuWidth;
|
|
||||||
} else if (distX < 0) {
|
|
||||||
distX = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.menu.style.transform = "translate3d(" + distX + "px, 0, 0)";
|
|
||||||
this.sidebarOverlay.style.opacity = distX / this.menuWidth;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onTouchEnd = () => {
|
|
||||||
const diff = this.touchCurPos.screenX - this.touchStartPos.screenX;
|
|
||||||
const absDiff = Math.abs(diff);
|
|
||||||
|
|
||||||
if (
|
|
||||||
absDiff > this.menuWidth / 2 ||
|
|
||||||
(Date.now() - this.touchStartTime < 180 && absDiff > 50)
|
|
||||||
) {
|
|
||||||
this.toggle(diff > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.removeEventListener("touchmove", this.onTouchMove);
|
|
||||||
document.body.removeEventListener("touchend", this.onTouchEnd);
|
|
||||||
this.viewport.classList.toggle("menu-dragging", false);
|
|
||||||
this.menu.style.transform = null;
|
|
||||||
this.sidebarOverlay.style.opacity = null;
|
|
||||||
|
|
||||||
this.touchStartPos = null;
|
|
||||||
this.touchCurPos = null;
|
|
||||||
this.touchStartTime = 0;
|
|
||||||
this.menuIsMoving = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
document.body.addEventListener("touchstart", this.onTouchStart, {passive: true});
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle(state) {
|
|
||||||
this.menuIsOpen = state;
|
|
||||||
this.viewport.classList.toggle("menu-open", state);
|
|
||||||
}
|
|
||||||
|
|
||||||
isOpen() {
|
|
||||||
return this.menuIsOpen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = new SlideoutMenu();
|
|
@ -11,6 +11,7 @@ export default new Vuex.Store({
|
|||||||
activeWindow: null,
|
activeWindow: null,
|
||||||
sessions: [],
|
sessions: [],
|
||||||
sidebarOpen: false,
|
sidebarOpen: false,
|
||||||
|
sidebarDragging: false,
|
||||||
userlistOpen: storage.get("thelounge.state.userlist") !== "false",
|
userlistOpen: storage.get("thelounge.state.userlist") !== "false",
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
@ -32,6 +33,9 @@ export default new Vuex.Store({
|
|||||||
sidebarOpen(state, payload) {
|
sidebarOpen(state, payload) {
|
||||||
state.sidebarOpen = payload;
|
state.sidebarOpen = payload;
|
||||||
},
|
},
|
||||||
|
sidebarDragging(state, payload) {
|
||||||
|
state.sidebarDragging = payload;
|
||||||
|
},
|
||||||
userlistOpen(state, payload) {
|
userlistOpen(state, payload) {
|
||||||
state.userlistOpen = payload;
|
state.userlistOpen = payload;
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,6 @@ const roundBadgeNumber = require("./libs/handlebars/roundBadgeNumber");
|
|||||||
const localetime = require("./libs/handlebars/localetime");
|
const localetime = require("./libs/handlebars/localetime");
|
||||||
const friendlysize = require("./libs/handlebars/friendlysize");
|
const friendlysize = require("./libs/handlebars/friendlysize");
|
||||||
const colorClass = require("./libs/handlebars/colorClass");
|
const colorClass = require("./libs/handlebars/colorClass");
|
||||||
const slideoutMenu = require("../js/slideout");
|
|
||||||
const storage = require("./localStorage");
|
const storage = require("./localStorage");
|
||||||
|
|
||||||
Vue.filter("localetime", localetime);
|
Vue.filter("localetime", localetime);
|
||||||
@ -54,15 +53,11 @@ const vueApp = new Vue({
|
|||||||
onSocketInit() {
|
onSocketInit() {
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
this.$store.commit("isConnected", true);
|
this.$store.commit("isConnected", true);
|
||||||
|
|
||||||
// TODO: handle slideut in vue
|
|
||||||
slideoutMenu.enable();
|
|
||||||
},
|
},
|
||||||
setSidebar(state) {
|
setSidebar(state) {
|
||||||
const utils = require("./utils");
|
const utils = require("./utils");
|
||||||
|
|
||||||
this.$store.commit("sidebarOpen", state);
|
this.$store.commit("sidebarOpen", state);
|
||||||
slideoutMenu.toggle(false);
|
|
||||||
|
|
||||||
if (window.outerWidth > utils.mobileViewportPixels) {
|
if (window.outerWidth > utils.mobileViewportPixels) {
|
||||||
storage.set("thelounge.state.sidebar", state);
|
storage.set("thelounge.state.sidebar", state);
|
||||||
|
Loading…
Reference in New Issue
Block a user