diff --git a/cypress/integration/custom_buttons.js b/cypress/integration/custom_buttons.js index ddbd19731a..fd93613900 100644 --- a/cypress/integration/custom_buttons.js +++ b/cypress/integration/custom_buttons.js @@ -41,6 +41,8 @@ describe( before(() => { cy.login(); cy.visit(`/app/note/new`); + // close the sidebar cause default is expanded + cy.get(".body-sidebar .collapse-sidebar-link").click(); }); test_button_names.forEach((button_name) => { diff --git a/frappe/public/icons/timeless/icons.svg b/frappe/public/icons/timeless/icons.svg index 3cf8477143..d6c409aada 100644 --- a/frappe/public/icons/timeless/icons.svg +++ b/frappe/public/icons/timeless/icons.svg @@ -417,8 +417,7 @@ Tip: use lucide.svg in /icons for all downloaded icons - + @@ -545,8 +544,7 @@ Tip: use lucide.svg in /icons for all downloaded icons - + @@ -876,7 +874,6 @@ Tip: use lucide.svg in /icons for all downloaded icons - diff --git a/frappe/public/js/frappe/ui/apps_switcher.js b/frappe/public/js/frappe/ui/apps_switcher.js index adb22a6982..0f346cc3db 100644 --- a/frappe/public/js/frappe/ui/apps_switcher.js +++ b/frappe/public/js/frappe/ui/apps_switcher.js @@ -3,22 +3,17 @@ frappe.ui.AppsSwitcher = class AppsSwitcher { this.drop_down_state = false; this.sidebar_wrapper = sidebar.wrapper; this.sidebar = sidebar; + this.app_switcher = $(sidebar.app_switcher_dropdown[0]); this.setup_app_switcher(); + this.set_hover(); } setup_app_switcher() { this.app_switcher_menu = $(".app-switcher-menu"); $(".app-switcher-dropdown").on("click", () => { + this.set_active(); this.app_switcher_menu.toggleClass("hidden"); }); - - // hover out of the sidebar move this to sidebar.js - this.sidebar_wrapper.find(".body-sidebar").on("mouseleave", () => { - this.app_switcher_menu.addClass("hidden"); - - // hide any expanded menus as they leave a blank space in the sidebar - this.sidebar_wrapper.find(".drop-icon[data-state='opened'").click(); - }); } create_app_data_map() { frappe.boot.app_data_map = {}; @@ -152,4 +147,23 @@ frappe.ui.AppsSwitcher = class AppsSwitcher { // re-render the sidebar frappe.app.sidebar.make_sidebar(); } + set_hover() { + this.app_switcher.on("mouseover", function (event) { + if ($(this).hasClass("active-sidebar")) return; + $(this).addClass("hover"); + if (!this.sidebar.sidebar_expanded) { + $(this).removeClass("hover"); + } + }); + + this.app_switcher.on("mouseleave", function () { + $(this).removeClass("hover"); + }); + } + set_active() { + this.app_switcher.toggleClass("active-sidebar"); + if (!this.sidebar.sidebar_expanded) { + this.app_switcher.removeClass("active-sidebar"); + } + } }; diff --git a/frappe/public/js/frappe/ui/sidebar.js b/frappe/public/js/frappe/ui/sidebar.js index 6d2303e2a7..b2c0e3a332 100644 --- a/frappe/public/js/frappe/ui/sidebar.js +++ b/frappe/public/js/frappe/ui/sidebar.js @@ -1,6 +1,7 @@ frappe.ui.Sidebar = class Sidebar { constructor() { this.items = {}; + this.child_items = []; this.sidebar_expanded = false; if (!frappe.boot.setup_complete) { @@ -79,16 +80,65 @@ frappe.ui.Sidebar = class Sidebar { } set_active_workspace_item() { - if (this.is_route_in_sidebar(decodeURIComponent(window.location.pathname))) { + if (!frappe.get_route()) return; + if (frappe.get_route()[0] == "") return; + let current_route = frappe.get_route(); + let doctype = frappe.get_route()[1]; + let current_item = doctype; + if (current_route[0] != "Workspaces") { + let meta_info = frappe.get_meta(doctype); + if (meta_info) { + let active_workspace = meta_info.module; + if (meta_info.__workspaces) { + active_workspace = meta_info.__workspaces[0]; + } + current_item = active_workspace; + } + } + if (this.is_route_in_sidebar(current_item)) { this.active_item.addClass("active-sidebar"); } + if (this.active_item) { + if (this.is_nested_item(this.active_item.parent())) { + let current_item = this.active_item.parent(); + this.expand_parent_item(current_item); + } + } + } + expand_parent_item(item) { + let parent_title = item.attr("item-parent"); + if (!parent_title) return; + + let parent = this.get_sidebar_item(parent_title); + $($(parent).children()[1]).removeClass("hidden"); + if (parent) { + if (this.is_nested_item($(parent))) { + this.expand_parent_item($(parent)); + } + } + } + is_nested_item(item) { + if (item.attr("item-parent")) { + return true; + } else { + return false; + } } - is_route_in_sidebar(route_name) { + get_sidebar_item(name) { + let sidebar_item = ""; + $(".sidebar-item-container").each(function () { + if ($(this).attr("item-name") == name) { + sidebar_item = this; + } + }); + return sidebar_item; + } + is_route_in_sidebar(active_module) { let match = false; const that = this; $(".item-anchor").each(function () { - if ($(this).attr("href") == route_name) { + if ($(this).attr("title") == active_module) { match = true; if (that.active_item) that.active_item.removeClass("active-sidebar"); that.active_item = $(this).parent(); @@ -126,12 +176,19 @@ frappe.ui.Sidebar = class Sidebar { this.make_sidebar(); } this.set_hover(); + this.set_sidebar_state(); + if (!this.sidebar_expanded) this.close_children_item(); + } + set_sidebar_state() { + this.sidebar_expanded = true; if (localStorage.getItem("sidebar-expanded") !== null) { this.sidebar_expanded = JSON.parse(localStorage.getItem("sidebar-expanded")); - this.expand_sidebar(); } + if (frappe.is_mobile()) { + this.sidebar_expanded = false; + } + this.expand_sidebar(); } - make_sidebar() { if (this.wrapper.find(".standard-sidebar-section")[0]) { this.wrapper.find(".standard-sidebar-section").remove(); @@ -242,6 +299,7 @@ frappe.ui.Sidebar = class Sidebar { let child_container = $item_container.find(".sidebar-child-item"); child_container.addClass("hidden"); this.prepare_sidebar(child_items, child_container, $item_container); + this.child_items.push(child_container); } $item_container.appendTo(container); @@ -394,10 +452,18 @@ frappe.ui.Sidebar = class Sidebar { close_sidebar() { this.sidebar_expanded = false; this.expand_sidebar(); + this.close_children_item(); } open_sidebar() { this.sidebar_expanded = true; this.expand_sidebar(); + this.set_active_workspace_item(); + } + + close_children_item() { + this.child_items.forEach((i) => { + i.addClass("hidden"); + }); } reload() { @@ -406,4 +472,9 @@ frappe.ui.Sidebar = class Sidebar { this.setup_pages(); }); } + set_height() { + $(".body-sidebar").css("height", window.innerHeight + "px"); + $(".overlay").css("height", window.innerHeight + "px"); + document.body.style.overflow = "hidden"; + } }; diff --git a/frappe/public/js/frappe/ui/toolbar/toolbar.js b/frappe/public/js/frappe/ui/toolbar/toolbar.js index 9a96f1ed21..ba1c163fc7 100644 --- a/frappe/public/js/frappe/ui/toolbar/toolbar.js +++ b/frappe/public/js/frappe/ui/toolbar/toolbar.js @@ -29,6 +29,7 @@ frappe.ui.toolbar.Toolbar = class { this.bind_events(); $(document).trigger("toolbar_setup"); $(".navbar-brand .app-logo").on("click", () => { + frappe.app.sidebar.set_height(); frappe.app.sidebar.toggle_sidebar(); }); } diff --git a/frappe/public/scss/common/icons.scss b/frappe/public/scss/common/icons.scss index bef46bd625..878c9590c1 100644 --- a/frappe/public/scss/common/icons.scss +++ b/frappe/public/scss/common/icons.scss @@ -9,7 +9,9 @@ background-position: 50% 50%; fill: var(--icon-fill); stroke: var(--icon-stroke); - stroke-width: 1.25px; + stroke-width: 1.5px; + stroke-linecap: round; + stroke-linejoin: round; } .es-icon { diff --git a/frappe/public/scss/desk/sidebar.scss b/frappe/public/scss/desk/sidebar.scss index 5390aa9f83..a667979871 100644 --- a/frappe/public/scss/desk/sidebar.scss +++ b/frappe/public/scss/desk/sidebar.scss @@ -6,6 +6,7 @@ --surface-modal: rgba(255, 255, 255, 1); --divider-color: rgba(237, 237, 237, 1); --sidebar-width: 220px; + --left-sidebar-width: 240px; } [data-theme="dark"] { --sidebar-hover-color: rgba(43, 43, 43, 1); @@ -122,7 +123,7 @@ body { } .sidebar-items { - width: 204px; + width: 224px; padding-left: 1px; padding-right: 1px; width: 100%; @@ -172,7 +173,7 @@ body { } svg { - margin: -1px; + margin: -2px; } } @@ -248,17 +249,17 @@ body { .body-sidebar { // make it an overlay on hover position: absolute; - width: var(--sidebar-width); + width: var(--left-sidebar-width); .app-switcher-dropdown { - width: 204px; + width: 224px; left: 0px; - padding: 2px 0px 2px 3px; + padding: 3px; } .body-sidebar-top { - width: 204px; + width: 224px; overflow-y: hidden; .app-switcher-dropdown { - width: 204px; + width: 224px; } } .sidebar-item-container { @@ -279,7 +280,7 @@ body { visibility: visible; } .body-sidebar-bottom { - width: var(--sidebar-width); + width: 224px; position: static; } } @@ -287,7 +288,7 @@ body { // show placeholder so that main section remains static .body-sidebar-placeholder { display: flex; - width: var(--sidebar-width); + width: var(--left-sidebar-width); } } @@ -310,7 +311,7 @@ body { position: relative; .body-sidebar { padding: 8px 8px 10px 8px; - width: var(--sidebar-width); + width: var(--left-sidebar-width); height: 100%; position: absolute; bottom: 0; @@ -319,10 +320,10 @@ body { .overlay { display: block; position: absolute; - width: 100vw; + width: calc(100vw - 240px); height: 100%; z-index: 1021; - left: var(--sidebar-width); + left: var(--left-sidebar-width); overflow: auto; background-color: rgba(128, 128, 128, 0.5); } @@ -347,15 +348,15 @@ body { text-decoration: none; width: 38px; height: 38px; - left: -2px; padding: 3px; + margin-left: -2px; .standard-sidebar-item { padding-top: 1px; padding-bottom: 1px; .d-flex { width: 161px; } - gap: 8px; + gap: 30px; } .sidebar-item-control { margin: 2px; @@ -365,15 +366,13 @@ body { .app-switcher-menu { position: absolute; - top: 44px; - left: 7px; - width: 205px; + top: 50px; + left: 9px; + width: 220px; padding: 6px; border-radius: var(--border-radius-lg); background: var(--surface-modal); - box-shadow: 0px 10px 24px -3px rgba(0, 0, 0, 0.1); - // box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.05); - // box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.2); + box-shadow: var(--shadow-xl); z-index: 1; } @@ -421,7 +420,7 @@ body { .active-sidebar { background: var(--sidebar-active-color); - box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.1); + box-shadow: var(--shadow-sm); border-radius: 8px; } .overlay {