132 lines
4.7 KiB
JavaScript
132 lines
4.7 KiB
JavaScript
"use client";
|
||
import Link from "next/link";
|
||
import React, { useEffect, useState } from "react";
|
||
import Image from "next/image";
|
||
import {
|
||
blockItems,
|
||
blogItems,
|
||
demos,
|
||
docsPages,
|
||
otherPages,
|
||
projectPages,
|
||
} from "@/data/menu";
|
||
import { usePathname } from "next/navigation";
|
||
// !text-[var(--current-color)]
|
||
export default function Nav({ color = "#fab758" }) {
|
||
const [menu, setMenu] = useState([]);
|
||
const pathname = usePathname();
|
||
|
||
useEffect(() => {
|
||
// Dynamically import Bootstrap
|
||
import("bootstrap").then((Bootstrap) => {
|
||
const CLASS_NAME = "has-child-dropdown-show";
|
||
|
||
// Save the original toggle function
|
||
const originalToggle = Bootstrap.Dropdown.prototype.toggle;
|
||
|
||
// Override the toggle function
|
||
Bootstrap.Dropdown.prototype.toggle = function () {
|
||
// Remove the CLASS_NAME from all dropdowns
|
||
document.querySelectorAll("." + CLASS_NAME).forEach(function (e) {
|
||
e.classList.remove(CLASS_NAME);
|
||
});
|
||
|
||
// Traverse up through the closest dropdown parents
|
||
let dd = this._element
|
||
.closest(".dropdown")
|
||
.parentNode.closest(".dropdown");
|
||
for (; dd && dd !== document; dd = dd.parentNode.closest(".dropdown")) {
|
||
dd.classList.add(CLASS_NAME);
|
||
}
|
||
|
||
// Call the original toggle function
|
||
return originalToggle.call(this);
|
||
};
|
||
|
||
// Add event listeners for hide.bs.dropdown to remove the CLASS_NAME
|
||
document.querySelectorAll(".dropdown").forEach(function (dd) {
|
||
dd.addEventListener("hide.bs.dropdown", function (e) {
|
||
if (this.classList.contains(CLASS_NAME)) {
|
||
this.classList.remove(CLASS_NAME);
|
||
e.preventDefault();
|
||
}
|
||
e.stopPropagation();
|
||
});
|
||
});
|
||
});
|
||
|
||
// 获取菜单数据
|
||
fetch("/api/get-menu")
|
||
.then((res) => res.json())
|
||
.then((data) => setMenu(data.menu || []));
|
||
|
||
// Optional cleanup function for any potential side effects
|
||
return () => {
|
||
// Cleanup code here (if needed)
|
||
};
|
||
}, []);
|
||
|
||
// 只在顶级菜单过滤 position
|
||
const filterHeaderMenu = (items) => {
|
||
return items.filter(item => item.position === 'Header');
|
||
};
|
||
|
||
// 递归渲染菜单
|
||
const renderMenu = (items, level = 0) => {
|
||
// 顶级菜单过滤 position
|
||
if (level === 0) items = filterHeaderMenu(items);
|
||
return items.map((item) => {
|
||
const hasChildren = item.children && item.children.length > 0;
|
||
const hasHref = !!item.href && item.href !== "#";
|
||
if (hasChildren) {
|
||
return (
|
||
<li key={item.id} className={`nav-item dropdown${level > 0 ? " dropdown-submenu dropend" : ""}`}>
|
||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||
{/* 如果有href,左侧为可点击跳转,始终用当前item的href */}
|
||
{hasHref && (
|
||
<Link
|
||
className={`${level > 0 ? "dropdown-item" : "nav-link"} !text-[.85rem] !tracking-[normal] hover:!text-[var(--current-color)] after:!text-[var(--current-color)] ${pathname === item.href ? "!text-[var(--current-color)]" : ""}`}
|
||
href={item.href}
|
||
style={{ paddingRight: 0 }}
|
||
>
|
||
{item.label}
|
||
</Link>
|
||
)}
|
||
{/* 右侧小三角,负责展开下拉 */}
|
||
<a
|
||
className={`${hasHref ? "dropdown-toggle" : (level > 0 ? "dropdown-item" : "nav-link") + " dropdown-toggle"} !text-[.85rem] !tracking-[normal] hover:!text-[var(--current-color)] after:!text-[var(--current-color)] ${!hasHref && pathname === item.href ? "!text-[var(--current-color)]" : ""}`}
|
||
href="#"
|
||
data-bs-toggle="dropdown"
|
||
aria-expanded="false"
|
||
style={hasHref ? { paddingLeft: 8, minWidth: 24 } : {}}
|
||
>
|
||
{hasHref ? <span className="sr-only">展开</span> : item.label}
|
||
</a>
|
||
</div>
|
||
<ul className={`dropdown-menu${level > 0 ? " submenu" : ""}`}>
|
||
{renderMenu(item.children, level + 1)}
|
||
</ul>
|
||
</li>
|
||
);
|
||
} else {
|
||
return (
|
||
<li key={item.id} className="nav-item">
|
||
<Link
|
||
className={`${level > 0 ? "dropdown-item" : "nav-link"} !text-[.85rem] !tracking-[normal] hover:!text-[var(--current-color)] after:!text-[var(--current-color)] ${pathname === item.href ? "!text-[var(--current-color)]" : ""}`}
|
||
href={item.href || "#"}
|
||
>
|
||
{item.label}
|
||
</Link>
|
||
</li>
|
||
);
|
||
}
|
||
});
|
||
};
|
||
|
||
return (
|
||
<ul className="navbar-nav" style={{ "--current-color": color }}>
|
||
{renderMenu(menu)}
|
||
</ul>
|
||
);
|
||
}
|