Files
IdeA/frontend/src/shared/ui/Tabs.tsx
Blomios 307ae71857 feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
2026-06-06 01:27:01 +02:00

77 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** Tabs — a horizontal, optionally closable tab bar (LD).
*
* Presentation-only and controlled: the parent owns the active id and the open
* set. Used for the project tab bar (one tab per open project, ARCHITECTURE §10)
* but generic enough for any tabbed surface.
*/
import { cn } from "../lib/cn";
import { IconButton } from "./IconButton";
export interface TabItem {
/** Stable id, returned by `onSelect`/`onClose`. */
id: string;
/** Visible label. */
label: string;
}
export interface TabsProps {
/** Tabs to render, left to right. */
items: TabItem[];
/** Currently-active tab id. */
value: string | null;
/** Called with the id of the tab the user activates. */
onSelect: (id: string) => void;
/** When provided, each tab shows a close (×) control. */
onClose?: (id: string) => void;
className?: string;
}
/** A themed tab strip with selection and optional per-tab close. */
export function Tabs({ items, value, onSelect, onClose, className }: TabsProps) {
return (
<div
role="tablist"
className={cn("flex flex-wrap items-stretch gap-1", className)}
>
{items.map((tab) => {
const active = tab.id === value;
return (
<div
key={tab.id}
className={cn(
"group flex items-center gap-1 rounded-md border px-1 transition-colors",
active
? "border-border-strong bg-raised"
: "border-transparent hover:bg-raised",
)}
>
<button
type="button"
role="tab"
aria-selected={active}
onClick={() => onSelect(tab.id)}
className={cn(
"px-2 py-1 text-sm focus-visible:outline-none",
active ? "font-semibold text-content" : "text-muted hover:text-content",
)}
>
{tab.label}
</button>
{onClose && (
<IconButton
size="sm"
aria-label={`close ${tab.label}`}
onClick={() => onClose(tab.id)}
className="opacity-60 group-hover:opacity-100"
>
×
</IconButton>
)}
</div>
);
})}
</div>
);
}