Merge pull request #28967 from sokumon/better-sidebar

fix: improved sidebar
This commit is contained in:
sokumon 2025-01-01 12:23:31 +05:30 committed by GitHub
commit 171eab1387
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 434 additions and 225 deletions

View file

@ -973,4 +973,12 @@ Tip: use lucide.svg in /icons for all downloaded icons
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 0a1 1 0 011 1v10a3 3 0 003 3h12a2 2 0 012 2v26a4 4 0 01-4 4H4a4 4 0 01-4-4V3a3 3 0 013-3h16zM8 37a1 1 0 100 2h21a1 1 0 100-2H8zm-1-7a1 1 0 011-1h21a1 1 0 110 2H8a1 1 0 01-1-1zm1-9a1 1 0 100 2h6a1 1 0 100-2H8z"></path>
</g>
</symbol>
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="icon-arrow-right-to-line">
<path d="M17 12H3" /> <path d="m11 18 6-6-6-6" /> <path d="M21 5v14" />
</symbol>
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="icon-arrow-left-to-line">
<path d="M3 19V5" /> <path d="m13 6-6 6 6 6" /> <path d="M7 12h14" />
</symbol>
</svg>

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-settings"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>

After

Width:  |  Height:  |  Size: 826 B

View file

@ -11,6 +11,8 @@ import "./frappe/ui/keyboard.js";
import "./frappe/ui/colors.js";
import "./frappe/ui/sidebar.html";
import "./frappe/ui/sidebar.js";
import "./frappe/ui/apps_switcher.js";
import "./frappe/ui/apps_switcher.html";
import "./frappe/ui/link_preview.js";
import "./frappe/request.js";

View file

