<!DOCTYPE html>
<html>

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta charset="utf-8" />
    <title>bootstrap5 navbar</title>

    <link rel="stylesheet" href="https://npm.elemecdn.com/bootstrap@5.0.0/dist/css/bootstrap.min.css" />
</head>

<body>

    <button class="bsnav-menu-toggle d-lg-none">
        <span></span>
        <span></span>
        <span></span>
    </button>

    <!-- mask -->
    <span class="bsnav-mask"></span>

    <nav class="mobile-offcanvas navbar navbar-expand-lg navbar-orange">

        <div class="container-fluid">

            <div class="bsnav-header">
                <button class="btn-close float-end"></button>
            </div>

            <a class="navbar-brand" href="#">Brand</a>

            <!-- left -->
            <ul class="navbar-nav">
                <li class="nav-item active"> <a class="nav-link" href="#"> Home </a> </li>
                <li class="nav-item"><a class="nav-link" href="#"> About </a></li>
                <li class="nav-item"><a class="nav-link" href="#"> Services </a></li>
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown"> More items </a>
                    <ul class="dropdown-menu">
                        <li><a class="dropdown-item" href="#"> Submenu item 1</a></li>
                        <li><a class="dropdown-item" href="#"> Submenu item 2 </a></li>
                        <li>
                            <hr class="dropdown-divider">
                        </li>
                        <li><a class="dropdown-item" href="#"> Submenu item 3 </a></li>
                        <li><a class="dropdown-item" href="#"> Submenu item 4 </a></li>
                        <li><a class="dropdown-item" href="#"> Submenu item 5 </a></li>
                        <li>
                            <hr class="dropdown-divider">
                        </li>
                        <li><a class="dropdown-item" href="#"> Submenu item 3 </a></li>
                        <li><a class="dropdown-item" href="#"> Submenu item 4 </a></li>
                        <li><a class="dropdown-item" href="#"> Submenu item 5 </a></li>
                        <li>
                            <hr class="dropdown-divider">
                        </li>
                        <li><a class="dropdown-item" href="#"> Submenu item 3 </a></li>
                    </ul>
                </li>
            </ul>

            <!-- right -->
            <ul class="navbar-nav ms-auto">
                <li class="nav-item"><a class="nav-link" href="#"> Menu item </a></li>
                <li class="nav-item"><a class="nav-link" href="#"> Menu item </a></li>
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown"> Dropdown right </a>
                    <ul class="dropdown-menu dropdown-menu-end">
                        <li><a class="dropdown-item" href="#"> Submenu item 1</a></li>
                        <li><a class="dropdown-item" href="#"> Submenu item 2 </a></li>
                        <li>
                            <hr class="dropdown-divider">
                        </li>
                        <li><a class="dropdown-item" href="#"> Submenu item 3 </a></li>
                    </ul>
                </li>
            </ul>

        </div>

    </nav>

    <script src="https://npm.elemecdn.com/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js"></script>

    <!-- https://bootstrap-menu.com/ -->
</body>

</html>
let bsnav = {
    mask: function (yesno) {
        if (yesno == true) {
            document.querySelector('.bsnav-mask').classList.add('active');
        }
        else if (yesno == false) {
            document.querySelector('.bsnav-mask').classList.remove('active');
        }
    },
    offcanvas: function (yesno) {
        bsnav.mask(yesno);

        if (yesno == true) {
            document.querySelector('.mobile-offcanvas').classList.add('show');
            document.body.classList.add('offcanvas-active');
        }
        else if (yesno == false) {
            document.querySelector('.mobile-offcanvas.show').classList.remove('show');
            document.body.classList.remove('offcanvas-active');
        }
    },
    init: function () {

        document.body.addEventListener('click', function (e) {
            var target = e.target;

            //close
            if (target.classList.contains("btn-close") && target.parentNode.classList.contains("bsnav-header")) {
                e.preventDefault();
                bsnav.offcanvas(false);
            }
            if (target.classList.contains("bsnav-mask")) {
                bsnav.offcanvas(false);
            }

            //open
            if (target.classList.contains("bsnav-menu-toggle") || target.parentNode.classList.contains("bsnav-menu-toggle")) {
                bsnav.offcanvas(!document.querySelector('.mobile-offcanvas').classList.contains('show'));
            }
        });
    }
}

bsnav.init();

