← back to Norma

components/TabNav.tsx

99 lines

'use client';

import { FileText, Newspaper, Twitter, BookOpen, Settings, Megaphone, Award, Plug } from 'lucide-react';

/* ─── Types ──────────────────────────────────────────────────────────────── */
export type TabId = 'drafts' | 'news' | 'petitions' | 'grants' | 'xsessions' | 'library' | 'integrations' | 'settings';

interface Tab {
  id: TabId;
  label: string;
  Icon: React.ElementType;
}

interface TabNavProps {
  activeTab: TabId;
  onTabChange: (tab: TabId) => void;
}

/* ─── Tab Config ─────────────────────────────────────────────────────────── */
const TABS: Tab[] = [
  { id: 'drafts',    label: 'Drafts',     Icon: FileText   },
  { id: 'news',      label: 'News',       Icon: Newspaper  },
  { id: 'petitions', label: 'Petitions',  Icon: Megaphone  },
  { id: 'grants',    label: 'Grants',     Icon: Award      },
  { id: 'xsessions',    label: 'X Sessions',    Icon: Twitter    },
  { id: 'library',       label: 'Library',       Icon: BookOpen   },
  { id: 'integrations',  label: 'Integrations',  Icon: Plug       },
  { id: 'settings',      label: 'Settings',      Icon: Settings   },
];

/* ─── Component ──────────────────────────────────────────────────────────── */
export default function TabNav({ activeTab, onTabChange }: TabNavProps) {
  return (
    <nav
      aria-label="Main navigation"
      style={{
        backgroundColor: 'var(--color-surface)',
        borderBottom: '1px solid var(--color-border)',
      }}
    >
      {/* Scrollable container for mobile */}
      <div
        className="flex overflow-x-auto"
        style={{ scrollbarWidth: 'none' }}
      >
        {TABS.map(({ id, label, Icon }) => {
          const isActive = activeTab === id;
          return (
            <button
              key={id}
              onClick={() => onTabChange(id)}
              aria-current={isActive ? 'page' : undefined}
              className="relative flex items-center gap-2 px-4 py-3 text-sm font-medium whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset"
              style={{
                color: isActive
                  ? 'var(--color-text)'
                  : 'var(--color-text-secondary)',
                borderBottom: isActive
                  ? '2px solid var(--color-primary)'
                  : '2px solid transparent',
                marginBottom: '-1px',   /* Overlap container border */
                backgroundColor: 'transparent',
                cursor: 'pointer',
                flexShrink: 0,
              }}
              onMouseEnter={(e) => {
                if (!isActive) {
                  (e.currentTarget as HTMLButtonElement).style.color =
                    'var(--color-text)';
                }
              }}
              onMouseLeave={(e) => {
                if (!isActive) {
                  (e.currentTarget as HTMLButtonElement).style.color =
                    'var(--color-text-secondary)';
                }
              }}
            >
              <Icon
                size={16}
                aria-hidden="true"
                style={{
                  color: isActive
                    ? 'var(--color-primary)'
                    : 'currentColor',
                  flexShrink: 0,
                }}
              />
              <span className="hidden sm:inline">{label}</span>
              {/* Mobile: show only icon label (sr-only text) */}
              <span className="sr-only sm:hidden">{label}</span>
            </button>
          );
        })}
      </div>
    </nav>
  );
}