Sidebar.tsx 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import React, { useContext } from 'react';
  2. import { BrandingContext } from '../App';
  3. import { NavLink } from 'react-router-dom';
  4. import {
  5. Home,
  6. LayoutGrid,
  7. Key,
  8. } from '../icons/commonIcons';
  9. export type PageId = 'home' | 'models' | 'profile' | 'platform';
  10. const navItems: { id: PageId; icon: any; label: string; path: string }[] = [
  11. { id: 'home', icon: Home, label: '首页', path: '/' },
  12. { id: 'models', icon: LayoutGrid, label: '模型广场', path: '/models' },
  13. { id: 'platform', icon: Key, label: '开放平台', path: '/platform' },
  14. ];
  15. const Sidebar: React.FC = () => {
  16. const branding = useContext(BrandingContext);
  17. return (
  18. <>
  19. {/* 桌面端侧边栏 */}
  20. <aside className="hidden md:flex w-fit h-[calc(100vh-4rem)] bg-white border-r border-gray-100 flex-col fixed left-0 top-14 sm:top-16">
  21. <nav className="flex-1 overflow-y-auto pt-4">
  22. {navItems.map((item) => (
  23. <NavLink
  24. key={item.id}
  25. to={item.path}
  26. className={({ isActive }) =>
  27. `flex items-center space-x-3 px-4 lg:px-6 py-3 lg:py-4 cursor-pointer transition-all group ${
  28. isActive
  29. ? 'bg-blue-50 text-blue-600 border-r-4 border-blue-600 font-bold'
  30. : 'text-gray-500 hover:bg-gray-50 hover:text-blue-600'
  31. }`
  32. }
  33. >
  34. {({ isActive }) => (
  35. <>
  36. <item.icon
  37. className={`w-5 h-5 flex-shrink-0 ${
  38. isActive
  39. ? 'text-blue-600'
  40. : 'text-gray-400 group-hover:text-blue-600'
  41. }`}
  42. />
  43. <span className="text-sm font-medium">{item.label}</span>
  44. </>
  45. )}
  46. </NavLink>
  47. ))}
  48. </nav>
  49. <div className="p-4 lg:p-6 border-t border-gray-50">
  50. <p className="text-[10px] text-gray-400 text-center">© 2026 {branding.system_name}</p>
  51. </div>
  52. </aside>
  53. {/* 移动端底部导航栏 */}
  54. <nav className="md:hidden fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 z-40 flex items-center justify-around px-1 py-1 safe-pb">
  55. {navItems.map((item) => (
  56. <NavLink
  57. key={item.id}
  58. to={item.path}
  59. className={({ isActive }) =>
  60. `flex flex-col items-center justify-center px-2 py-1.5 rounded-lg transition-all min-w-0 flex-1 ${
  61. isActive
  62. ? 'text-blue-600'
  63. : 'text-gray-400 hover:text-blue-600'
  64. }`
  65. }
  66. >
  67. {({ isActive }) => (
  68. <>
  69. <item.icon className={`w-5 h-5 flex-shrink-0 ${isActive ? 'text-blue-600' : 'text-gray-400'}`} />
  70. <span className="text-[10px] mt-0.5 font-medium truncate w-full text-center">{item.label}</span>
  71. </>
  72. )}
  73. </NavLink>
  74. ))}
  75. </nav>
  76. </>
  77. );
  78. };
  79. export default Sidebar;