@ -140,6 +140,7 @@ frappe.router = {
this.current_sub_path = sub_path;
this.current_route = await this.parse();
this.set_history(sub_path);
this.set_active_sidebar_item();
this.render();
this.set_title(sub_path);
this.trigger("change");
@ -162,7 +163,6 @@ frappe.router = {
// /app/user/user-001 = ["Form", "User", "user-001"]
// /app/user/user-001 = ["Form", "User", "user-001"]
// /app/event/view/calendar/default = ["List", "Event", "Calendar", "Default"]
if (frappe.workspaces[route[0]]) {
// public workspace
route = ["Workspaces", frappe.workspaces[route[0]].name];
@ -280,6 +280,10 @@ frappe.router = {
frappe.ui.hide_open_dialog();
},
async set_active_sidebar_item() {
frappe.app.sidebar.set_active_workspace_item();
},
render() {
if (this.current_route[0]) {
this.render_page();

View file

@ -0,0 +1,23 @@
<a class="app-switcher-dropdown" style="text-decoration: none;">
<div class="standard-sidebar-item">
<div class="d-flex">
<div class="sidebar-item-icon app-logo-container">
<img class="app-logo"
src="{%= app_logo_url %}" alt="{%= ("App Logo") %}">
</div>
<div class="sidebar-item-label app-title" style="margin-left: 10px; margin-top: 1px">
{%= app_title %}
</div>
</div>
<div class="sidebar-item-control">
<button class="btn-reset drop-icon show-in-edit-mode">
<svg class="es-icon es-line icon-sm" style="display: block;margin:auto;" aria-hidden="true">
<use class="" href="#es-line-down"></use>
</svg>
</button>
</div>
</div>
</a>
<div class="app-switcher-menu hidden" role="menu">
</div>

View file

@ -0,0 +1,154 @@
frappe.ui.AppsSwitcher = class AppsSwitcher {
constructor(sidebar_wrapper) {
this.drop_down_state = false;
this.sidebar_wrapper = sidebar_wrapper;
this.setup_app_switcher();
}
setup_app_switcher() {
this.app_switcher_menu = $(".app-switcher-menu");
$(".app-switcher-dropdown").on("click", () => {
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 = {};
for (var app of frappe.boot.app_data) {
frappe.boot.app_data_map[app.app_name] = app;
if (app.workspaces?.length) {
this.add_app_item(app);
}
}
}
populate_apps_menu() {
this.add_private_app();
this.add_website_select();
this.add_settings_select();
this.setup_select_app();
}
add_app_item(app) {
$(`<div class="app-item" data-app-name="${app.app_name}"
data-app-route="${app.app_route}">
<a>
<div class="sidebar-item-icon">
<img
class="app-logo"
src="${app.app_logo_url}"
alt="${__("App Logo")}"
>
</div>
<span class="app-item-title">${app.app_title}</span>
</a>
</div>`).appendTo(this.app_switcher_menu);
}
add_private_app() {
let private_pages = frappe.app.sidebar.all_pages.filter((p) => p.public === 0);
if (private_pages.length === 0) return;
const app = {
app_name: "private",
app_title: __("My Workspaces"),
app_route: "/app/private",
app_logo_url: "/assets/frappe/images/frappe-framework-logo.svg",
workspaces: private_pages,
};
frappe.boot.app_data_map["private"] = app;
$(`<div class="divider"></div>`).prependTo(this.app_switcher_menu);
$(`<div class="app-item" data-app-name="${app.app_name}"
data-app-route="${app.app_route}">
<a>
<div class="sidebar-item-icon">
<img
class="app-logo"
src="${app.app_logo_url}"
alt="${__("App Logo")}"
>
</div>
<span class="app-item-title">${app.app_title}</span>
</a>
</div>`).prependTo(this.app_switcher_menu);
}
setup_select_app() {
this.app_switcher_menu.find(".app-item").on("click", (e) => {
let item = $(e.delegateTarget);
let route = item.attr("data-app-route");
this.app_switcher_menu.toggleClass("hidden");
if (item.attr("data-app-name") == "settings") {
frappe.quick_edit("Workspace Settings");
return;
}
if (route.startsWith("/app/private")) {
this.set_current_app("private");
let ws = Object.values(frappe.workspace_map).find((ws) => ws.public === 0);
route += "/" + frappe.router.slug(ws.title);
frappe.set_route(route);
} else if (route.startsWith("/app")) {
frappe.set_route(route);
this.set_current_app(item.attr("data-app-name"));
} else {
// new page
window.open(route);
}
});
}
// refactor them into one single function
add_website_select() {
$(`<div class="divider"></div>`).appendTo(this.app_switcher_menu);
this.add_app_item(
{
app_name: "website",
app_title: __("Website"),
app_route: "/",
app_logo_url: "/assets/frappe/images/web.svg",
},
this.app_switcher_menu
);
}
add_settings_select() {
$(`<div class="divider"></div>`).appendTo(this.app_switcher_menu);
this.add_app_item({
app_name: "settings",
app_title: __("Settings"),
app_logo_url: "/assets/frappe/images/settings-gear.svg",
});
let settings_item = this.app_switcher_menu.children().last();
}
set_current_app(app) {
if (!app) {
console.warn("set_current_app: app not defined");
return;
}
let app_data = frappe.boot.app_data_map[app] || frappe.boot.app_data_map["frappe"];
this.sidebar_wrapper
.find(".app-switcher-dropdown .sidebar-item-icon img")
.attr("src", app_data.app_logo_url);
this.sidebar_wrapper
.find(".app-switcher-dropdown .sidebar-item-label")
.html(app_data.app_title);
$(".navbar-brand .app-logo").attr("src", app_data.app_logo_url);
if (frappe.current_app === app) return;
frappe.current_app = app;
// re-render the sidebar
frappe.app.sidebar.make_sidebar();
}
};

View file

@ -2,41 +2,13 @@
<div class="body-sidebar-placeholder"></div>
<div class="body-sidebar">
<div class="body-sidebar-top">
<a class="app-switcher-dropdown"
style="text-decoration: none; width: 100%; position: relative;">
<div class="standard-sidebar-item">
<div class="d-flex">
<div class="sidebar-item-icon">
<img class="app-logo"
src="{%= app_logo_url %}" alt="{%= ("App Logo") %}">
</div>
<div class="sidebar-item-label" style="margin-left: 5px; margin-top: 1px">
{%= app_title %}
</div>
</div>
<div class="sidebar-item-control">
<button class="btn-reset drop-icon show-in-edit-mode">
<svg class="es-icon es-line icon-sm" style="" aria-hidden="true">
<use class="" href="#es-line-down"></use>
</svg>
</button>
</div>
</div>
</a>
<div class="app-switcher-menu hidden" role="menu">
</div>
<div class="sidebar-items">
</div>
</div>
<div class="body-sidebar-bottom">
<a class="edit-sidebar-link text-extra-muted hidden">
<svg class="icon icon-sm" style="margin-top: -2px;">
<use href="#icon-setting-gear"></use></svg> {%= __("Settings") %}</a>
<a class="close-sidebar-link text-extra-muted hidden">
<svg class="icon icon-sm" style="margin-top: -2px;">
<use href="#icon-close"></use></svg> {%= __("Close") %}</a>
<a class="collapse-sidebar-link">
<svg class="icon" style="margin-top: -2px">
<use href="#icon-arrow-right-to-line"></use></svg> {%= __("Collapse") %}</a>
</div>
</div>

View file

@ -1,8 +1,7 @@
frappe.provide("frappe.ui");
frappe.ui.Sidebar = class Sidebar {
constructor() {
this.items = {};
this.sidebar_expanded = false;
if (!frappe.boot.setup_complete) {
// no sidebar if setup is not complete
@ -35,25 +34,34 @@ frappe.ui.Sidebar = class Sidebar {
make_dom() {
this.set_default_app();
this.wrapper = $(
frappe.render_template("sidebar", {
this.wrapper = $(frappe.render_template("sidebar")).prependTo("body");
this.app_switcher_dropdown = $(
frappe.render_template("apps_switcher", {
app_logo_url: frappe.boot.app_data[0].app_logo_url,
app_title: __(frappe.boot.app_data[0].app_title),
})
).prependTo("body");
).prependTo(this.wrapper.find(".body-sidebar"));
this.$sidebar = this.wrapper.find(".sidebar-items");
if (this.has_access) {
this.wrapper
.find(".body-sidebar .edit-sidebar-link")
.removeClass("hidden")
.on("click", () => {
frappe.quick_edit("Workspace Settings");
});
}
this.wrapper.find(".body-sidebar .collapse-sidebar-link").on("click", () => {
this.toggle_sidebar();
});
this.setup_app_switcher();
this.apps_switcher = new frappe.ui.AppsSwitcher(this.wrapper);
this.apps_switcher.create_app_data_map();
}
set_hover() {
$(".standard-sidebar-item > .item-anchor").on("mouseover", function (event) {
if ($(this).parent().hasClass("active-sidebar")) return;
$(this).parent().addClass("hover");
});
$(".standard-sidebar-item > .item-anchor").on("mouseleave", function () {
$(this).parent().removeClass("hover");
});
}
set_all_pages() {
@ -69,137 +77,29 @@ frappe.ui.Sidebar = class Sidebar {
frappe.current_app = frappe.boot.app_data[0].app_name;
}
setup_app_switcher() {
let app_switcher_menu = $(".app-switcher-menu");
$(".app-switcher-dropdown").on("click", () => {
app_switcher_menu.toggleClass("hidden");
});
// hover out of the sidebar
this.wrapper.find(".body-sidebar").on("mouseleave", () => {
app_switcher_menu.addClass("hidden");
// hide any expanded menus as they leave a blank space in the sidebar
this.wrapper.find(".drop-icon[data-state='opened'").click();
});
frappe.boot.app_data_map = {};
this.add_private_app(app_switcher_menu);
for (var app of frappe.boot.app_data) {
frappe.boot.app_data_map[app.app_name] = app;
if (app.workspaces?.length) {
this.add_app_item(app, app_switcher_menu);
}
set_active_workspace_item() {
if (this.is_route_in_sidebar(decodeURIComponent(window.location.pathname))) {
this.active_item.addClass("active-sidebar");
}
this.add_website_select(app_switcher_menu);
this.setup_select_app(app_switcher_menu);
}
add_app_item(app, app_switcher_menu) {
$(`<div class="app-item" data-app-name="${app.app_name}"
data-app-route="${app.app_route}">
<a>
<div class="sidebar-item-icon">
<img
class="app-logo"
src="${app.app_logo_url}"
alt="${__("App Logo")}"
>
</div>
<span class="app-item-title">${app.app_title}</span>
</a>
</div>`).appendTo(app_switcher_menu);
}
add_private_app(app_switcher_menu) {
let private_pages = this.all_pages.filter((p) => p.public === 0);
if (private_pages.length === 0) return;
const app = {
app_name: "private",
app_title: __("My Workspaces"),
app_route: "/app/private",
app_logo_url: "/assets/frappe/images/frappe-framework-logo.svg",
workspaces: private_pages,
};
frappe.boot.app_data_map["private"] = app;
$(`<div class="divider"></div>`).prependTo(app_switcher_menu);
$(`<div class="app-item" data-app-name="${app.app_name}"
data-app-route="${app.app_route}">
<a>
<div class="sidebar-item-icon">
<img
class="app-logo"
src="${app.app_logo_url}"
alt="${__("App Logo")}"
>
</div>
<span class="app-item-title">${app.app_title}</span>
</a>
</div>`).prependTo(app_switcher_menu);
}
setup_select_app(app_switcher_menu) {
app_switcher_menu.find(".app-item").on("click", (e) => {
let item = $(e.delegateTarget);
let route = item.attr("data-app-route");
app_switcher_menu.toggleClass("hidden");
if (route.startsWith("/app/private")) {
this.set_current_app("private");
let ws = Object.values(frappe.workspace_map).find((ws) => ws.public === 0);
route += "/" + frappe.router.slug(ws.title);
frappe.set_route(route);
} else if (route.startsWith("/app")) {
frappe.set_route(route);
this.set_current_app(item.attr("data-app-name"));
} else {
// new page
window.open(route);
is_route_in_sidebar(route_name) {
let match = false;
const that = this;
$(".item-anchor").each(function () {
if ($(this).attr("href") == route_name) {
match = true;
if (that.active_item) that.active_item.removeClass("active-sidebar");
that.active_item = $(this).parent();
// this exists the each loop
return false;
}
});
}
set_current_app(app) {
if (!app) {
console.warn("set_current_app: app not defined");
return;
}
let app_data = frappe.boot.app_data_map[app] || frappe.boot.app_data_map["frappe"];
this.wrapper
.find(".app-switcher-dropdown .sidebar-item-icon img")
.attr("src", app_data.app_logo_url);
this.wrapper.find(".app-switcher-dropdown .sidebar-item-label").html(app_data.app_title);
$(".navbar-brand .app-logo").attr("src", app_data.app_logo_url);
if (frappe.current_app === app) return;
frappe.current_app = app;
// re-render the sidebar
this.make_sidebar();
}
add_website_select(app_switcher_menu) {
$(`<div class="divider"></div>`).appendTo(app_switcher_menu);
this.add_app_item(
{
app_name: "website",
app_title: __("Website"),
app_route: "/",
app_logo_url: "/assets/frappe/images/web.svg",
},
app_switcher_menu
);
return match;
}
setup_pages() {
this.set_all_pages();
this.all_pages.forEach((page) => {
page.is_editable = !page.public || this.has_access;
if (typeof page.content == "string") {
@ -224,6 +124,11 @@ frappe.ui.Sidebar = class Sidebar {
}
this.make_sidebar();
}
this.set_hover();
if (localStorage.getItem("sidebar-expanded") !== null) {
this.sidebar_expanded = JSON.parse(localStorage.getItem("sidebar-expanded"));
this.expand_sidebar();
}
}
make_sidebar() {
@ -248,6 +153,7 @@ frappe.ui.Sidebar = class Sidebar {
this.wrapper.find(".selected")[0].scrollIntoView();
this.setup_sorting();
this.set_active_workspace_item();
}
build_sidebar_section(title, root_pages) {
@ -263,7 +169,7 @@ frappe.ui.Sidebar = class Sidebar {
$(".item-anchor").on("click", () => {
$(".list-sidebar.hidden-xs.hidden-sm").removeClass("opened");
$(".close-sidebar").css("display", "none");
// $(".close-sidebar").css("display", "none");
$("body").css("overflow", "auto");
});
@ -290,6 +196,30 @@ frappe.ui.Sidebar = class Sidebar {
}
child_container.appendTo(item_container);
}
toggle_sidebar() {
if (!this.sidebar_expanded) {
this.open_sidebar();
} else {
this.close_sidebar();
}
}
expand_sidebar() {
let direction;
if (this.sidebar_expanded) {
this.wrapper.addClass("expanded");
// this.sidebar_expanded = false
direction = "left";
} else {
this.wrapper.removeClass("expanded");
// this.sidebar_expanded = true
direction = "right";
}
localStorage.setItem("sidebar-expanded", this.sidebar_expanded);
this.wrapper
.find(".body-sidebar .collapse-sidebar-link")
.find("use")
.attr("href", `#icon-arrow-${direction}-to-line`);
}
append_item(item, container) {
let is_current_page = false;
@ -454,6 +384,15 @@ frappe.ui.Sidebar = class Sidebar {
}
}
close_sidebar() {
this.sidebar_expanded = false;
this.expand_sidebar();
}
open_sidebar() {
this.sidebar_expanded = true;
this.expand_sidebar();
}
reload() {
return frappe.workspace.get_pages().then((r) => {
frappe.boot.sidebar_pages = r;

View file

@ -29,18 +29,7 @@ frappe.ui.toolbar.Toolbar = class {
this.bind_events();
$(document).trigger("toolbar_setup");
$(".navbar-brand .app-logo").on("click", () => {
$(".body-sidebar-container")
.toggleClass("expanded")
.find(".edit-sidebar-link")
.addClass("hidden");
// show close link
$(".body-sidebar-container")
.find(".close-sidebar-link")
.removeClass("hidden")
.on("click", () => {
$(".body-sidebar-container").removeClass("expanded");
});
frappe.app.sidebar.toggle_sidebar();
});
}

View file

@ -46,7 +46,9 @@ frappe.views.Workspace = class Workspace {
this.prepare_container();
this.sidebar = frappe.app.sidebar;
this.app_switcher_menu = frappe.app.app_switcher_menu;
this.sidebar.setup_pages();
this.sidebar.apps_switcher.populate_apps_menu();
this.cached_pages = $.extend(true, {}, frappe.boot.sidebar_pages);
this.has_access = frappe.boot.sidebar_pages.has_access;
this.has_create_access = frappe.boot.sidebar_pages.has_create_access;
@ -232,10 +234,9 @@ frappe.views.Workspace = class Workspace {
this.prepare_editorjs();
$(".item-anchor").removeClass("disable-click");
$(".body-sidebar-container").removeClass("expanded");
this.remove_page_skeleton();
frappe.app.sidebar.set_current_app(app);
frappe.app.sidebar.apps_switcher.set_current_app(app);
this.wrapper.find(".workspace-title").html(__(this._page.title));
this.wrapper
.find(".workspace-icon")
@ -545,7 +546,7 @@ frappe.views.Workspace = class Workspace {
if (!frappe.boot.app_data_map["private"] && new_page.public === 0) {
let app_switcher_menu = $(".app-switcher-menu");
this.sidebar.add_private_app(app_switcher_menu);
this.sidebar.apps_switcher.add_private_app(app_switcher_menu);
}
resolve();
}

View file

@ -69,34 +69,47 @@ body {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100vh;
z-index: 1030;
padding: 8px 8px 10px 8px;
.body-sidebar-top {
flex: 1 1;
padding: 1px;
width: 34px;
display: flex;
align-items: flex-start;
flex-direction: column;
flex-wrap: nowrap;
gap: 2px;
justify-content: flex-start;
overflow: hidden;
padding: 13px;
position: static;
font-size: var(--text-base);
// transition: width 200ms;
}
.body-sidebar-bottom {
padding: 15px;
overflow: hidden;
padding: 7px;
width: 30px;
height: 30px;
// position: relative;
// top:10px;
}
.app-title {
font-weight: 500;
line-height: 16.1px;
}
.app-logo {
width: 23px;
width: 32px;
height: 32px;
}
.sidebar-items {
width: 204px;
padding-left: 1px;
padding-right: 1px;
width: 100%;
}
@ -107,6 +120,8 @@ body {
.standard-sidebar-section {
margin-bottom: var(--margin-xl);
display: flex;
flex-direction: column;
&:last-of-type {
margin-bottom: var(--margin-sm);
@ -115,72 +130,103 @@ body {
&:first-child {
margin-top: 24px;
}
.sidebar-item-container {
width: 30px;
margin-bottom: 2px;
}
}
.standard-sidebar-item {
display: flex;
line-height: 0px;
justify-content: space-between;
padding: 0px;
.sidebar-item-control {
display: none;
> * {
align-self: center;
margin-left: 3px;
box-shadow: none;
// margin-left: 3px;
// box-shadow: none;
}
.drop-icon {
padding: 0px 12px 0px 2px;
width: 28px;
height: 28px;
padding: 6px;
}
svg {
margin-right: 0;
margin-top: 3px;
margin: -1px;
}
}
.sidebar-item-label {
display: none;
font-size: var(--text-sm);
font-size: var(--text-md);
}
.item-anchor {
line-height: 10px;
display: flex;
overflow: hidden;
gap: 5px;
align-items: center;
padding: 3px 0px 3px 11px;
// padding: 3px 0px 3px 11px;
flex: 1;
&:hover {
text-decoration: none !important;
}
.sidebar-item-icon {
padding: 7px;
width: 30px;
height: 30px;
svg {
width: 16px;
height: 16px;
}
}
}
}
.edit-sidebar-link {
display: none;
.collapse-sidebar-link {
width: 2px;
height: 12px;
visibility: collapse;
text-decoration: none;
font-size: var(--text-md);
svg {
width: 16px;
height: 16px;
}
}
.collapse-sidebar-link svg {
visibility: visible;
}
.sidebar-item-container {
width: 30px;
position: relative;
margin-left: -10px;
margin-bottom: 6px;
// &:hover{
// background-color: #f3f3f3;
// border-radius: 8px;
// }
// margin-left: -10px;
// margin-bottom: 6px;
/* nested container */
.sidebar-item-container {
margin-left: 20px;
padding-left: 12px;
.standard-sidebar-item {
justify-content: start;
}
}
.indicator {
margin-left: 5px;
}
}
}
@ -188,25 +234,46 @@ body {
.body-sidebar {
// make it an overlay on hover
position: absolute;
width: 200px;
width: 220px;
.app-switcher-dropdown {
width: 204px;
left: 0px;
padding: 2px 0px 2px 3px;
}
.body-sidebar-top {
overflow-y: auto;
width: 204px;
overflow-y: hidden;
.app-switcher-dropdown {
width: 204px;
}
}
.sidebar-item-container {
width: 100%;
}
.sidebar-item-label {
display: flex;
align-items: center;
}
.sidebar-item-control {
display: block;
}
.edit-sidebar-link {
display: block;
.sidebar-items {
padding: 0px;
}
.collapse-sidebar-link {
visibility: visible;
}
.body-sidebar-bottom {
width: 220px;
position: static;
}
}
// show placeholder so that main section remains static
.body-sidebar-placeholder {
display: flex;
width: 220px;
}
}
@ -218,6 +285,7 @@ body {
// body sidebar hidded in mobile view
.body-sidebar-container {
.body-sidebar {
padding: 0px;
width: 0px;
overflow: hidden;
}
@ -226,21 +294,42 @@ body {
// expands when navbar-brand is clicked
.body-sidebar-container.expanded {
.body-sidebar {
width: 200px;
padding: 8px 8px 10px 8px;
width: 220px;
}
// acts a overlay when in mobile view
.body-sidebar-placeholder {
display: flex;
width: 0px;
}
}
}
@include media-breakpoint-up(sm) {
// for bigger screens, expand / collapse on hover
.body-sidebar-container:hover {
@include body-sidebar-expanded();
}
// .body-sidebar-container:hover {
// @include body-sidebar-expanded();
// }
}
.app-switcher-dropdown {
position: relative;
text-decoration: none;
width: 38px;
height: 38px;
left: -2px;
padding: 3px;
.standard-sidebar-item {
padding-top: 1px;
padding-bottom: 1px;
.d-flex {
width: 161px;
}
gap: 12px;
}
.sidebar-item-control {
margin-top: -2px;
margin: 2px;
margin-right: 0px;
}
}
@ -248,27 +337,40 @@ body {
position: absolute;
top: 44px;
left: 7px;
width: 183px; /* 200 - 7px */
padding: var(--padding-xs);
box-shadow: var(--shadow-base);
background-color: var(--neutral);
width: 220px; /* 200 - 7px */
padding: 6px;
border-radius: var(--border-radius-lg);
background: var(--surface-modal, rgba(255, 255, 255, 1));
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);
z-index: 1;
border-radius: var(--border-radius-tiny);
}
.app-item {
padding: var(--padding-xs);
// padding: var(--padding-xs);
border-radius: var(--border-radius-tiny);
opacity: 0px;
&:hover {
background-color: var(--subtle-accent);
}
a {
width: 208px;
height: 28px;
padding: 6px 8px 6px 8px;
gap: 8px;
text-decoration: none;
display: flex;
align-items: center;
gap: var(--margin-sm);
.sidebar-item-icon {
line-height: 0px;
.app-logo {
width: 16px;
height: 16px;
}
}
}
.app-item-title {
@ -277,7 +379,21 @@ body {
overflow: hidden;
}
}
// sidebar-item states
@mixin hover-mixin {
background-color: #f3f3f3;
border-radius: 8px;
}
.hover {
@include hover-mixin();
}
.active-sidebar {
background: var(--surface-selected, rgba(255, 255, 255, 1));
box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
// form sidebar
.form-sidebar {
.sidebar-section {