Merge pull request #35841 from iamejaaz/mobile-nav-merge

feat(mobile): merge navbar into one
This commit is contained in:
Ejaaz Khan 2026-01-12 12:21:53 +05:30 committed by GitHub
commit 4d114e79f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 84 additions and 85 deletions

View file

@ -352,6 +352,7 @@ frappe.ui.form.Toolbar = class Toolbar {
// Print
this.add_discard();
this.add_print();
this.add_open_sidebar();
this.add_email();
this.add_rename();
this.add_reload();
@ -484,6 +485,19 @@ frappe.ui.form.Toolbar = class Toolbar {
}
}
add_open_sidebar() {
if (this.page.hide_sidebar) {
return;
}
this.page.add_menu_item(
__("Open Sidebar"),
() => {
this.setup_sidebar_toggle(this.frm.sidebar.sidebar.parent());
},
true
);
}
add_reload() {
// reload
this.page.add_menu_item(
@ -894,6 +908,36 @@ frappe.ui.form.Toolbar = class Toolbar {
dialog.show();
}
setup_sidebar_toggle(sidebar_wrapper) {
console.log(sidebar_wrapper);
if (frappe.utils.is_xs() || frappe.utils.is_sm()) {
this.setup_overlay_sidebar(sidebar_wrapper);
} else {
sidebar_wrapper.toggle();
}
$(document.body).trigger("toggleSidebar");
}
setup_overlay_sidebar(sidebar_wrapper) {
sidebar_wrapper.find(".close-sidebar").remove();
let overlay_sidebar = sidebar_wrapper.find(".overlay-sidebar").addClass("opened");
$('<div class="close-sidebar">').hide().appendTo(sidebar_wrapper).fadeIn();
let scroll_container = $("html").css("overflow-y", "hidden");
sidebar_wrapper.find(".close-sidebar").on("click", (e) => this.close_sidebar(e));
sidebar_wrapper.on("click", "button:not(.dropdown-toggle)", (e) => this.close_sidebar(e));
this.close_sidebar = () => {
scroll_container.css("overflow-y", "");
sidebar_wrapper.find("div.close-sidebar").fadeOut(() => {
overlay_sidebar
.removeClass("opened")
.find(".dropdown-toggle")
.removeClass("text-muted");
});
};
}
follow() {
let is_followed = this.frm.get_docinfo().is_document_followed;
frappe

View file

@ -435,10 +435,7 @@ frappe.views.BaseList = class BaseList {
this.$result[0].style.removeProperty("height");
// place it at the footer of the page
const resultContainerHeight =
window.innerHeight -
this.$result.get(0).offsetTop -
this.$paging_area.get(0).offsetHeight;
const resultContainerHeight = window.innerHeight - this.$paging_area.get(0).offsetHeight;
this.$result.parent(".result-container").css({
height: resultContainerHeight - (frappe.is_mobile() ? 100 : 0) + "px",
});

View file

@ -2,7 +2,7 @@
<div class="container">
<div class="row flex-nowrap align-center page-head-content justify-between">
<div class="page-title">
<button class="btn-reset sidebar-toggle-btn">
<button class="btn-reset sidebar-toggle-btn navbar-brand">
<svg class="es-icon icon-md sidebar-toggle-placeholder">
<use href="#es-line-align-justify"></use>
</svg>
@ -24,7 +24,7 @@
<span class="indicator-pill whitespace-nowrap"></span>
</div>
</div>
<div class="flex col page-actions justify-content-end">
<div class="flex col page-actions justify-content-end {% if frappe.is_mobile() %} pr-0 {% endif %}">
<!-- buttons -->
<div class="filters flex"></div>
<div class="custom-actions hide hidden-xs hidden-md"></div>
@ -60,6 +60,18 @@
<button class="btn btn-primary btn-sm hide primary-action"></button>
</div>
</div>
{% if frappe.is_mobile() %}
<div class="search-bar text-muted hidden ml-2 mr-3">
<div
class="navbar-modal-search-mobile"
placeholder="Search for type a command"
>
<span class="search-icon">
<svg class="icon icon-sm"><use href="#icon-search"></use></svg>
</span>
</div>
</div>
{% endif %}
</div>
</div>
</div>

View file

@ -44,7 +44,15 @@ frappe.ui.Page = class Page {
this.wrapper = $(this.parent);
this.add_main_section();
this.setup_scroll_handler();
this.setup_sidebar_toggle();
this.setup_main_sidebar_toggle();
this.setup_mobile_awesomebar();
}
setup_mobile_awesomebar() {
if (frappe.boot.desk_settings.search_bar && frappe.is_mobile()) {
let awesome_bar = new frappe.search.AwesomeBar();
awesome_bar.setup(".navbar-modal-search-mobile");
}
}
setup_scroll_handler() {
@ -195,66 +203,6 @@ frappe.ui.Page = class Page {
.appendTo(this.sidebar);
}
setup_sidebar_toggle() {
let sidebar_toggle = $(".page-head").find(".sidebar-toggle-btn");
let sidebar_wrapper = this.wrapper.find(".layout-side-section");
if (this.disable_sidebar_toggle || !sidebar_wrapper.length) {
sidebar_toggle.last().remove();
this.wrapper.addClass("no-list-sidebar");
} else {
if (!frappe.is_mobile()) {
sidebar_toggle.attr("title", __("Toggle Sidebar"));
}
sidebar_toggle.attr("aria-label", __("Toggle Sidebar"));
sidebar_toggle.tooltip({
delay: { show: 600, hide: 100 },
trigger: "hover",
});
sidebar_toggle.click(() => {
if (frappe.utils.is_xs() || frappe.utils.is_sm()) {
this.setup_overlay_sidebar();
} else {
sidebar_wrapper.toggle();
}
$(document.body).trigger("toggleSidebar");
this.update_sidebar_icon();
});
}
}
setup_overlay_sidebar() {
this.sidebar.find(".close-sidebar").remove();
let overlay_sidebar = this.sidebar.find(".overlay-sidebar").addClass("opened");
$('<div class="close-sidebar">').hide().appendTo(this.sidebar).fadeIn();
let scroll_container = $("html").css("overflow-y", "hidden");
this.sidebar.find(".close-sidebar").on("click", (e) => this.close_sidebar(e));
this.sidebar.on("click", "button:not(.dropdown-toggle)", (e) => this.close_sidebar(e));
this.close_sidebar = () => {
scroll_container.css("overflow-y", "");
this.sidebar.find("div.close-sidebar").fadeOut(() => {
overlay_sidebar
.removeClass("opened")
.find(".dropdown-toggle")
.removeClass("text-muted");
});
};
}
update_sidebar_icon() {
let sidebar_toggle = $(".page-head").find(".sidebar-toggle-btn");
let sidebar_toggle_icon = sidebar_toggle.find(".sidebar-toggle-icon");
let sidebar_wrapper = this.wrapper.find(".layout-side-section");
let is_sidebar_visible = $(sidebar_wrapper).is(":visible");
sidebar_toggle_icon.html(
frappe.utils.icon(
is_sidebar_visible ? "es-line-sidebar-collapse" : "es-line-sidebar-expand",
"md"
)
);
}
set_indicator(label, color) {
this.clear_indicator().removeClass("hide").html(`<span>${label}</span>`).addClass(color);
}
@ -284,6 +232,14 @@ frappe.ui.Page = class Page {
return button;
}
setup_main_sidebar_toggle() {
$(".sidebar-toggle-btn.navbar-brand").on("click", (event) => {
frappe.app.sidebar.set_height();
frappe.app.sidebar.toggle_width();
frappe.app.sidebar.prevent_scroll();
});
}
clear_indicator() {
return this.indicator
.removeClass()

View file

@ -1,10 +1,7 @@
<div class="sticky-top">
{% if (frappe.boot.read_only || frappe.boot.user.impersonated_by || frappe.is_mobile()) { %}
{% if (frappe.boot.read_only || frappe.boot.user.impersonated_by) { %}
<header class="navbar navbar-expand" role="navigation">
<div class="container">
<a class="navbar-brand navbar-home">
<img class="app-logo" src="{{ frappe.boot.app_data[0].app_logo_url }}" alt="{{ __(" App Logo") }}">
</a>
<div class="collapse navbar-collapse justify-content-end">
{% if (frappe.boot.read_only) { %}
<span class="indicator-pill yellow no-indicator-dot read-only-banner" title="{%= __("Your site is undergoing maintenance or being updated.") %}">
@ -16,19 +13,6 @@
{%= __("Impersonating {0}", [frappe.boot.user.name]) %}
</span>
{% } %}
{% if frappe.is_mobile() %}
<div class="search-bar text-muted hidden">
<div
id="navbar-modal-search"
class="navbar-modal-search-mobile"
placeholder="Search for type a command"
>
<span class="search-icon">
<svg class="icon icon-sm"><use href="#icon-search"></use></svg>
</span>
</div>
</div>
{% endif %}
</div>
</div>
</header>

View file

@ -33,7 +33,6 @@ frappe.ui.toolbar.Toolbar = class {
this.bind_events();
$(document).trigger("toolbar_setup");
this.navbar = $(".navbar-brand");
this.app_logo = this.navbar.find(".app-logo");
this.bind_click();
}
change_toolbar() {
@ -54,6 +53,7 @@ frappe.ui.toolbar.Toolbar = class {
frappe.app.sidebar.prevent_scroll();
});
}
bind_events() {
// clear all custom menus on page change
$(document).on("page-change", function () {

View file

@ -1,3 +1,9 @@
body:not([data-route^="Form"]) {
.layout-side-section {
display: none;
}
}
.page-title {
display: flex;
align-items: center;