Refactor: Extract sidebar into a reusable component

This commit is contained in:
hiep200311
2026-06-04 08:38:42 +07:00
parent 65f306523a
commit 3c4385777c
7 changed files with 284 additions and 59 deletions
+3 -2
View File
@@ -144,7 +144,8 @@
margin: 0 15px; /* space around separator */
/* stacked dots */
box-shadow: 0 6px 0 rgba(255, 255, 255, 0.6),
box-shadow:
0 6px 0 rgba(255, 255, 255, 0.6),
0 -6px 0 rgba(255, 255, 255, 0.6);
}
@@ -328,7 +329,7 @@
flex-grow: 1;
}
.contact-section {
.header-contact-section {
display: none; /* Hide contact info on mobile - it will be in sidebar */
}
+1 -1
View File
@@ -55,7 +55,7 @@
</div>
<!-- Contact Info - Horizontal Layout -->
<div class="col-lg-6 col-md-6 col-12 contact-section">
<div class="col-lg-6 col-md-6 col-12 header-contact-section">
<div class="row g-3">
<!-- Address -->
<div class="col-md-6 col-12">
+128
View File
@@ -0,0 +1,128 @@
/* views/components/sidebar/sidebar.css */
/* Floating Menu Button Styles */
.floating-menu-btn {
display: none;
position: fixed;
bottom: 25px;
right: 25px;
width: 60px;
height: 60px;
border-radius: 50%;
background-color: #e84e0f;
color: white;
border: none;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
z-index: 1030;
cursor: pointer;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.floating-menu-btn:hover {
background-color: #c93d0a;
transform: scale(1.05);
}
.floating-menu-btn i {
font-size: 1.8rem;
}
/* Sidebar Overlay */
.sidebar-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1040;
}
.sidebar-overlay.show {
display: block;
}
/* Sidebar Styles */
.sidebar {
position: fixed;
top: 0;
left: -300px;
width: 300px;
height: 100%;
background-color: #30875f;
z-index: 1050;
overflow-y: auto;
transition: left 0.3s ease;
padding: 20px;
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.2);
}
.sidebar.open {
left: 0;
}
.sidebar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
.sidebar-logo {
width: 60px;
height: auto;
}
.close-sidebar {
background: none;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
}
.sidebar-nav {
display: flex;
flex-direction: column;
}
.sidebar-nav .nav-link {
padding: 15px 10px !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
color: white !important;
text-decoration: none;
}
.sidebar-contact {
margin-top: 20px;
color: white;
font-size: 0.9rem;
}
.sidebar-contact div {
margin-bottom: 10px;
}
/* Media Queries for Sidebar */
@media (max-width: 768px) {
.floating-menu-btn {
display: flex;
}
}
@media (max-width: 576px) {
.sidebar {
width: 250px;
}
.floating-menu-btn {
width: 50px;
height: 50px;
bottom: 20px;
right: 20px;
}
}
+56
View File
@@ -0,0 +1,56 @@
<!-- Floating Menu Button -->
<button class="floating-menu-btn" id="floatingMenuBtn">
<i class="bi bi-list"></i>
</button>
<!-- Sidebar Overlay -->
<div class="sidebar-overlay" id="sidebarOverlay"></div>
<!-- Sidebar -->
<div class="sidebar" id="sidebar">
<div class="sidebar-header">
<img
src="https://ik.imagekit.io/1e8470bv5/companyLogo.webp?updatedAt=1754143468028"
alt="Ky Long Logo"
class="sidebar-logo"
/>
<button class="close-sidebar">
<i class="bi bi-x-lg"></i>
</button>
</div>
<nav class="sidebar-nav">
<a href="/" class="nav-link">TRANG CHỦ</a>
<a href="/aboutMain" class="nav-link">GIỚI THIỆU</a>
<a href="/productMain" class="nav-link">SẢN PHẨM</a>
<a href="/serviceMain" class="nav-link">DỊCH VỤ</a>
<a href="/newsMain" class="nav-link">TIN TỨC</a>
<a href="/contactMain" class="nav-link">LIÊN HỆ</a>
</nav>
<div class="sidebar-contact">
<div class="d-flex align-items-center mb-3">
<div
class="contact-icon2 d-flex align-items-center justify-content-center me-2"
>
<i class="bi bi-geo-alt-fill"></i>
</div>
<div>
<div>Lầu 12, số 27 Đinh Bộ Lĩnh,</div>
<div>P. Bình Thạnh, TP.Hồ Chí Minh</div>
</div>
</div>
<div class="d-flex align-items-center">
<div
class="contact-icon d-flex align-items-center justify-content-center me-2"
>
<i class="bi bi-envelope-open-fill"></i>
</div>
<div>
<div>Email:</div>
<div>info@kylongtech.com</div>
</div>
</div>
</div>
</div>
+69
View File
@@ -0,0 +1,69 @@
// views/components/sidebar/sidebar.js
document.addEventListener("DOMContentLoaded", () => {
initSidebar();
});
function initSidebar() {
const floatingMenuBtn = document.getElementById("floatingMenuBtn");
const sidebarOverlay = document.getElementById("sidebarOverlay");
const sidebar = document.getElementById("sidebar");
const closeSidebarBtn = document.querySelector(".close-sidebar");
function openSidebar() {
if (sidebar && sidebarOverlay) {
sidebar.classList.add("open");
sidebarOverlay.style.display = "block";
}
}
function closeSidebar() {
if (sidebar && sidebarOverlay) {
sidebar.classList.remove("open");
sidebarOverlay.style.display = "none";
}
}
if (floatingMenuBtn) {
floatingMenuBtn.addEventListener("click", openSidebar);
}
if (closeSidebarBtn) {
closeSidebarBtn.addEventListener("click", closeSidebar);
}
if (sidebarOverlay) {
sidebarOverlay.addEventListener("click", closeSidebar);
}
// Close sidebar when clicking outside or on a link
document.addEventListener("click", (e) => {
if (sidebar && sidebar.classList.contains("open")) {
// Click outside sidebar and not on floating menu button
if (
!sidebar.contains(e.target) &&
!e.target.closest("#floatingMenuBtn")
) {
closeSidebar();
}
// Click on a nav link
if (e.target.closest(".sidebar-nav .nav-link")) {
closeSidebar();
}
}
});
// Handle scroll behavior to hide/show floating menu button smoothly
let lastScrollY = window.scrollY;
window.addEventListener("scroll", () => {
if (window.innerWidth <= 768 && floatingMenuBtn) {
if (window.scrollY > lastScrollY && window.scrollY > 100) {
// Scrolling down
floatingMenuBtn.style.display = "none";
} else {
// Scrolling up
floatingMenuBtn.style.display = "flex";
}
}
lastScrollY = window.scrollY;
});
}
+24
View File
@@ -0,0 +1,24 @@
// views/components/sidebar/sidebarLoader.js
document.addEventListener("DOMContentLoaded", function () {
const sidebarContainer = document.getElementById("sidebar-container");
if (!sidebarContainer) return;
// Load HTML
fetch("/components/sidebar/sidebar.html")
.then((response) => response.text())
.then((data) => {
sidebarContainer.innerHTML = data;
// Load CSS
const link = document.createElement("link");
link.rel = "stylesheet";
link.href = "/components/sidebar/sidebar.css";
document.head.appendChild(link);
// Load JS
const script = document.createElement("script");
script.src = "/components/sidebar/sidebar.js";
document.body.appendChild(script);
})
.catch((error) => console.error("Error loading sidebar:", error));
});