146 lines
5.5 KiB
TypeScript
Executable File
146 lines
5.5 KiB
TypeScript
Executable File
import React from 'react';
|
||
import { NAV_LINKS, ABOUT_CONTEXT_NAV_LINKS, BUSINESS_CONTEXT_NAV_LINKS, EDUCATION_CONTEXT_NAV_LINKS, ACCELERATOR_CONTEXT_NAV_LINKS, SECTION_IDS, APP_NAME, FOOTER_CONTENT } from '../constants';
|
||
import { NavLinkItem, CurrentView } from '../types';
|
||
import { ChevronRightIcon } from './icons';
|
||
import Logo from './Logo'; // Import the new Logo component
|
||
|
||
interface SidebarProps {
|
||
isOpen: boolean;
|
||
onClose: () => void;
|
||
currentView: CurrentView;
|
||
setCurrentView: (view: CurrentView) => void;
|
||
isDesktopCollapsed: boolean;
|
||
}
|
||
|
||
const Sidebar: React.FC<SidebarProps> = ({ isOpen, onClose, currentView, setCurrentView, isDesktopCollapsed }) => {
|
||
|
||
const scrollToSection = (hash: string) => {
|
||
if (hash.startsWith('#')) {
|
||
const sectionId = hash.substring(1);
|
||
const element = document.getElementById(sectionId);
|
||
if (element) {
|
||
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||
} else {
|
||
console.warn(`Element with ID ${sectionId} not found for scrolling.`);
|
||
}
|
||
} else {
|
||
console.warn(`Invalid hash for scrolling: ${hash}`);
|
||
}
|
||
};
|
||
|
||
const handleNavLinkClick = (item: NavLinkItem) => {
|
||
if (item.targetView) {
|
||
setCurrentView(item.targetView);
|
||
setTimeout(() => scrollToSection(item.href), 50); // Increased delay
|
||
} else {
|
||
setCurrentView('main');
|
||
setTimeout(() => scrollToSection(item.href), 50); // Increased delay
|
||
}
|
||
|
||
if (window.innerWidth < 768) { // md breakpoint
|
||
onClose();
|
||
}
|
||
};
|
||
|
||
const isAboutContextView = ['about', 'mission', 'careers'].includes(currentView);
|
||
const isBusinessContextView = ['businessLanding', 'businessServices'].includes(currentView);
|
||
const isEducationContextView = ['educationBusiness', 'educationStudents'].includes(currentView);
|
||
const isAcceleratorContextView = ['acceleratorAbout', 'acceleratorProjects', 'acceleratorInvestment'].includes(currentView);
|
||
|
||
let linksToRender: NavLinkItem[];
|
||
if (isAboutContextView) {
|
||
linksToRender = ABOUT_CONTEXT_NAV_LINKS;
|
||
} else if (isBusinessContextView) {
|
||
linksToRender = BUSINESS_CONTEXT_NAV_LINKS;
|
||
} else if (isEducationContextView) {
|
||
linksToRender = EDUCATION_CONTEXT_NAV_LINKS;
|
||
} else if (isAcceleratorContextView) {
|
||
linksToRender = ACCELERATOR_CONTEXT_NAV_LINKS;
|
||
} else {
|
||
linksToRender = NAV_LINKS;
|
||
}
|
||
|
||
const getLinkClasses = (item: NavLinkItem) => {
|
||
let baseClasses = `relative flex items-center p-3 rounded-lg hover:bg-slate-100
|
||
transition-colors duration-150
|
||
focus:outline-none focus:ring-2 focus:ring-slate-400 focus:bg-slate-100`;
|
||
|
||
if (item.label === 'На Главную') {
|
||
baseClasses += ' text-slate-500 hover:text-slate-700';
|
||
} else {
|
||
baseClasses += ' text-slate-700 hover:text-slate-900';
|
||
}
|
||
|
||
const isActive = (isAboutContextView || isBusinessContextView || isEducationContextView || isAcceleratorContextView) && item.targetView === currentView;
|
||
|
||
if (isActive) {
|
||
baseClasses += ' bg-slate-200 text-slate-900 font-semibold';
|
||
}
|
||
|
||
return baseClasses;
|
||
};
|
||
|
||
const sidebarClasses = `h-screen w-72 flex flex-col p-6 transform transition-all duration-300 ease-in-out
|
||
fixed top-0 left-0 z-40
|
||
bg-white/95 backdrop-blur-sm
|
||
md:bg-white md:z-30
|
||
${isOpen ? 'translate-x-0' : '-translate-x-full'}
|
||
${isDesktopCollapsed ? 'md:-translate-x-full' : 'md:translate-x-0'}`;
|
||
|
||
return (
|
||
<aside
|
||
id="sidebar-drawer"
|
||
className={sidebarClasses}
|
||
aria-label="Sidebar"
|
||
>
|
||
<div className="flex items-center justify-start mb-8 pl-1">
|
||
<a
|
||
href={`#${SECTION_IDS.hero}`}
|
||
onClick={(e) => {
|
||
e.preventDefault();
|
||
setCurrentView('main');
|
||
setTimeout(() => scrollToSection(`#${SECTION_IDS.hero}`), 50);
|
||
if (window.innerWidth < 768) onClose();
|
||
}}
|
||
className="flex items-center gap-3"
|
||
>
|
||
<Logo width={32} height={32} />
|
||
<span className={`font-quicksand text-2xl font-bold text-slate-900 transition-opacity duration-200 ${isDesktopCollapsed ? 'opacity-0' : 'opacity-100'}`}>
|
||
{APP_NAME}
|
||
</span>
|
||
</a>
|
||
</div>
|
||
|
||
<nav className="flex-grow flex flex-col justify-center overflow-y-auto no-scrollbar">
|
||
<ul className="space-y-2 font-medium">
|
||
{linksToRender.map((item: NavLinkItem) => (
|
||
<li key={item.id} className="group relative">
|
||
<a
|
||
href={item.href}
|
||
onClick={(e) => {
|
||
e.preventDefault();
|
||
handleNavLinkClick(item);
|
||
}}
|
||
className={`${getLinkClasses(item)}`}
|
||
>
|
||
{item.icon && <item.icon className="w-5 h-5 shrink-0 text-slate-500 group-hover:text-slate-700 transition-colors duration-150 mr-4" />}
|
||
<span className="font-quicksand text-base whitespace-nowrap">{item.label}</span>
|
||
{item.children && (
|
||
<ChevronRightIcon className="w-4 h-4 ml-auto opacity-50 group-hover:opacity-100 transition-opacity" />
|
||
)}
|
||
</a>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</nav>
|
||
|
||
<div className="pt-4 mt-8 border-t border-slate-200">
|
||
<p className="text-xs text-center text-slate-500">
|
||
{FOOTER_CONTENT.copyrightText(new Date().getFullYear())}
|
||
</p>
|
||
</div>
|
||
</aside>
|
||
);
|
||
};
|
||
|
||
export default Sidebar; |