From 4a79acc6ff7933a6e52c587cfacd1763ed8b3b45 Mon Sep 17 00:00:00 2001 From: Ahmed Zamil Date: Wed, 3 Mar 2021 05:20:20 +0300 Subject: [PATCH] navbar --- LICENSE | 2 +- css/iui.css | 163 ++++++++++++++++++++++++++++++++++++++------ src/UI/Navbar.js | 171 +++++++++++++++++++++++++++++++++++------------ 3 files changed, 273 insertions(+), 63 deletions(-) diff --git a/LICENSE b/LICENSE index c840fc5..92c1d00 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2021 Esiur Foundation +Copyright (c) 2020-2021 Esiur Foundation, Ahmed Kh. Zamil Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/css/iui.css b/css/iui.css index a5e65e1..4185647 100644 --- a/css/iui.css +++ b/css/iui.css @@ -2724,7 +2724,7 @@ html[dir='rtl'] .multiselect-list-remove { height: 100%; } -.navbar-search +.navbar-search, .sitebar-search { margin: 6px; background-image: var(--search); @@ -2734,13 +2734,29 @@ html[dir='rtl'] .multiselect-list-remove { padding-left: 30px; } + +.navbar-item > .navbar-menu +{ + transition: max-height ease-in-out 0.5s; + overflow: hidden; + max-height: 800px; +} + +.navbar-item[collapsed] > .navbar-menu +{ + max-height: 0; + transition: max-height ease-in-out 0.3s; +} + .navbar-container { overflow: auto; visibility: hidden; } -.navbar-container > i-link > span > span + +.navbar i-link > span > span, +.sitebar i-link > span > span { color: black; background-color: #fff3d4; @@ -2783,22 +2799,19 @@ html[dir='rtl'] .multiselect-list-remove { visibility: visible; } -.navbar-container i-link -{ - transition: height ease 0.2s; -} -.navbar-container i-link[data-level = '1'] { +.navbar-container[level = '1'] > i-link { padding-right: 20px; font-size: 14px; } -.navbar-container i-link[data-level = '0'] { +.navbar-container[level = '0'] > i-link, +.sitebar-container[level = '0'] > i-link { background-color: #e5e5e5; /*border: 1px solid #cacaca;*/ } -.navbar-container i-link[data-level = '2'] { +.navbar-container[level = '2'] > i-link { background-color: #d4d4d4; padding-right: 40px; font-size: 14px; @@ -2806,23 +2819,17 @@ html[dir='rtl'] .multiselect-list-remove { font-weight: bold; } -.navbar-container i-link[hidden] { - /* display: none; */ - padding-top: 0; - padding-bottom: 0; - height: 0; - transition: height ease 0.2s; -} - - -.navbar-container i-link[selected] +.navbar-item[selected] > i-link, .navbar-item[selected] > i-link:hover, +.sitebar-item[selected] > i-link, .sitebar-item[selected] > i-link:hover { font-weight: bold; background:#4ebeec; color: white; } -.navbar-container i-check { + +.navbar-container i-check +{ width: 42px; background-image: var(--arrow-left); background-position: 0px 48%; @@ -2835,6 +2842,120 @@ html[dir='rtl'] .multiselect-list-remove { border-bottom-left-radius: 10px; } -.navbar-container i-check[checked='checked'] { +.sitebar-container i-check +{ + width: 34px; + background-image: var(--arrow-left); + background-position: 0px 48%; + background-repeat: no-repeat; +} + +.navbar-container i-check[checked='checked'], +.sitebar-container i-check[checked='checked'] +{ background-image: var(--arrow-down-active); } + +.sitebar { + display: flex; + height: 100%; +} + +.sitebar-container{ + display: flex; +} + +.sitebar-item +{ + position: relative; +} + +.sitebar-item > i-link +{ + display: flex; + background: #e9e9e9; + +} + +.sitebar-item > i-link:hover +{ + border-radius: 0; +} + +.sitebar-menu +{ + position: absolute; + width: auto; + white-space: nowrap; + background: #e0e0e080; + display: flex; + flex-direction: column; + /* padding: 5px; */ + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + box-shadow: 0px 1px 2px 0px #b5b5b5; + min-width: 100%; + /* top: calc(100% - 1px);*/ + overflow: visible; +} + +.sitebar-container > * +{ + text-align: center; +} + +.sitebar-item > i-link +{ + padding: 10px; +} + +/* .sitebar-item > .sitebar-menu +{ + display: none; +} + +.sitebar-item:hover > .sitebar-menu +{ + display: block; +} */ + + +.sitebar-item[level='0'] > .sitebar-menu +{ + transition: transform ease-in-out 0.2s; + transform: scaleY(1); + transform-origin: top; + +} + + +.sitebar-item[level='0'][collapsed] > .sitebar-menu +{ + transition: transform ease-in-out 0.2s; + transform: scaleY(0); + transform-origin: top; + +} + + +.sitebar-item[level='1'] > .sitebar-menu +{ + max-width: 800px; + left: -100%; + top: 0; + box-shadow: -1px 1px 1px 0px #c8c8c8; + border-bottom-right-radius: 0; + + transition: transform ease-in-out 0.2s; + transform: scaleX(1); + transform-origin: right; + +} + +.sitebar-item[level='1'][collapsed] > .sitebar-menu +{ + transition: transform ease-in-out 0.2s; + transform: scaleX(0); + transform-origin: right; +} + diff --git a/src/UI/Navbar.js b/src/UI/Navbar.js index 9a7c8e7..89dda2a 100644 --- a/src/UI/Navbar.js +++ b/src/UI/Navbar.js @@ -8,9 +8,11 @@ export default IUI.module(class Navbar extends IUIElement constructor() { super(); + + this._list = []; } - search(text) { + search_old(text) { for(var i = 0; i < this._container.children.length; i++) { let el = this._container.children[i]; @@ -45,8 +47,45 @@ export default IUI.module(class Navbar extends IUIElement } } + search(text, within) { + + let menu = within == null ? this._container : within.menu; + + for(var i = 0; i < menu.children.length; i++) + { + let item = menu.children[i]; + let link = item.link; + if (link.title.toLowerCase().includes(text)) + { + link.text.innerHTML = link.title.replace(new RegExp(text, 'gi'), (str) => `${str}`); + item.style.display = ""; + + //if (within != null) + // within.removeAttribute("collapsed"); + + // make parents visible + let parent = within; + + while (parent != null && parent != this) + { + parent.expand.checked = true; + parent.removeAttribute("collapsed"); + parent.style.display = ""; + parent = parent.parentElement.parentElement; + } + + } + else + { + item.style.display = "none"; + } + + if (item.menu != null) + this.search(text, item); + } + } - expand(link, value) { + expand_old(link, value) { let next = link;// = link.nextElementSibling; let level = parseInt(link.getAttribute("data-level")); @@ -71,6 +110,23 @@ export default IUI.module(class Navbar extends IUIElement } } + expand(item, value) { + if (value) + item.removeAttribute("collapsed"); + else + item.setAttribute("collapsed", ""); + + item.expand.checked = value; + } + + get collapsed(){ + return this.hasAttribute("collapsed"); + } + + get auto(){ + return this.hasAttribute("auto"); + } + build(){ this.innerHTML = ""; @@ -90,60 +146,92 @@ export default IUI.module(class Navbar extends IUIElement this.appendChild(this._container); - var appendRoutes = (routes, level) => { + let collapsed = this.collapsed; + let auto = this.auto; + + const filterRoutes = (routes) => + routes.filter(r => { + if (r.hasAttribute("private")) + return false; + + if (this.private instanceof Function) + { + try{ + if (this.private(r)) + { + return false; + } + } catch(ex){ + console.log(ex); + debugger; + } + + return true; + } + }); + + const appendRoutes = (routes, level, container) => { for (var i = 0; i < routes.length; i++) { - if (routes[i].hasAttribute("private")) - continue; - if (this.private instanceof Function) - { - try{ - // console.log("F"); - if (this.private(routes[i])) - { - // console.log("private", route[i]); - continue; - } - } catch(ex){ - console.log(ex); - debugger; - } - } + let item = document.createElement("div"); + item.className = this.cssClass + "-item"; - let el = new Link();// document.createElement("i-link"); - el.setAttribute("data-level", level); - el.link = routes[i].link; - el.title = routes[i].caption; + let link = new Link();// document.createElement("i-link"); + item.setAttribute("level", level); + link.link = routes[i].link; + link.title = routes[i].caption; if (routes[i].icon != null) - el.innerHTML = ""; + link.innerHTML = ""; - el.text = document.createElement("span"); - el.text.innerHTML = el.title; - el.appendChild(el.text); - - this._container.appendChild(el); + link.text = document.createElement("span"); + link.text.innerHTML = link.title; + link.appendChild(link.text); - if (routes[i].routes.length > 0) { + item.link = link; + + item.appendChild(link); + container.appendChild(item); + + this._list.push(item); + + let subRoutes = filterRoutes(routes[i].routes); + + if (subRoutes.length > 0) { // append plus - el.expand = new Check({cssClass: this.cssClass + "-check"});// document.createElement("i-check"); - el.expand.checked = true; + item.expand = new Check({cssClass: this.cssClass + "-check"});// document.createElement("i-check"); + item.expand.checked = this.collapsed ? false : true; + item.expand.checked = !collapsed; - //plus.className = "expand";#f8f8f8 - el.expand.on("click", (e) => { - self.expand(el, el.expand.checked); + if (collapsed) + item.setAttribute("collapsed", ""); + + link.appendChild(item.expand); + + item.menu = document.createElement("div"); + item.menu.className = this.cssClass + "-menu"; + item.appendChild(item.menu); + + item.expand.on("click", (e) => { + self.expand(item, item.expand.checked); e.stopPropagation(); }); - el.appendChild(el.expand); - appendRoutes(routes[i].routes, level + 1); + + if (auto) + { + item.addEventListener("mouseenter", ()=> self.expand(item, true)); + item.addEventListener("mouseleave", ()=> self.expand(item, false)); + } + + appendRoutes(subRoutes, level + 1, item.menu); } } }; - appendRoutes(roots, 0); + appendRoutes(filterRoutes(roots), 0, this._container); } created() { @@ -151,10 +239,11 @@ export default IUI.module(class Navbar extends IUIElement window.router.on("created", this.build); window.router.on("navigate", (e) => { - for(var i = 0; i < this?._container?.children?.length; i++) + + for(var i = 0; i < this._list.length; i++) { - var el = this._container.children[i]; - if (el.link == e.base) + var el = this._list[i]; + if (el.link.link == e.base) el.setAttribute("selected", ""); else el.removeAttribute("selected");