let bs = {
    obj: {},
    alert: function (content) {
        if (bs.obj.alert) {
            bs.obj.alert.dispose();
        }

        var dom = document.createElement("div");
        dom.className = "modal";
        dom.innerHTML = `
  <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-sm">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Message</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        ${content}
      </div>
      <div class="modal-footer justify-content-center">
        <button type="button" class="btn btn-warning" data-bs-dismiss="modal">确定</button>
      </div>
    </div>
  </div>`;

        document.body.appendChild(dom);
        bs.obj.alert = new bootstrap.Modal(dom);
        bs.obj.alert.show();
    },
    msg: function (content) {
        if (!bs.obj.msgbox) {
            bs.obj.msgbox = document.createElement("div");
            bs.obj.msgbox.className = "toast-container position-absolute top-0 start-50 translate-middle-x p-3";
            bs.obj.msgbox.style.zIndex = 9;
            document.body.appendChild(bs.obj.msgbox);
        }

        var dom = document.createElement("div");
        dom.innerHTML = `<div class="toast" data-bs-autohide="true">
            <div class="toast-header">
                <img src="/favicon.ico" class="rounded me-2" alt="icon" style="height:18px">
                <strong class="me-auto pt-1">Message</strong>
                <small class="text-muted">${new Date().toLocaleTimeString()}</small>
                <button type="button" class="btn-close me-1" data-bs-dismiss="toast"></button>
            </div>
            <div class="toast-body">
                ${content}
            </div>
        </div>`;

        var toastdom = dom.children[0];
        bs.obj.msgbox.appendChild(toastdom);
        new bootstrap.Toast(toastdom).show();
    }
}

// bs.alert(new Date().toISOString());
// bs.msg(new Date().toISOString());
.dropdown:hover {
    z-index: 45;
}

.navbar:hover {
    z-index: 40;
}

.dropdown .dropdown-menu,
.navbar .dropdown-menu {
    margin-top: 0;
    box-shadow: 0 2px 4px rgba(34, 34, 34, 0.15);
}

.dropdown .dropdown-menu-end,
.navbar .dropdown-menu-end {
    right: 0;
    left: auto;
}

/* mask */
.bsnav-mask {
    display: block;
    height: 100%;
    width: 0%;
    z-index: 20;
    position: fixed;
    top: 0;
    right: 0;
    opacity: 0;
    visibility: hidden;
    background-color: rgba(34, 34, 34, 0.6);
    transition: opacity 0.2s linear, visibility 0.2s, width 2s ease-in;
}

    .bsnav-mask.active {
        z-index: 25;
        transition: opacity 0.3s ease, width 0s;
        opacity: 1;
        width: 100%;
        visibility: visible;
    }

body.offcanvas-active {
    overflow: hidden;
}

.bsnav-header {
    display: none;
}

/*menu-toggle*/
.bsnav-menu-toggle {
    position: fixed;
    left: 0;
    bottom: 0;
    z-index: 49;
    padding: 10px 15px;
    outline: none;
    cursor: pointer;
    background-color: transparent;
    border: 1px solid transparent;
}

    .bsnav-menu-toggle span {
        background-color: orange;
        margin-bottom: 6px;
        display: block;
        width: 26px;
        height: 3px;
    }

/* ============ mobile view ============ */
@media all and (max-width: 991px) {
    .bsnav-header {
        display: block;
    }

    .mobile-offcanvas {
        visibility: hidden;
        transform: translateX(-100%);
        border-radius: 0;
        display: block;
        position: fixed;
        top: 0;
        left: 0;
        height: 100%;
        z-index: 48;
        width: 80vw;
        overflow-y: scroll;
        overflow-x: hidden;
        padding-bottom: 45px;
        transition: visibility 0.3s ease-in-out, transform 0.3s ease-in-out;
    }

        .mobile-offcanvas.show {
            visibility: visible;
            transform: translateX(0);
        }

        .mobile-offcanvas .container,
        .mobile-offcanvas .container-fluid {
            display: block;
        }

    .navbar-brand {
        padding-left: .7rem;
    }
}
/* mobile view .end */

/* desktop */
@media all and (min-width: 992px) {
    .navbar {
        padding: 0;
    }

        .navbar .nav-item .dropdown-menu {
            display: none;
        }

        .navbar .nav-item:hover .dropdown-menu {
            display: block;
        }

        .navbar .nav-item .dropdown-menu {
            margin-top: 0;
        }
}
/* desktop .end */

/* orange theme */
.navbar-orange {
    background-color: #ffca2a;
    box-shadow: 0 2px 3px rgba(100, 100, 100, 0.1);
    font-size: 14px;
}

    .navbar-orange .navbar-brand {
        font-weight: 600;
        display: block;
    }

    .navbar-orange .navbar-nav .nav-link {
        color: #444;
        padding: 0.7rem;
        font-weight: 600;
        border: 2px solid transparent;
    }

    .navbar-orange .navbar-nav .nav-item.show .nav-link,
    .navbar-orange .navbar-nav .nav-item:hover .nav-link {
        color: #0d6efd;
    }

    .navbar-orange .dropdown-menu {
        border: 0;
        background-clip: initial;
        border-radius: 0;
        box-shadow: 0 1px 5px rgba(70, 70, 70, 0.2);
    }

        .navbar-orange .dropdown-menu .dropdown-item {
            padding: 0.6rem 1.5rem;
        }