123 lines
3.3 KiB
JavaScript
123 lines
3.3 KiB
JavaScript
/*
|
|
Copyright (C) 2025 QuantumNous
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
For commercial licensing, please contact support@quantumnous.com
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { Link, useLocation } from 'react-router-dom';
|
|
import { Box, LayoutDashboard, Trophy, BookOpen } from 'lucide-react';
|
|
import SkeletonWrapper from '../components/SkeletonWrapper';
|
|
|
|
const NAV_ICONS = {
|
|
pricing: Box,
|
|
console: LayoutDashboard,
|
|
benchmark: Trophy,
|
|
docs: BookOpen,
|
|
};
|
|
|
|
const Navigation = ({
|
|
mainNavLinks,
|
|
isMobile,
|
|
isLoading,
|
|
userState,
|
|
pricingRequireAuth,
|
|
}) => {
|
|
const location = useLocation();
|
|
|
|
const isActive = (linkPath) => {
|
|
if (!linkPath) return false;
|
|
const currentPath = location.pathname;
|
|
if (linkPath === "/") {
|
|
return currentPath === "/";
|
|
}
|
|
return currentPath.startsWith(linkPath);
|
|
};
|
|
|
|
const renderNavLinks = () => {
|
|
const baseClasses =
|
|
"flex-shrink-0 inline-flex items-center gap-1.5 text-[14px] transition-colors duration-150 rounded-md px-3 py-1.5";
|
|
const hoverClasses =
|
|
"hover:bg-accent hover:text-accent-foreground";
|
|
|
|
return mainNavLinks.map((link) => {
|
|
const Icon = NAV_ICONS[link.itemKey];
|
|
const linkContent = (
|
|
<>
|
|
{Icon && <Icon size={16} className="shrink-0" />}
|
|
<span>{link.text}</span>
|
|
</>
|
|
);
|
|
|
|
if (link.isExternal) {
|
|
const openInNewTab = link.openInNewTab !== false;
|
|
return (
|
|
<a
|
|
key={link.itemKey}
|
|
href={link.externalLink}
|
|
{...(openInNewTab
|
|
? { target: "_blank", rel: "noopener noreferrer" }
|
|
: {})}
|
|
className={`${baseClasses} ${hoverClasses} text-muted-foreground`}
|
|
>
|
|
{linkContent}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
let targetPath = link.to;
|
|
if (link.itemKey === "console" && !userState.user) {
|
|
targetPath = "/login";
|
|
}
|
|
if (link.itemKey === "pricing" && pricingRequireAuth && !userState.user) {
|
|
targetPath = "/login";
|
|
}
|
|
|
|
const active = isActive(link.to);
|
|
const activeClasses = active
|
|
? "bg-accent text-accent-foreground font-semibold"
|
|
: "text-muted-foreground";
|
|
|
|
return (
|
|
<Link
|
|
key={link.itemKey}
|
|
to={targetPath}
|
|
className={`${baseClasses} ${hoverClasses} ${activeClasses}`}
|
|
>
|
|
{linkContent}
|
|
</Link>
|
|
);
|
|
});
|
|
};
|
|
|
|
return (
|
|
<nav className="hidden md:flex items-center gap-1 overflow-x-auto whitespace-nowrap scrollbar-hide">
|
|
<SkeletonWrapper
|
|
loading={isLoading}
|
|
type="navigation"
|
|
count={4}
|
|
width={60}
|
|
height={16}
|
|
isMobile={isMobile}
|
|
>
|
|
{renderNavLinks()}
|
|
</SkeletonWrapper>
|
|
</nav>
|
|
);
|
|
};
|
|
|
|
export default Navigation;
|