Ctrl K
ComunidadGuías…

dashboard/src/components/layout/Sidebar.tsx

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import React, { useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import '@/styles/sidebar.css';

interface SidebarProps {
  isOpen?: boolean;
  onClose?: () => void;
}

export const Sidebar: React.FC<SidebarProps> = ({ isOpen, onClose }) => {
  const navigate = useNavigate();
  const location = useLocation();
  const currentPath = location.pathname.split('/')[1] || 'applications';

  useEffect(() => {
    const previousOverflow = document.body.style.overflow;

    if (isOpen) {
      document.body.style.overflow = 'hidden';
    } else {
      document.body.style.overflow = previousOverflow || '';
    }

    return () => {
      document.body.style.overflow = previousOverflow;
    };
  }, [isOpen]);

  // Active tab on a subpage (/applications/<app>, ?page=3) stays clickable: it is the way back.
  const isOnPage = (page: string) =>
    page === currentPath && location.pathname.replace(/\/+$/, '').split('/').length <= 2 && !location.search;

  const getButtonClass = (page: string) => {
    const baseClass = "sidebar-nav-button flex items-center";
    if (page !== currentPath) return baseClass;
    return isOnPage(page) ? `${baseClass} active current` : `${baseClass} active`;
  };

  const handleNavigation = (path: string) => {
    if (!isOnPage(path)) navigate(`/${path}`);
    onClose?.(); // close drawer on mobile after navigation
  };

  // Drawer for mobile
  const Drawer = () => (
    <div className={`fixed inset-0 z-200 flex md:hidden transition-all duration-300 ${isOpen ? '' : 'pointer-events-none'}`}> 
      {/* Overlay */}
      <div
        className={`fixed inset-0 sidebar-drawer-overlay transition-opacity duration-300 ${isOpen ? 'opacity-100' : 'opacity-0'}`}
        onClick={onClose}
        aria-label="Close menu overlay"
      />
      {/* Drawer panel */}
      <aside className={`relative w-64 max-w-[80vw] h-full sidebar-drawer-panel transform transition-transform duration-300 ${isOpen ? 'translate-x-0' : '-translate-x-full'}`}>
                <div className="p-6 pt-3">
          <div className="mb-3 flex items-center justify-between w-full">
            <div 
              onClick={() => { navigate('/applications'); onClose?.(); }}
              className="w-full cursor-pointer sidebar-logo"
            >
              <img
                src={`${import.meta.env.BASE_URL}banner-small.png`}
                alt="FaynoSync Logo"
                className="w-full h-[80px] object-contain rounded-lg"
              />
            </div>
            <button
              className="ml-2 sidebar-close-button"
              aria-label="Close menu"
              onClick={onClose}
            >
              <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
              </svg>
            </button>
          </div>
          <nav>
            <button 
              className={getButtonClass('applications')}
              aria-current={isOnPage('applications') ? 'page' : undefined}
              onClick={() => handleNavigation('applications')}
            >
              <i className="fas fa-th-large"></i>
              <span>Applications</span>
            </button>
            <button 
              className={getButtonClass('channels')}
              aria-current={isOnPage('channels') ? 'page' : undefined}
              onClick={() => handleNavigation('channels')}
            >
              <i className="fas fa-broadcast-tower"></i>
              <span>Channels</span>
            </button>
            <button 
              className={getButtonClass('platforms')}
              aria-current={isOnPage('platforms') ? 'page' : undefined}
              onClick={() => handleNavigation('platforms')}
            >
              <i className="fas fa-desktop"></i>
              <span>Platforms</span>
            </button>
            <button 
              className={getButtonClass('architectures')}
              aria-current={isOnPage('architectures') ? 'page' : undefined}
              onClick={() => handleNavigation('architectures')}
            >
              <i className="fas fa-microchip"></i>
              <span>Architectures</span>
            </button>
            <button
              className={getButtonClass('statistics')}
              aria-current={isOnPage('statistics') ? 'page' : undefined}
              onClick={() => handleNavigation('statistics')}
            >
              <i className="fas fa-chart-bar"></i>
              <span>Statistics</span>
            </button>
            <button
              className={getButtonClass('reports')}
              aria-current={isOnPage('reports') ? 'page' : undefined}
              onClick={() => handleNavigation('reports')}
            >
              <i className="fas fa-flag"></i>
              <span>Reports</span>
            </button>
          </nav>
        </div>
      </aside>
    </div>
  );

  return (
    <>
      {/* Drawer only on mobile */}
      <Drawer />
      {/* Sidebar only on desktop */}
      <aside className="hidden md:block w-64 min-h-screen sidebar">
        <div className="p-6 pt-3">
          <div className="mb-3 flex items-center justify-center w-full">
            <div 
              onClick={() => navigate('/applications')}
              className="w-full cursor-pointer sidebar-logo"
            >
              <img
                src={`${import.meta.env.BASE_URL}banner-small.png`}
                alt="FaynoSync Logo"
                className="w-full h-[80px] object-contain rounded-lg"
              />
            </div>
          </div>
          <nav>
            <button 
              className={getButtonClass('applications')}
              aria-current={isOnPage('applications') ? 'page' : undefined}
              onClick={() => handleNavigation('applications')}
            >
              <i className="fas fa-th-large"></i>
              <span>Applications</span>
            </button>
            <button 
              className={getButtonClass('channels')}
              aria-current={isOnPage('channels') ? 'page' : undefined}
              onClick={() => handleNavigation('channels')}
            >
              <i className="fas fa-broadcast-tower"></i>
              <span>Channels</span>
            </button>
            <button 
              className={getButtonClass('platforms')}
              aria-current={isOnPage('platforms') ? 'page' : undefined}
              onClick={() => handleNavigation('platforms')}
            >
              <i className="fas fa-desktop"></i>
              <span>Platforms</span>
            </button>
            <button 
              className={getButtonClass('architectures')}
              aria-current={isOnPage('architectures') ? 'page' : undefined}
              onClick={() => handleNavigation('architectures')}
            >
              <i className="fas fa-microchip"></i>
              <span>Architectures</span>
            </button>
            <button
              className={getButtonClass('statistics')}
              aria-current={isOnPage('statistics') ? 'page' : undefined}
              onClick={() => handleNavigation('statistics')}
            >
              <i className="fas fa-chart-bar"></i>
              <span>Statistics</span>
            </button>
            <button
              className={getButtonClass('reports')}
              aria-current={isOnPage('reports') ? 'page' : undefined}
              onClick={() => handleNavigation('reports')}
            >
              <i className="fas fa-flag"></i>
              <span>Reports</span>
            </button>
          </nav>
        </div>
      </aside>
    </>
  );
};