mirror of
https://github.com/thelounge/thelounge
synced 2024-11-14 16:27:22 +00:00
Merge pull request #2246 from thelounge/astorije/sidebar-overlay
Add a semi-opaque overlay when channel list is open on mobile
This commit is contained in:
commit
039c12266a
4 changed files with 72 additions and 36 deletions
|
@ -518,7 +518,7 @@ kbd {
|
||||||
width: 220px;
|
width: 220px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar.menu-open {
|
#viewport.menu-open #sidebar {
|
||||||
display: none;
|
display: none;
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
}
|
}
|
||||||
|
@ -2273,22 +2273,46 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -220px;
|
left: -220px;
|
||||||
z-index: 1;
|
z-index: 2;
|
||||||
transition: transform 160ms;
|
transition: transform 160ms;
|
||||||
transform: translateZ(0);
|
transform: translateZ(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar.menu-open {
|
#sidebar-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 160ms, visibility 160ms;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#viewport.menu-open #sidebar-overlay {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#viewport.menu-open #sidebar {
|
||||||
display: flex;
|
display: flex;
|
||||||
transform: translate3d(220px, 0, 0);
|
transform: translate3d(220px, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar.menu-dragging {
|
#viewport.menu-dragging #sidebar-overlay,
|
||||||
transition: none !important;
|
#viewport.menu-dragging #sidebar {
|
||||||
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar.menu-open .messages {
|
#viewport.menu-open #sidebar,
|
||||||
pointer-events: none;
|
#viewport.menu-dragging #sidebar {
|
||||||
|
box-shadow: 0 0 25px 0 rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#viewport.menu-open #sidebar-overlay,
|
||||||
|
#viewport.menu-dragging #sidebar-overlay {
|
||||||
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sidebar .empty::before {
|
#sidebar .empty::before {
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
<span class="tooltipped tooltipped-n tooltipped-no-touch" aria-label="Sign out"><button class="icon sign-out" id="sign-out" aria-label="Sign out"></button></span>
|
<span class="tooltipped tooltipped-n tooltipped-no-touch" aria-label="Sign out"><button class="icon sign-out" id="sign-out" aria-label="Sign out"></button></span>
|
||||||
</footer>
|
</footer>
|
||||||
</aside>
|
</aside>
|
||||||
|
<div id="sidebar-overlay"></div>
|
||||||
<article id="windows">
|
<article id="windows">
|
||||||
<div id="loading" class="window active">
|
<div id="loading" class="window active">
|
||||||
<div id="loading-status-container">
|
<div id="loading-status-container">
|
||||||
|
|
|
@ -40,13 +40,17 @@ $(function() {
|
||||||
storage.set(name, state);
|
storage.set(name, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#windows").on("click", function(e) {
|
// If sidebar overlay is visible and it is clicked, close the sidebar
|
||||||
const isOpen = slideoutMenu.isOpen();
|
$("#sidebar-overlay").on("click", () => {
|
||||||
|
slideoutMenu.toggle(false);
|
||||||
|
storeSidebarVisibility("thelounge.state.sidebar", false);
|
||||||
|
});
|
||||||
|
|
||||||
if ((isOpen && $(window).outerWidth() < utils.mobileViewportPixels) || $(e.target).is(".lt")) {
|
$("#windows").on("click", "button.lt", () => {
|
||||||
slideoutMenu.toggle(!isOpen);
|
const isOpen = !slideoutMenu.isOpen();
|
||||||
storeSidebarVisibility("thelounge.state.sidebar", !isOpen);
|
|
||||||
}
|
slideoutMenu.toggle(isOpen);
|
||||||
|
storeSidebarVisibility("thelounge.state.sidebar", isOpen);
|
||||||
});
|
});
|
||||||
|
|
||||||
viewport.on("click", ".rt", function() {
|
viewport.on("click", ".rt", function() {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const viewport = document.getElementById("viewport");
|
||||||
const menu = document.getElementById("sidebar");
|
const menu = document.getElementById("sidebar");
|
||||||
|
const sidebarOverlay = document.getElementById("sidebar-overlay");
|
||||||
|
|
||||||
let touchStartPos = null;
|
let touchStartPos = null;
|
||||||
let touchCurPos = null;
|
let touchCurPos = null;
|
||||||
|
@ -16,7 +18,7 @@ class SlideoutMenu {
|
||||||
|
|
||||||
static toggle(state) {
|
static toggle(state) {
|
||||||
menuIsOpen = state;
|
menuIsOpen = state;
|
||||||
menu.classList.toggle("menu-open", state);
|
viewport.classList.toggle("menu-open", state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static isOpen() {
|
static isOpen() {
|
||||||
|
@ -34,46 +36,50 @@ function onTouchStart(e) {
|
||||||
|
|
||||||
menuWidth = parseFloat(window.getComputedStyle(menu).width);
|
menuWidth = parseFloat(window.getComputedStyle(menu).width);
|
||||||
|
|
||||||
if ((!menuIsOpen && touch.screenX < 50) || (menuIsOpen && touch.screenX > menuWidth)) {
|
if (!menuIsOpen || touch.screenX > menuWidth) {
|
||||||
touchStartPos = touch;
|
touchStartPos = touch;
|
||||||
touchCurPos = touch;
|
touchCurPos = touch;
|
||||||
touchStartTime = Date.now();
|
touchStartTime = Date.now();
|
||||||
|
|
||||||
menu.classList.toggle("menu-dragging", true);
|
document.body.addEventListener("touchmove", onTouchMove, {passive: true});
|
||||||
document.body.addEventListener("touchmove", onTouchMove);
|
|
||||||
document.body.addEventListener("touchend", onTouchEnd, {passive: true});
|
document.body.addEventListener("touchend", onTouchEnd, {passive: true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTouchMove(e) {
|
function onTouchMove(e) {
|
||||||
const touch = touchCurPos = e.touches.item(0);
|
const touch = touchCurPos = e.touches.item(0);
|
||||||
let setX = touch.screenX - touchStartPos.screenX;
|
let distX = touch.screenX - touchStartPos.screenX;
|
||||||
|
const distY = touch.screenY - touchStartPos.screenY;
|
||||||
|
|
||||||
if (Math.abs(setX > 30)) {
|
if (!menuIsMoving) {
|
||||||
menuIsMoving = true;
|
// 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) {
|
||||||
|
onTouchEnd();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!menuIsMoving && Math.abs(touch.screenY - touchStartPos.screenY) > 30) {
|
const devicePixelRatio = window.devicePixelRatio || 2;
|
||||||
onTouchEnd();
|
|
||||||
return;
|
if (Math.abs(distX) > devicePixelRatio) {
|
||||||
|
viewport.classList.toggle("menu-dragging", true);
|
||||||
|
menuIsMoving = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menuIsOpen) {
|
if (menuIsOpen) {
|
||||||
setX += menuWidth;
|
distX += menuWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setX > menuWidth) {
|
if (distX > menuWidth) {
|
||||||
setX = menuWidth;
|
distX = menuWidth;
|
||||||
} else if (setX < 0) {
|
} else if (distX < 0) {
|
||||||
setX = 0;
|
distX = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.style.transform = "translate3d(" + setX + "px, 0, 0)";
|
menu.style.transform = "translate3d(" + distX + "px, 0, 0)";
|
||||||
|
sidebarOverlay.style.opacity = distX / menuWidth;
|
||||||
if (menuIsMoving) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTouchEnd() {
|
function onTouchEnd() {
|
||||||
|
@ -86,8 +92,9 @@ function onTouchEnd() {
|
||||||
|
|
||||||
document.body.removeEventListener("touchmove", onTouchMove);
|
document.body.removeEventListener("touchmove", onTouchMove);
|
||||||
document.body.removeEventListener("touchend", onTouchEnd);
|
document.body.removeEventListener("touchend", onTouchEnd);
|
||||||
menu.classList.toggle("menu-dragging", false);
|
viewport.classList.toggle("menu-dragging", false);
|
||||||
menu.style.transform = null;
|
menu.style.transform = null;
|
||||||
|
sidebarOverlay.style.opacity = null;
|
||||||
|
|
||||||
touchStartPos = null;
|
touchStartPos = null;
|
||||||
touchCurPos = null;
|
touchCurPos = null;
|
||||||
|
|
Loading…
Reference in a new issue