FEATURE: sidebar for narrow desktop screen (#19160)

When desktop screen is narrow like < 1100px, sidebar should behave similarly to mobile version.
This commit is contained in:
Krzysztof Kotlarek 2022-11-25 15:33:26 +11:00 committed by GitHub
parent 20715cd7f0
commit 5b6604f5a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 194 additions and 59 deletions

View File

@ -40,6 +40,20 @@ const SiteHeaderComponent = MountWidget.extend(
this.queueRerender();
},
@observes("site.narrowDesktopView")
narrowDesktopViewChanged() {
if (
this.siteSettings.enable_experimental_sidebar_hamburger &&
(!this.sidebarEnabled || this.site.narrowDesktopView)
) {
this.appEvents.on(
"sidebar-hamburger-dropdown:rendered",
this,
"_animateMenu"
);
}
},
_animateOpening(panel) {
const headerCloak = document.querySelector(".header-cloak");
panel.classList.add("animate");
@ -219,7 +233,7 @@ const SiteHeaderComponent = MountWidget.extend(
if (
this.siteSettings.enable_experimental_sidebar_hamburger &&
!this.sidebarEnabled
(!this.sidebarEnabled || this.site.narrowDesktopView)
) {
this.appEvents.on(
"sidebar-hamburger-dropdown:rendered",
@ -353,14 +367,17 @@ const SiteHeaderComponent = MountWidget.extend(
const menuPanels = document.querySelectorAll(".menu-panel");
if (menuPanels.length === 0) {
if (this.site.mobileView) {
if (this.site.mobileView || this.site.narrowDesktopView) {
this._animate = true;
}
return;
}
const windowWidth = document.body.offsetWidth;
const viewMode = this.site.mobileView ? "slide-in" : "drop-down";
const viewMode =
this.site.mobileView || this.site.narrowDesktopView
? "slide-in"
: "drop-down";
menuPanels.forEach((panel) => {
const headerCloak = document.querySelector(".header-cloak");
@ -377,7 +394,7 @@ const SiteHeaderComponent = MountWidget.extend(
panel.classList.add(viewMode);
if (this._animate || this._panMenuOffset !== 0) {
if (
this.site.mobileView &&
(this.site.mobileView || this.site.narrowDesktopView) &&
panel.parentElement.classList.contains(this._leftMenuClass())
) {
this._panMenuOrigin = "left";
@ -394,7 +411,7 @@ const SiteHeaderComponent = MountWidget.extend(
// We use a mutationObserver to check for style changes, so it's important
// we don't set it if it doesn't change. Same goes for the panelBody!
if (!this.site.mobileView) {
if (!this.site.mobileView && !this.site.narrowDesktopView) {
const buttonPanel = document.querySelectorAll("header ul.icons");
if (buttonPanel.length === 0) {
return;
@ -469,6 +486,8 @@ export default SiteHeaderComponent.extend({
didInsertElement() {
this._super(...arguments);
this.appEvents.on("site-header:force-refresh", this, "queueRerender");
const header = document.querySelector(".d-header-wrap");
if (header) {
schedule("afterRender", () => {
@ -499,6 +518,7 @@ export default SiteHeaderComponent.extend({
this._super(...arguments);
this._resizeObserver?.disconnect();
this.appEvents.off("site-header:force-refresh", this, "queueRerender");
},
});

View File

@ -20,7 +20,9 @@ export default Controller.extend({
init() {
this._super(...arguments);
this.showSidebar =
this.canDisplaySidebar && !this.keyValueStore.getItem(HIDE_SIDEBAR_KEY);
this.canDisplaySidebar &&
!this.keyValueStore.getItem(HIDE_SIDEBAR_KEY) &&
!this.site.narrowDesktopView;
},
@discourseComputed

View File

@ -0,0 +1,45 @@
import NarrowDesktop from "discourse/lib/narrow-desktop";
export default {
name: "narrow-desktop",
initialize(container) {
NarrowDesktop.init();
let site;
if (!container.isDestroyed) {
site = container.lookup("service:site");
site.set("narrowDesktopView", NarrowDesktop.narrowDesktopView);
}
if ("ResizeObserver" in window) {
this._resizeObserver = new ResizeObserver((entries) => {
if (container.isDestroyed) {
return;
}
for (let entry of entries) {
const oldNarrowDesktopView = site.narrowDesktopView;
const newNarrowDesktopView = NarrowDesktop.isNarrowDesktopView(
entry.contentRect.width
);
if (oldNarrowDesktopView !== newNarrowDesktopView) {
const applicationController = container.lookup(
"controller:application"
);
site.set("narrowDesktopView", newNarrowDesktopView);
if (newNarrowDesktopView) {
applicationController.set("showSidebar", false);
}
applicationController.appEvents.trigger(
"site-header:force-refresh"
);
}
}
});
const bodyElement = document.querySelector("body");
if (bodyElement) {
this._resizeObserver.observe(bodyElement);
}
}
},
};

View File

@ -0,0 +1,16 @@
let narrowDesktopForced = false;
const NarrowDesktop = {
narrowDesktopView: false,
init() {
this.narrowDesktopView =
narrowDesktopForced || this.isNarrowDesktopView(window.innerWidth);
},
isNarrowDesktopView(width) {
return width < 1100;
},
};
export default NarrowDesktop;

View File

@ -476,7 +476,7 @@ export default createWidget("header", {
);
} else if (state.hamburgerVisible) {
if (this.siteSettings.enable_experimental_sidebar_hamburger) {
if (!attrs.sidebarEnabled) {
if (!attrs.sidebarEnabled || this.site.narrowDesktopView) {
panels.push(this.attach("revamped-hamburger-menu-wrapper", {}));
}
} else {
@ -501,7 +501,7 @@ export default createWidget("header", {
}
});
if (this.site.mobileView) {
if (this.site.mobileView || this.site.narrowDesktopView) {
panels.push(this.attach("header-cloak"));
}
@ -591,7 +591,8 @@ export default createWidget("header", {
toggleHamburger() {
if (
this.siteSettings.enable_experimental_sidebar_hamburger &&
this.attrs.sidebarEnabled
this.attrs.sidebarEnabled &&
!this.site.narrowDesktopView
) {
this.sendWidgetAction("toggleSidebar");
} else {
@ -601,7 +602,7 @@ export default createWidget("header", {
schedule("afterRender", () => {
if (this.siteSettings.enable_experimental_sidebar_hamburger) {
// Remove focus from hamburger toggle button
document.querySelector("#toggle-hamburger-menu").blur();
document.querySelector("#toggle-hamburger-menu")?.blur();
} else {
// auto focus on first link in dropdown
document.querySelector(".hamburger-panel .menu-links a")?.focus();

View File

@ -11,8 +11,12 @@ export default createWidget("sidebar-toggle", {
? "sidebar.hide_sidebar"
: "sidebar.show_sidebar",
icon: "bars",
action: "toggleSidebar",
className: "btn btn-flat btn-sidebar-toggle",
action: this.site.narrowDesktopView
? "toggleHamburger"
: "toggleSidebar",
className: `btn btn-flat btn-sidebar-toggle ${
this.site.narrowDesktopView ? "narrow-desktop" : ""
}`,
ariaExpanded: attrs.showSidebar ? "true" : "false",
ariaControls: "d-sidebar",
}),

View File

@ -0,0 +1,47 @@
import { test } from "qunit";
import { click, settled, visit, waitUntil } from "@ember/test-helpers";
import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers";
acceptance("Sidebar - Narrow Desktop", function (needs) {
needs.user();
needs.settings({
enable_experimental_sidebar_hamburger: true,
enable_sidebar: true,
});
test("wide sidebar is changed to cloak when resize to narrow screen", async function (assert) {
await visit("/");
await settled();
assert.ok(exists("#d-sidebar"), "wide sidebar is displayed");
await click(".header-sidebar-toggle .btn");
assert.ok(!exists("#d-sidebar"), "widge sidebar is collapsed");
const bodyElement = document.querySelector("body");
bodyElement.style.width = "1000px";
await waitUntil(
() => document.querySelector(".btn-sidebar-toggle.narrow-desktop"),
{
timeout: 5000,
}
);
await click(".btn-sidebar-toggle");
assert.ok(
exists(".sidebar-hamburger-dropdown"),
"cloak sidebar is displayed"
);
await click("#main-outlet");
assert.ok(
!exists(".sidebar-hamburger-dropdown"),
"cloak sidebar is collapsed"
);
bodyElement.style.width = null;
});
});

View File

@ -660,3 +660,50 @@ div.menu-links-header {
color: var(--primary-med-or-secondary-med);
}
}
.hamburger-panel .menu-panel.slide-in {
left: 0;
.panel-body {
display: block;
}
.panel-body-contents {
max-height: unset;
min-height: 100%;
}
}
.header-cloak {
height: 100%;
width: 100%;
position: fixed;
background-color: black;
--opacity: 0.5;
opacity: var(--opacity);
top: 0;
left: 0;
display: none;
touch-action: pan-y pinch-zoom;
@media (prefers-reduced-motion: no-preference) {
&.animate {
transition: opacity 0.1s linear;
}
}
}
.menu-panel.slide-in {
transform: translateX(var(--offset));
@media (prefers-reduced-motion: no-preference) {
&.animate {
transition: transform 0.1s linear;
}
}
&.moving,
&.animate {
// PERF: only render first 20 items in a list to allow for smooth
// pan events
li:nth-child(n + 20) {
display: none;
}
}
}

View File

@ -1,50 +1,3 @@
.hamburger-panel .menu-panel.slide-in {
left: 0;
.panel-body {
display: block;
}
.panel-body-contents {
max-height: unset;
min-height: 100%;
}
}
.header-cloak {
height: 100%;
width: 100%;
position: fixed;
background-color: black;
--opacity: 0.5;
opacity: var(--opacity);
top: 0;
left: 0;
display: none;
touch-action: pan-y pinch-zoom;
@media (prefers-reduced-motion: no-preference) {
&.animate {
transition: opacity 0.1s linear;
}
}
}
.menu-panel.slide-in {
transform: translateX(var(--offset));
@media (prefers-reduced-motion: no-preference) {
&.animate {
transition: transform 0.1s linear;
}
}
&.moving,
&.animate {
// PERF: only render first 20 items in a list to allow for smooth
// pan events
li:nth-child(n + 20) {
display: none;
}
}
}
.user-menu .quick-access-panel.quick-access-profile li:not(.show-all) {
border-bottom: 1px solid var(--primary-low);