feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
This commit is contained in:
76
frontend/src/shared/ui/Tabs.tsx
Normal file
76
frontend/src/shared/ui/Tabs.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
/** 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user