diff --git a/app/assets/javascripts/discourse/app/components/menu-panel.hbs b/app/assets/javascripts/discourse/app/components/menu-panel.hbs index 9e77bac711d..e45928f73cb 100644 --- a/app/assets/javascripts/discourse/app/components/menu-panel.hbs +++ b/app/assets/javascripts/discourse/app/components/menu-panel.hbs @@ -1,4 +1,7 @@ -
+
{{yield}} diff --git a/app/assets/javascripts/discourse/app/components/site-header.js b/app/assets/javascripts/discourse/app/components/site-header.js index 160870f6d82..aa4ab35dc74 100644 --- a/app/assets/javascripts/discourse/app/components/site-header.js +++ b/app/assets/javascripts/discourse/app/components/site-header.js @@ -12,6 +12,8 @@ import { isTesting } from "discourse-common/config/environment"; import discourseLater from "discourse-common/lib/later"; import { bind, observes } from "discourse-common/utils/decorators"; +let _menuPanelClassesToForceDropdown = []; + const SiteHeaderComponent = MountWidget.extend( Docking, RerenderOnDoNotDisturbChange, @@ -351,12 +353,17 @@ const SiteHeaderComponent = MountWidget.extend( return; } - const viewMode = + let viewMode = this.site.mobileView || this.site.narrowDesktopView ? "slide-in" : "drop-down"; menuPanels.forEach((panel) => { + if (menuPanelContainsClass(panel)) { + viewMode = "drop-down"; + this._animate = false; + } + const headerCloak = document.querySelector(".header-cloak"); panel.classList.remove("drop-down"); @@ -408,6 +415,31 @@ const SiteHeaderComponent = MountWidget.extend( } ); +function menuPanelContainsClass(menuPanel) { + if (!_menuPanelClassesToForceDropdown) { + return false; + } + + // Check if any of the classNames are present in the node's classList + for (let className of _menuPanelClassesToForceDropdown) { + if (menuPanel.classList.contains(className)) { + // Found a matching class + return true; + } + } + + // No matching class found + return false; +} + +export function forceDropdownForMenuPanels(classNames) { + // If classNames is a string, convert it to an array + if (typeof classNames === "string") { + classNames = [classNames]; + } + return _menuPanelClassesToForceDropdown.push(...classNames); +} + export default SiteHeaderComponent.extend({ classNames: ["d-header-wrap"], classNameBindings: ["site.mobileView::drop-down-mode"], diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.js b/app/assets/javascripts/discourse/app/lib/plugin-api.js index 70af87b8690..a68c5b5b83a 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.js +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.js @@ -24,6 +24,7 @@ import { } from "discourse/components/search-menu/results/random-quick-tip"; import { addOnKeyUpCallback } from "discourse/components/search-menu/search-term"; import { REFRESH_COUNTS_APP_EVENT_NAME as REFRESH_USER_SIDEBAR_CATEGORIES_SECTION_COUNTS_APP_EVENT_NAME } from "discourse/components/sidebar/user/categories-section"; +import { forceDropdownForMenuPanels } from "discourse/components/site-header"; import { addTopicTitleDecorator } from "discourse/components/topic-title"; import { addUserMenuProfileTabItem } from "discourse/components/user-menu/profile-tab-content"; import { addDiscoveryQueryParam } from "discourse/controllers/discovery/list"; @@ -141,7 +142,7 @@ import { modifySelectKit } from "select-kit/mixins/plugin-api"; // docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version // using the format described at https://keepachangelog.com/en/1.0.0/. -export const PLUGIN_API_VERSION = "1.16.0"; +export const PLUGIN_API_VERSION = "1.17.0"; // This helper prevents us from applying the same `modifyClass` over and over in test mode. function canModify(klass, type, resolverName, changes) { @@ -1834,6 +1835,22 @@ class PluginApi { addGlimmerSearchSuggestion(value); } + /** + * Force a given menu panel (search-menu, user-menu) to be displayed as dropdown if ANY of the passed `classNames` are included in the `classList` of a menu panel. + * This can be useful for plugins as the default behavior is to add a 'slide-in' behavior to a menu panel if you are viewing on a small screen. eg. mobile. + * Sometimes when we are rendering the menu panel in a non-standard way we don't want this behavior and want to force the menu panel to be displayed as a dropdown. + * + * The `classNames` param can be passed as a single string or an array of strings. This way you can disable the 'slide-in' behavior for multiple menu panels. + * + * ``` + * api.forceDropdownForMenuPanels(["search-menu-panel", "user-menu"]); + * ``` + * + */ + forceDropdownForMenuPanels(classNames) { + forceDropdownForMenuPanels(classNames); + } + /** * Download calendar modal which allow to pick between ICS and Google Calendar. Optionally, recurrence rule can be specified - https://datatracker.ietf.org/doc/html/rfc5545#section-3.3.10 * diff --git a/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md b/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md index 0d651279dfe..e449599c7cf 100644 --- a/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md +++ b/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md @@ -7,6 +7,12 @@ in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.17.0] - 2023-11-30 + +### Added + +- Introduces `forceDropdownAnimationForMenuPanels` API for forcing one or many Menu Panels (search-menu, user-menu, etc) to be rendered as a dropdown. This can be useful for plugins as the default behavior is to add a 'slide-in' behavior to a menu panel if you are viewing on a small screen. eg. mobile. + ## [1.16.0] - 2023-11-17 ### Added