Skip to content

Instantly share code, notes, and snippets.

@Renancp01
Created March 31, 2022 02:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Renancp01/1c0b1ffcbafd63af80ca57510184154d to your computer and use it in GitHub Desktop.
Save Renancp01/1c0b1ffcbafd63af80ca57510184154d to your computer and use it in GitHub Desktop.
Pro Sidebar template
<div class="layout has-sidebar fixed-sidebar fixed-header">
<aside id="sidebar" class="sidebar break-point-lg has-bg-image">
<div class="image-wrapper">
<img src="https://user-images.githubusercontent.com/25878302/144499035-2911184c-76d3-4611-86e7-bc4e8ff84ff5.jpg" alt="sidebar background" />
</div>
<div class="sidebar-layout">
<div class="sidebar-header">
<span style="
text-transform: uppercase;
font-size: 15px;
letter-spacing: 3px;
font-weight: bold;
">Pro Sidebar</span>
</div>
<div class="sidebar-content">
<nav class="menu open-current-submenu">
<ul>
<li class="menu-item sub-menu">
<a href="#">
<span class="menu-icon">
<i class="ri-vip-diamond-fill"></i>
</span>
<span class="menu-title">Components</span>
<span class="menu-suffix">&#x1F525;</span>
</a>
<div class="sub-menu-list">
<ul>
<li class="menu-item">
<a href="#">
<span class="menu-title">Grid</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-title">Layout</span>
</a>
</li>
<li class="menu-item sub-menu">
<a href="#">
<span class="menu-title">Forms</span>
</a>
<div class="sub-menu-list">
<ul>
<li class="menu-item">
<a href="#">
<span class="menu-title">Input</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-title">Select</span>
</a>
</li>
<li class="menu-item sub-menu">
<a href="#">
<span class="menu-title">More</span>
</a>
<div class="sub-menu-list">
<ul>
<li class="menu-item">
<a href="#">
<span class="menu-title">CheckBox</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-title">Radio</span>
</a>
</li>
<li class="menu-item sub-menu">
<a href="#">
<span class="menu-title">Want more ?</span>
<span class="menu-suffix">&#x1F914;</span>
</a>
<div class="sub-menu-list">
<ul>
<li class="menu-item">
<a href="#">
<span class="menu-prefix">&#127881;</span>
<span class="menu-title">You made it </span>
</a>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
<li class="menu-item sub-menu">
<a href="#">
<span class="menu-icon">
<i class="ri-bar-chart-2-fill"></i>
</span>
<span class="menu-title">Charts</span>
</a>
<div class="sub-menu-list">
<ul>
<li class="menu-item">
<a href="#">
<span class="menu-title">Pie chart</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-title">Line chart</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-title">Bar chart</span>
</a>
</li>
</ul>
</div>
</li>
<li class="menu-item sub-menu">
<a href="#">
<span class="menu-icon">
<i class="ri-shopping-cart-fill"></i>
</span>
<span class="menu-title">E-commerce</span>
</a>
<div class="sub-menu-list">
<ul>
<li class="menu-item">
<a href="#">
<span class="menu-title">Products</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-title">Orders</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-title">credit card</span>
</a>
</li>
</ul>
</div>
</li>
<li class="menu-item sub-menu">
<a href="#">
<span class="menu-icon">
<i class="ri-global-fill"></i>
</span>
<span class="menu-title">Maps</span>
</a>
<div class="sub-menu-list">
<ul>
<li class="menu-item">
<a href="#">
<span class="menu-title">Google maps</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-title">Open street map</span>
</a>
</li>
</ul>
</div>
</li>
<li class="menu-item sub-menu">
<a href="#">
<span class="menu-icon">
<i class="ri-brush-3-fill"></i>
</span>
<span class="menu-title">Theme</span>
</a>
<div class="sub-menu-list">
<ul>
<li class="menu-item">
<a href="#">
<span class="menu-title">Dark</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-title">Light</span>
</a>
</li>
</ul>
</div>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-icon">
<i class="ri-book-2-fill"></i>
</span>
<span class="menu-title">Documentation</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-icon">
<i class="ri-calendar-fill"></i>
</span>
<span class="menu-title">Calendar</span>
</a>
</li>
<li class="menu-item">
<a href="#">
<span class="menu-icon">
<i class="ri-service-fill"></i>
</span>
<span class="menu-title">Examples</span>
</a>
</li>
</ul>
</nav>
</div>
<div class="sidebar-footer"><span>Sidebar footer</span></div>
</div>
</aside>
<div id="overlay" class="overlay"></div>
<div class="layout">
<header class="header">
<a id="btn-collapse" href="#">
<i class="ri-menu-line ri-xl"></i>
</a>
<a id="btn-toggle" href="#" class="sidebar-toggler break-point-lg">
<i class="ri-menu-line ri-xl"></i>
</a>
</header>
<main class="content">
<div>
<h1>Pro Sidebar</h1>
<p>
Responsive layout with advanced sidebar menu built with SCSS and vanilla Javascript
</p>
<p>
Full Code and documentation available on <a href="https://github.com/azouaoui-med/pro-sidebar-template" target="_blank">Github</a>
</p>
<div>
<a href="https://github.com/azouaoui-med/pro-sidebar-template" target="_blank">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/azouaoui-med/pro-sidebar-template?style=social" />
</a>
<a href="https://github.com/azouaoui-med/pro-sidebar-template" target="_blank">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/azouaoui-med/pro-sidebar-template?style=social" />
</a>
</div>
</div>
<div>
<h2>Features</h2>
<ul>
<li>Fully responsive</li>
<li>Collapsable sidebar</li>
<li>Multi level menu</li>
<li>RTL support</li>
<li>Customizable</li>
</ul>
</div>
<div>
<h2>Resources</h2>
<ul>
<li>
<a target="_blank" href="https://github.com/azouaoui-med/css-pro-layout">
Css Pro Layout</a>
</li>
<li>
<a target="_blank" href="https://github.com/popperjs/popper-core"> Popper Core</a>
</li>
<li>
<a target="_blank" href="https://remixicon.com/"> Remix Icons</a>
</li>
</ul>
</div>
<footer class="footer">
<small style="margin-bottom: 20px; display: inline-block">
© 2022 made with
<span style="color: red; font-size: 18px">&#10084;</span> by -
<a target="_blank" href="https://azouaoui.netlify.com"> Mohamed Azouaoui </a>
</small>
<br />
<div>
<a href="https://github.com/azouaoui-med" target="_blank" rel="noopener noreferrer">
<img alt="GitHub followers" src="https://img.shields.io/github/followers/azouaoui-med?label=github&style=social" />
</a>
<a href="https://twitter.com/azouaoui_med" target="_blank" rel="noopener noreferrer">
<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/azouaoui_med?label=twitter&style=social" />
</a>
</div>
</footer>
</main>
<div class="overlay"></div>
</div>
</div>
const ANIMATION_DURATION = 300;
const SIDEBAR_EL = document.getElementById("sidebar");
const SUB_MENU_ELS = document.querySelectorAll(
".menu > ul > .menu-item.sub-menu"
);
const FIRST_SUB_MENUS_BTN = document.querySelectorAll(
".menu > ul > .menu-item.sub-menu > a"
);
const INNER_SUB_MENUS_BTN = document.querySelectorAll(
".menu > ul > .menu-item.sub-menu .menu-item.sub-menu > a"
);
class PopperObject {
instance = null;
reference = null;
popperTarget = null;
constructor(reference, popperTarget) {
this.init(reference, popperTarget);
}
init(reference, popperTarget) {
this.reference = reference;
this.popperTarget = popperTarget;
this.instance = Popper.createPopper(this.reference, this.popperTarget, {
placement: "right",
strategy: "fixed",
resize: true,
modifiers: [
{
name: "computeStyles",
options: {
adaptive: false
}
},
{
name: "flip",
options: {
fallbackPlacements: ["left", "right"]
}
}
]
});
document.addEventListener(
"click",
(e) => this.clicker(e, this.popperTarget, this.reference),
false
);
const ro = new ResizeObserver(() => {
this.instance.update();
});
ro.observe(this.popperTarget);
ro.observe(this.reference);
}
clicker(event, popperTarget, reference) {
if (
SIDEBAR_EL.classList.contains("collapsed") &&
!popperTarget.contains(event.target) &&
!reference.contains(event.target)
) {
this.hide();
}
}
hide() {
this.instance.state.elements.popper.style.visibility = "hidden";
}
}
class Poppers {
subMenuPoppers = [];
constructor() {
this.init();
}
init() {
SUB_MENU_ELS.forEach((element) => {
this.subMenuPoppers.push(
new PopperObject(element, element.lastElementChild)
);
this.closePoppers();
});
}
togglePopper(target) {
if (window.getComputedStyle(target).visibility === "hidden")
target.style.visibility = "visible";
else target.style.visibility = "hidden";
}
updatePoppers() {
this.subMenuPoppers.forEach((element) => {
element.instance.state.elements.popper.style.display = "none";
element.instance.update();
});
}
closePoppers() {
this.subMenuPoppers.forEach((element) => {
element.hide();
});
}
}
const slideUp = (target, duration = ANIMATION_DURATION) => {
const { parentElement } = target;
parentElement.classList.remove("open");
target.style.transitionProperty = "height, margin, padding";
target.style.transitionDuration = `${duration}ms`;
target.style.boxSizing = "border-box";
target.style.height = `${target.offsetHeight}px`;
target.offsetHeight;
target.style.overflow = "hidden";
target.style.height = 0;
target.style.paddingTop = 0;
target.style.paddingBottom = 0;
target.style.marginTop = 0;
target.style.marginBottom = 0;
window.setTimeout(() => {
target.style.display = "none";
target.style.removeProperty("height");
target.style.removeProperty("padding-top");
target.style.removeProperty("padding-bottom");
target.style.removeProperty("margin-top");
target.style.removeProperty("margin-bottom");
target.style.removeProperty("overflow");
target.style.removeProperty("transition-duration");
target.style.removeProperty("transition-property");
}, duration);
};
const slideDown = (target, duration = ANIMATION_DURATION) => {
const { parentElement } = target;
parentElement.classList.add("open");
target.style.removeProperty("display");
let { display } = window.getComputedStyle(target);
if (display === "none") display = "block";
target.style.display = display;
const height = target.offsetHeight;
target.style.overflow = "hidden";
target.style.height = 0;
target.style.paddingTop = 0;
target.style.paddingBottom = 0;
target.style.marginTop = 0;
target.style.marginBottom = 0;
target.offsetHeight;
target.style.boxSizing = "border-box";
target.style.transitionProperty = "height, margin, padding";
target.style.transitionDuration = `${duration}ms`;
target.style.height = `${height}px`;
target.style.removeProperty("padding-top");
target.style.removeProperty("padding-bottom");
target.style.removeProperty("margin-top");
target.style.removeProperty("margin-bottom");
window.setTimeout(() => {
target.style.removeProperty("height");
target.style.removeProperty("overflow");
target.style.removeProperty("transition-duration");
target.style.removeProperty("transition-property");
}, duration);
};
const slideToggle = (target, duration = ANIMATION_DURATION) => {
if (window.getComputedStyle(target).display === "none")
return slideDown(target, duration);
return slideUp(target, duration);
};
const PoppersInstance = new Poppers();
/**
* wait for the current animation to finish and update poppers position
*/
const updatePoppersTimeout = () => {
setTimeout(() => {
PoppersInstance.updatePoppers();
}, ANIMATION_DURATION);
};
/**
* sidebar collapse handler
*/
document.getElementById("btn-collapse").addEventListener("click", () => {
SIDEBAR_EL.classList.toggle("collapsed");
PoppersInstance.closePoppers();
if (SIDEBAR_EL.classList.contains("collapsed"))
FIRST_SUB_MENUS_BTN.forEach((element) => {
element.parentElement.classList.remove("open");
});
updatePoppersTimeout();
});
/**
* sidebar toggle handler (on break point )
*/
document.getElementById("btn-toggle").addEventListener("click", () => {
SIDEBAR_EL.classList.toggle("toggled");
updatePoppersTimeout();
});
/**
* toggle sidebar on overlay click
*/
document.getElementById("overlay").addEventListener("click", () => {
SIDEBAR_EL.classList.toggle("toggled");
});
const defaultOpenMenus = document.querySelectorAll(".menu-item.sub-menu.open");
defaultOpenMenus.forEach((element) => {
element.lastElementChild.style.display = "block";
});
/**
* handle top level submenu click
*/
FIRST_SUB_MENUS_BTN.forEach((element) => {
element.addEventListener("click", () => {
if (SIDEBAR_EL.classList.contains("collapsed"))
PoppersInstance.togglePopper(element.nextElementSibling);
else {
const parentMenu = element.closest(".menu.open-current-submenu");
if (parentMenu)
parentMenu
.querySelectorAll(":scope > ul > .menu-item.sub-menu > a")
.forEach(
(el) =>
window.getComputedStyle(el.nextElementSibling).display !==
"none" && slideUp(el.nextElementSibling)
);
slideToggle(element.nextElementSibling);
}
});
});
/**
* handle inner submenu click
*/
INNER_SUB_MENUS_BTN.forEach((element) => {
element.addEventListener("click", () => {
slideToggle(element.nextElementSibling);
});
});
<script src="https://unpkg.com/@popperjs/core@2"></script>
$text-color: #b3b8d4;
$secondary-text-color: #dee2ec;
$bg-color: #0c1e35;
$secondary-bg-color: #0b1a2c;
$border-color: rgba(#535d7d, 0.3);
$sidebar-header-height: 64px;
$sidebar-footer-height: 64px;
.layout {
z-index: 1;
.header {
box-shadow: 1px 1px 4px #9aa0b9;
display: flex;
align-items: center;
padding: 20px;
}
.content {
padding: 20px;
display: flex;
flex-direction: column;
}
.footer {
text-align: center;
margin-top: auto;
margin-bottom: 20px;
padding: 20px;
}
&.rtl {
.header {
box-shadow: -1px 1px 4px #9aa0b9;
}
}
}
.sidebar {
color: $text-color;
overflow-x: hidden !important;
position: relative;
background-color: $bg-color;
.image-wrapper {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0.2;
z-index: 1;
display: none;
> img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
}
&.has-bg-image .image-wrapper {
display: block;
}
.sidebar-layout {
height: 100%;
display: flex;
flex-direction: column;
position: relative;
z-index: 2;
.sidebar-header {
height: $sidebar-header-height;
min-height: $sidebar-header-height;
display: flex;
align-items: center;
padding: 0 20px;
border-bottom: 1px solid $border-color;
> span {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.sidebar-content {
flex-grow: 1;
padding: 10px 0;
}
.sidebar-footer {
height: $sidebar-footer-height;
min-height: $sidebar-footer-height;
display: flex;
align-items: center;
border-top: 1px solid $border-color;
padding: 0 20px;
> span {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
}
@keyframes swing {
0%,
30%,
50%,
70%,
100% {
transform: rotate(0deg);
}
10% {
transform: rotate(10deg);
}
40% {
transform: rotate(-10deg);
}
60% {
transform: rotate(5deg);
}
80% {
transform: rotate(-5deg);
}
}
.layout {
.sidebar {
.menu {
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
.menu-item {
a {
display: flex;
align-items: center;
height: 50px;
padding: 0 20px;
color: $text-color;
.menu-icon {
font-size: 1.2rem;
width: 35px;
min-width: 35px;
height: 35px;
line-height: 35px;
text-align: center;
display: inline-block;
margin-right: 10px;
border-radius: 2px;
transition: color 0.3s;
i {
display: inline-block;
}
}
.menu-title {
font-size: 0.9rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-grow: 1;
transition: color 0.3s;
}
.menu-prefix,
.menu-suffix {
display: inline-block;
padding: 5px;
opacity: 1;
transition: opacity 0.3s;
}
&:hover {
.menu-title {
color: $secondary-text-color;
}
.menu-icon {
color: $secondary-text-color;
i {
animation: swing ease-in-out 0.5s 1 alternate;
}
}
&::after {
border-color: $secondary-text-color !important;
}
}
}
&.sub-menu {
position: relative;
> a {
&::after {
content: "";
transition: transform 0.3s;
border-right: 2px solid currentcolor;
border-bottom: 2px solid currentcolor;
width: 5px;
height: 5px;
transform: rotate(-45deg);
}
}
> .sub-menu-list {
padding-left: 20px;
display: none;
overflow: hidden;
z-index: 999;
}
&.open {
> a {
&::after {
transform: rotate(45deg);
}
}
}
}
&.active {
> a {
.menu-title {
color: $secondary-text-color;
}
&::after {
border-color: $secondary-text-color;
}
.menu-icon {
color: $secondary-text-color;
}
}
}
}
> ul > .sub-menu > .sub-menu-list {
background-color: $secondary-bg-color;
}
&.icon-shape-circle,
&.icon-shape-rounded,
&.icon-shape-square {
.menu-item a .menu-icon {
background-color: $secondary-bg-color;
}
}
&.icon-shape-circle .menu-item a .menu-icon {
border-radius: 50%;
}
&.icon-shape-rounded .menu-item a .menu-icon {
border-radius: 4px;
}
&.icon-shape-square .menu-item a .menu-icon {
border-radius: 0;
}
}
&:not(.collapsed) {
.menu > ul {
> .menu-item {
&.sub-menu {
> .sub-menu-list {
visibility: visible !important;
position: static !important;
transform: translate(0, 0) !important;
}
}
}
}
}
&.collapsed {
.menu > ul {
> .menu-item {
> a {
.menu-prefix,
.menu-suffix {
opacity: 0;
}
}
&.sub-menu {
> a {
&::after {
content: "";
width: 5px;
height: 5px;
background-color: currentcolor;
border-radius: 50%;
display: inline-block;
position: absolute;
right: 10px;
top: 50%;
border: none;
transform: translateY(-50%);
}
&:hover {
&::after {
background-color: $secondary-text-color;
}
}
}
> .sub-menu-list {
transition: none !important;
width: 200px;
margin-left: 3px !important;
border-radius: 4px;
display: block !important;
}
}
&.active {
> a {
&::after {
background-color: $secondary-text-color;
}
}
}
}
}
}
&.has-bg-image {
.menu {
&.icon-shape-circle,
&.icon-shape-rounded,
&.icon-shape-square {
.menu-item a .menu-icon {
background-color: rgba($secondary-bg-color, 0.6);
}
}
}
&:not(.collapsed) {
.menu {
> ul > .sub-menu > .sub-menu-list {
background-color: rgba($secondary-bg-color, 0.6);
}
}
}
}
}
&.rtl {
.sidebar {
.menu {
.menu-item {
a {
.menu-icon {
margin-left: 10px;
margin-right: 0;
}
}
&.sub-menu {
> a {
&::after {
transform: rotate(135deg);
}
}
> .sub-menu-list {
padding-left: 0;
padding-right: 20px;
}
&.open {
> a {
&::after {
transform: rotate(45deg);
}
}
}
}
}
}
&.collapsed {
.menu > ul {
> .menu-item {
&.sub-menu {
a::after {
right: auto;
left: 10px;
}
> .sub-menu-list {
margin-left: -3px !important;
}
}
}
}
}
}
}
}
* {
box-sizing: border-box;
}
body {
margin: 0;
height: 100vh;
font-family: "Roboto", sans-serif;
color: #212529;
}
a {
text-decoration: none;
}
@media (max-width: 992px) {
#btn-collapse {
display: none;
}
}
<link href="https://unpkg.com/css-pro-layout@1.1.0/dist/css/css-pro-layout.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/remixicon@2.2.0/fonts/remixicon.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment