Operations dashboard screens are added
This commit is contained in:
@@ -1,14 +1,11 @@
|
||||
interface Props {
|
||||
label: string;
|
||||
value?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
import { FormProps } from "@/constants/types";
|
||||
export default function FormInput({
|
||||
label,
|
||||
value,
|
||||
type = "text",
|
||||
}: Props) {
|
||||
placeholder="string"
|
||||
}: FormProps) {
|
||||
return (
|
||||
<div>
|
||||
<label className="mb-2 block text-sm text-slate-400">
|
||||
@@ -18,7 +15,10 @@ export default function FormInput({
|
||||
<input
|
||||
type={type}
|
||||
defaultValue={value}
|
||||
placeholder={placeholder}
|
||||
|
||||
className="h-10 w-full rounded-xl border border-slate-700 text-white px-5"
|
||||
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
83
utils/navbar.tsx
Normal file
83
utils/navbar.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Search, HelpCircle, Globe, Sun, Bell, ChevronDown, MapPin } from 'lucide-react';
|
||||
|
||||
export default function Navbar() {
|
||||
return (
|
||||
/*
|
||||
- 'fixed top-0 right-0 left-64' anchors the navbar to the top of the screen,
|
||||
leaving room exactly for your 64-width sidebar.
|
||||
- 'bg-[#071321]' matches your master UI background.
|
||||
- 'h-16' gives it a consistent height.
|
||||
*/
|
||||
<header className="fixed top-0 right-0 left-64 z-30 flex h-16 items-center justify-between border-b border-[#142538]/50 bg-[#071321] px-8">
|
||||
|
||||
{/* Left Group */}
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Company Selector */}
|
||||
<div className="flex items-center gap-2 rounded-full bg-[#0a1826] px-3 py-1.5 text-sm font-semibold text-[#10b981] border border-[#132338] cursor-pointer hover:bg-[#0f2338] transition whitespace-nowrap">
|
||||
<span className="h-2 w-2 rounded-full bg-[#10b981] shrink-0"></span>
|
||||
<span className="font-semibold">Apple One</span>
|
||||
<ChevronDown className="h-3.5 w-3.5 text-[#10b981]" />
|
||||
</div>
|
||||
|
||||
{/* Location Selector */}
|
||||
<div className="flex items-center gap-2 rounded-full bg-[#0a1826] px-4 py-2 text-sm font-medium text-[#cbd5e1] border border-[#132338] cursor-pointer hover:bg-[#0f2338] transition whitespace-nowrap">
|
||||
<MapPin className="h-4 w-4 text-gray-500 shrink-0" />
|
||||
<span className="whitespace-nowrap">
|
||||
Apple One — <span className="text-[#cbd5e1] font-semibold">HQ Tower</span>
|
||||
</span>
|
||||
<ChevronDown className="h-4 w-4 text-gray-500 shrink-0" />
|
||||
</div>
|
||||
|
||||
{/* Search Bar */}
|
||||
<div className="relative w-60">
|
||||
<Search className="absolute left-4 top-2.5 h-4 w-4 text-gray-500" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search requests, equipment, met"
|
||||
className="w-full rounded-xl bg-[#0a1826] pl-10 pr-4 py-2 text-sm text-white placeholder-gray-500 border border-[#132338] focus:outline-none focus:border-[#3de0c4]/50"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Utilities */}
|
||||
<div className="flex items-center gap-3">
|
||||
{/* Tour */}
|
||||
<button className="flex items-center gap-2 rounded-xl border border-[#132338] bg-[#0a1826] px-4 py-2 text-sm font-semibold text-white transition hover:bg-[#14253d]">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<span>Tour</span>
|
||||
</button>
|
||||
|
||||
{/* Language */}
|
||||
<div className="flex items-center gap-1.5 rounded-xl border border-[#132338] bg-[#0a1826] px-4 py-2 text-sm font-semibold text-[#cbd5e1] cursor-pointer hover:bg-[#14253d]">
|
||||
<Globe className="h-4 w-4 text-gray-400" />
|
||||
<span>English</span>
|
||||
<ChevronDown className="h-4 w-4 text-gray-500" />
|
||||
</div>
|
||||
|
||||
{/* Live Indicator */}
|
||||
<div className="flex items-center gap-2 px-1 text-sm font-bold text-[#10b981] tracking-wider">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-[#10b981]"></span>
|
||||
<span className="text-xs font-bold text-gray-400">LIVE</span>
|
||||
</div>
|
||||
|
||||
{/* Theme Toggle */}
|
||||
<button className="flex h-9 w-9 items-center justify-center rounded-xl border border-[#132338] bg-[#0a1826] text-gray-400 hover:text-white transition">
|
||||
<Sun className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
{/* Notifications */}
|
||||
<div className="relative flex h-9 w-9 items-center justify-center rounded-xl border border-[#132338] bg-[#0a1826] cursor-pointer hover:bg-[#14253d] transition">
|
||||
<Bell className="h-4 w-4 text-gray-400" />
|
||||
<span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-[#ef4444] text-[9px] font-bold text-white">
|
||||
8
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Profile Avatar */}
|
||||
<div className="flex h-9 w-9 items-center justify-center rounded-full bg-[#1b3454] text-xs font-bold text-white cursor-pointer hover:opacity-90 transition">
|
||||
DH
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
49
utils/sideBarItem.tsx
Normal file
49
utils/sideBarItem.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import {Props} from "@/constants/types";
|
||||
import Button from "@/utils/button";
|
||||
|
||||
export default function SidebarItem({ item }: Props) {
|
||||
const [open, setOpen] = useState(item.title === "Overview");
|
||||
|
||||
return (
|
||||
<div className=" border-b border-slate-800 ">
|
||||
<Button
|
||||
onClick={() => setOpen(!open)}
|
||||
className="flex w-full items-center justify-between px-5 py-4 hover:bg-slate-900"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<item.icon size={20} />
|
||||
|
||||
<span className="font-medium">{item.title}</span>
|
||||
</div>
|
||||
|
||||
<ChevronDown
|
||||
size={18}
|
||||
className={`transition-transform ${
|
||||
open ? "rotate-180" : ""
|
||||
}`}
|
||||
/>
|
||||
</Button>
|
||||
|
||||
{open && item.children.length > 0 && (
|
||||
<div className="ml-6 border-l border-slate-700 pl-4 pb-2">
|
||||
{item.children.map((child: any) => (
|
||||
<Link
|
||||
key={child.title}
|
||||
href={child.href}
|
||||
className="group mt-2 flex items-center gap-3 rounded-lg px-3 py-2 text-slate-300 hover:bg-teal-500/20 hover:text-teal-400"
|
||||
>
|
||||
<child.icon size={18} />
|
||||
|
||||
<span>{child.title}</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
82
utils/sidebar.tsx
Normal file
82
utils/sidebar.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { SIDEBAR_ITEMS } from "@/constants/constant";
|
||||
import SidebarItem from "./sideBarItem";
|
||||
import {
|
||||
ShieldCheck,
|
||||
Activity,
|
||||
ChevronDown,
|
||||
ChevronsLeft,
|
||||
} from "lucide-react";
|
||||
import { useSession, signOut } from "next-auth/react";
|
||||
export default function Sidebar() {
|
||||
const { data: session } = useSession();
|
||||
console.log("Session data ",session?.user?.name)
|
||||
console.log("Session data ",session?.user?.email)
|
||||
return (
|
||||
<aside className="fixed bg-[#071321] text-white h-screen overflow-y-auto [scrollbar-color:#1b2a40_#071321] [scrollbar-width:thin]">
|
||||
<div className="flex items-center gap-2 px-2 pt-2 pb-3">
|
||||
<div className="flex h-9 w-9 items-center justify-center rounded-lg
|
||||
bg-[#3de0c4] font-bold text-[#05111d] text-sm">
|
||||
K
|
||||
</div>
|
||||
<span className="text-sm font-bold tracking-tight text-white">
|
||||
KA<span className="text-[#3de0c4]">FM</span>
|
||||
</span>
|
||||
</div>
|
||||
<hr className="border-[#142538]" />
|
||||
<div className="mx-4 my-4 flex rounded-xl
|
||||
bg-[#091624] p-2 border border-[#142538]">
|
||||
<button className="flex flex-1
|
||||
items-center justify-center gap-1 rounded-lg bg-[#3de0c4] py-1.5 text-xs
|
||||
text-black font-bold shadow-sm">
|
||||
<Activity size={14} />
|
||||
Operations
|
||||
</button>
|
||||
<button className="flex flex-1 items-center justify-center gap-1
|
||||
rounded-lg py-1 text-xs text-slate-400 font-medium hover:text-white transition-colors">
|
||||
<ShieldCheck size={14} />
|
||||
Admin
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="px-4 pt-2 pb-1 text-xs font-semibold uppercase
|
||||
tracking-wider text-slate-500">
|
||||
Tenant runtime
|
||||
</p>
|
||||
<div className="py-3">
|
||||
{SIDEBAR_ITEMS.map((item) => (
|
||||
<SidebarItem
|
||||
key={item.title}
|
||||
item={item}
|
||||
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="px-3 pb-2 pt-1
|
||||
border-t border-[#0f1f30]">
|
||||
<button className="flex w-full items-center gap-2 rounded-xl py-2 px-3 text-xs text-slate-400 hover:bg-[#091624] hover:text-white transition-colors">
|
||||
<ChevronsLeft size={16} />
|
||||
Minimise menu
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Profile Card Section */}
|
||||
<div className="m-3 mt-0 rounded-xl border border-[#142538] bg-[#071321] p-2.5">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex gap-2.5 items-center">
|
||||
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-cyan-600/50 bg-[#0d2430] text-cyan-400 text-xs font-bold">
|
||||
DT
|
||||
</div>
|
||||
<div className="min-w-0 leading-tight">
|
||||
<h4 className="font-semibold text-xs text-white truncate">{session?.user?.name}</h4>
|
||||
<p className="text-[11px] text-slate-500 truncate">
|
||||
{session?.user?.email}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<ChevronDown className="-rotate-90 text-slate-500 shrink-0" size={14}
|
||||
onClick={() => signOut({ callbackUrl: "/login" })} />
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
226
utils/table.tsx
Normal file
226
utils/table.tsx
Normal file
@@ -0,0 +1,226 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Pencil,
|
||||
Menu,
|
||||
ShieldCheck,
|
||||
QrCode,
|
||||
Power,
|
||||
Check,
|
||||
Sparkles,
|
||||
} from 'lucide-react';
|
||||
|
||||
// Data model interface
|
||||
interface TableRowData {
|
||||
id: string;
|
||||
block: string;
|
||||
floor: string;
|
||||
zone: string;
|
||||
department: string;
|
||||
location: string;
|
||||
window: string;
|
||||
tat: string;
|
||||
sched: number;
|
||||
approval: boolean;
|
||||
status: 'ACTIVE' | 'INACTIVE';
|
||||
}
|
||||
|
||||
// Sample data extracted from your screenshot
|
||||
const mockData: TableRowData[] = [
|
||||
{ id: '1', block: 'Block 1', floor: 'G', zone: 'Z2', department: 'Electrical', location: 'Main lobby', window: '06:00–17:30', tat: '60m', sched: 8, approval: true, status: 'INACTIVE' },
|
||||
{ id: '2', block: 'Block 2', floor: '3', zone: 'Z2', department: 'Electrical', location: 'Main lobby', window: '08:00–23:59', tat: '30m', sched: 4, approval: false, status: 'ACTIVE' },
|
||||
{ id: '3', block: 'Block 2', floor: '3', zone: 'Z1', department: 'Inspection work', location: 'Cafeteria', window: '06:00–17:30', tat: '20m', sched: 8, approval: true, status: 'ACTIVE' },
|
||||
{ id: '4', block: 'Block 1', floor: 'G', zone: 'Z1', department: 'HVAC', location: 'Server room', window: '08:00–18:00', tat: '30m', sched: 4, approval: false, status: 'INACTIVE' },
|
||||
{ id: '5', block: 'Block 2', floor: '3', zone: 'N', department: 'Inspection work', location: 'Server room', window: '08:00–18:00', tat: '60m', sched: 8, approval: true, status: 'ACTIVE' },
|
||||
{ id: '6', block: 'Block 2', floor: 'G', zone: 'Z1', department: 'Electrical', location: 'Reception', window: '06:00–18:00', tat: '60m', sched: 6, approval: false, status: 'ACTIVE' },
|
||||
{ id: '7', block: 'Block 1', floor: 'G', zone: 'Z2', department: 'Electrical', location: 'Food court', window: '06:00–17:30', tat: '60m', sched: 8, approval: true, status: 'ACTIVE' },
|
||||
{ id: '8', block: 'Block 2', floor: '3', zone: 'Z2', department: 'Electrical', location: 'Cafeteria', window: '08:00–23:59', tat: '30m', sched: 4, approval: false, status: 'ACTIVE' },
|
||||
{ id: '9', block: 'Block 2', floor: '3', zone: 'Z1', department: 'Inspection work', location: 'Gym', window: '06:00–17:30', tat: '20m', sched: 8, approval: true, status: 'INACTIVE' },
|
||||
{ id: '10', block: 'Block 1', floor: 'G', zone: 'Z1', department: 'HVAC', location: 'Lobby', window: '08:00–18:00', tat: '30m', sched: 4, approval: false, status: 'ACTIVE' },
|
||||
];
|
||||
|
||||
export default function LocationTable(){
|
||||
const [selectedIds, setSelectedIds] = useState<string[]>(['1']); // Row 1 selected by default (teal indicator bar)
|
||||
|
||||
const toggleSelectAll = () => {
|
||||
if (selectedIds.length === mockData.length) {
|
||||
setSelectedIds([]);
|
||||
} else {
|
||||
setSelectedIds(mockData.map((row) => row.id));
|
||||
}
|
||||
};
|
||||
|
||||
const toggleSelectRow = (id: string) => {
|
||||
setSelectedIds((prev) =>
|
||||
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id]
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full bg-[#071321] text-slate-300 rounded-xl overflow-hidden border border-slate-800/80 shadow-2xl relative font-sans">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left text-xs border-collapse">
|
||||
{/* TABLE HEADER */}
|
||||
<thead>
|
||||
<tr className="border-b border-slate-800/90 text-[11px] font-bold tracking-wider text-slate-500 uppercase font-mono">
|
||||
<th className="py-4 px-4 w-12 text-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedIds.length === mockData.length}
|
||||
onChange={toggleSelectAll}
|
||||
className="rounded border-slate-700 bg-slate-900/80 text-teal-400 focus:ring-0 focus:ring-offset-0 cursor-pointer accent-teal-400 h-3.5 w-3.5"
|
||||
/>
|
||||
</th>
|
||||
<th className="py-4 px-3 font-mono">BLOCK</th>
|
||||
<th className="py-4 px-3 font-mono">FLOOR</th>
|
||||
<th className="py-4 px-3 font-mono">ZONE</th>
|
||||
<th className="py-4 px-3 font-mono">DEPARTMENT</th>
|
||||
<th className="py-4 px-3 font-mono">LOCATION</th>
|
||||
<th className="py-4 px-3 font-mono">WINDOW</th>
|
||||
<th className="py-4 px-3 font-mono">TAT</th>
|
||||
<th className="py-4 px-3 font-mono">SCHED.</th>
|
||||
<th className="py-4 px-3 font-mono">APPROVAL</th>
|
||||
<th className="py-4 px-3 font-mono">STATUS</th>
|
||||
<th className="py-4 px-4 font-mono text-right pr-6">ACTIONS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
{/* TABLE BODY */}
|
||||
<tbody className="divide-y divide-slate-800/50">
|
||||
{mockData.map((row) => {
|
||||
const isSelected = selectedIds.includes(row.id);
|
||||
|
||||
return (
|
||||
<tr
|
||||
key={row.id}
|
||||
className={`group relative transition-colors ${
|
||||
isSelected
|
||||
? 'bg-[#0e2238]/60 hover:bg-[#122942]/80'
|
||||
: 'hover:bg-slate-800/30'
|
||||
}`}
|
||||
>
|
||||
{/* Left Selection Indicator Bar (for Row 1 / Selected Rows) */}
|
||||
<td className="py-3 px-4 text-center relative">
|
||||
{isSelected && (
|
||||
<span className="absolute left-0 top-0 bottom-0 w-[3px] bg-teal-400 rounded-r" />
|
||||
)}
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isSelected}
|
||||
onChange={() => toggleSelectRow(row.id)}
|
||||
className="rounded border-slate-700 bg-slate-900/80 text-teal-400 focus:ring-0 focus:ring-offset-0 cursor-pointer accent-teal-400 h-3.5 w-3.5"
|
||||
/>
|
||||
</td>
|
||||
|
||||
{/* Block */}
|
||||
<td className="py-3 px-3 font-semibold text-slate-100 whitespace-nowrap">
|
||||
{row.block}
|
||||
</td>
|
||||
|
||||
{/* Floor */}
|
||||
<td className="py-3 px-3 font-medium text-slate-200">
|
||||
{row.floor}
|
||||
</td>
|
||||
|
||||
{/* Zone */}
|
||||
<td className="py-3 px-3 font-medium text-slate-300">
|
||||
{row.zone}
|
||||
</td>
|
||||
|
||||
{/* Department */}
|
||||
<td className="py-3 px-3 font-semibold text-slate-200 whitespace-nowrap">
|
||||
{row.department}
|
||||
</td>
|
||||
|
||||
{/* Location */}
|
||||
<td className="py-3 px-3 font-extrabold text-white whitespace-nowrap">
|
||||
{row.location}
|
||||
</td>
|
||||
|
||||
{/* Window */}
|
||||
<td className="py-3 px-3 font-mono text-slate-400 text-[11px] whitespace-nowrap">
|
||||
{row.window}
|
||||
</td>
|
||||
|
||||
{/* TAT */}
|
||||
<td className="py-3 px-3 font-mono text-slate-200 font-medium">
|
||||
{row.tat}
|
||||
</td>
|
||||
|
||||
{/* Sched */}
|
||||
<td className="py-3 px-3 font-mono text-slate-200 font-medium">
|
||||
{row.sched}
|
||||
</td>
|
||||
|
||||
{/* Approval */}
|
||||
<td className="py-3 px-3 whitespace-nowrap">
|
||||
{row.approval ? (
|
||||
<span className="inline-flex items-center gap-1.5 text-emerald-400 font-semibold">
|
||||
<Check size={14} className="stroke-[3]" />
|
||||
<span>Yes</span>
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-slate-500 font-mono">——</span>
|
||||
)}
|
||||
</td>
|
||||
|
||||
{/* Status Badge */}
|
||||
<td className="py-3 px-3 whitespace-nowrap">
|
||||
{row.status === 'ACTIVE' ? (
|
||||
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[10px] font-bold font-mono tracking-wider bg-emerald-950/80 border border-emerald-800/40 text-emerald-400">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-emerald-400"></span>
|
||||
ACTIVE
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[10px] font-bold font-mono tracking-wider bg-slate-800/80 border border-slate-700/50 text-slate-400">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-slate-400"></span>
|
||||
INACTIVE
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
|
||||
{/* Action Icon Buttons */}
|
||||
<td className="py-3 px-4 text-right whitespace-nowrap pr-6">
|
||||
<div className="inline-flex items-center gap-1.5">
|
||||
<button
|
||||
title="Edit"
|
||||
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
|
||||
>
|
||||
<Pencil size={13} />
|
||||
</button>
|
||||
<button
|
||||
title="Options"
|
||||
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
|
||||
>
|
||||
<Menu size={13} />
|
||||
</button>
|
||||
<button
|
||||
title="Security"
|
||||
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
|
||||
>
|
||||
<ShieldCheck size={13} />
|
||||
</button>
|
||||
<button
|
||||
title="QR Code"
|
||||
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
|
||||
>
|
||||
<QrCode size={13} />
|
||||
</button>
|
||||
<button
|
||||
title="Toggle Power"
|
||||
className="p-1.5 rounded-md bg-[#0b1b2d] hover:bg-slate-700/60 border border-slate-800 text-slate-400 hover:text-slate-200 transition-colors"
|
||||
>
|
||||
<Power size={13} />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
36
utils/tabs.tsx
Normal file
36
utils/tabs.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
// @/utils/NavigationTabs.tsx
|
||||
import React from 'react';
|
||||
|
||||
interface NavigationTabsProps {
|
||||
tabs: string[];
|
||||
activeTab: string;
|
||||
onTabChange: (tab: string) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function NavigationTabs({
|
||||
tabs,
|
||||
activeTab,
|
||||
onTabChange,
|
||||
className = '',
|
||||
}: NavigationTabsProps) {
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center gap-8 border-b border-slate-800 text-sm font-semibold overflow-x-auto no-scrollbar ${className}`}
|
||||
>
|
||||
{tabs.map((tab) => (
|
||||
<button
|
||||
key={tab}
|
||||
onClick={() => onTabChange(tab)}
|
||||
className={`pb-3 relative transition-colors whitespace-nowrap ${
|
||||
activeTab === tab
|
||||
? 'text-teal-400 border-b-2 border-teal-400 font-bold'
|
||||
: 'text-slate-400 hover:text-slate-200'
|
||||
}`}
|
||||
>
|
||||
{tab}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user