update design

This commit is contained in:
Rami Bitar
2026-06-10 13:47:50 -04:00
parent b5a79b6475
commit b212250da0
96 changed files with 7486 additions and 6441 deletions

View File

@@ -1,143 +1,91 @@
import React, { createContext, useContext, useState } from 'react';
import { cn } from '@/lib/utils';
"use client"
interface TabsContextType {
activeTab: string;
setActiveTab: (value: string) => void;
}
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import { cva, type VariantProps } from "class-variance-authority"
const TabsContext = createContext<TabsContextType | undefined>(undefined);
function useTabs() {
const context = useContext(TabsContext);
if (!context) {
throw new Error('Tabs components must be used within a Tabs component');
}
return context;
}
interface TabsProps extends React.HTMLAttributes<HTMLDivElement> {
defaultValue?: string;
value?: string;
onValueChange?: (value: string) => void;
}
import { cn } from "@/lib/utils"
function Tabs({
className,
defaultValue,
value: controlledValue,
onValueChange,
children,
orientation = "horizontal",
...props
}: TabsProps) {
const [internalValue, setInternalValue] = useState(defaultValue || '');
const isControlled = controlledValue !== undefined;
const activeTab = isControlled ? controlledValue : internalValue;
const handleValueChange = (newValue: string) => {
if (!isControlled) {
setInternalValue(newValue);
}
onValueChange?.(newValue);
};
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
return (
<TabsContext.Provider
value={{ activeTab, setActiveTab: handleValueChange }}
>
<div
data-slot="tabs"
className={cn('flex flex-col gap-2', className)}
{...props}
>
{children}
</div>
</TabsContext.Provider>
);
}
interface TabsListProps extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
}
function TabsList({ className, children, ...props }: TabsListProps) {
return (
<div
data-slot="tabs-list"
<TabsPrimitive.Root
data-slot="tabs"
data-orientation={orientation}
orientation={orientation}
className={cn(
'bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]',
"group/tabs flex gap-2 data-[orientation=horizontal]:flex-col",
className
)}
role="tablist"
{...props}
>
{children}
</div>
);
/>
)
}
interface TabsTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
value: string;
children: React.ReactNode;
const tabsListVariants = cva(
"rounded-lg p-[3px] group-data-[orientation=horizontal]/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
{
variants: {
variant: {
default: "bg-muted",
line: "gap-1 bg-transparent",
},
},
defaultVariants: {
variant: "default",
},
}
)
function TabsList({
className,
variant = "default",
...props
}: React.ComponentProps<typeof TabsPrimitive.List> &
VariantProps<typeof tabsListVariants>) {
return (
<TabsPrimitive.List
data-slot="tabs-list"
data-variant={variant}
className={cn(tabsListVariants({ variant }), className)}
{...props}
/>
)
}
function TabsTrigger({
className,
value,
children,
...props
}: TabsTriggerProps) {
const { activeTab, setActiveTab } = useTabs();
const isActive = activeTab === value;
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
return (
<button
<TabsPrimitive.Trigger
data-slot="tabs-trigger"
role="tab"
aria-selected={isActive}
aria-controls={`tabs-content-${value}`}
className={cn(
'text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*="size-"])]:size-4',
isActive &&
'bg-background dark:bg-input/30 dark:border-input shadow-sm',
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 data-[state=active]:text-foreground",
"after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
className
)}
onClick={() => setActiveTab(value)}
{...props}
>
{children}
</button>
);
}
interface TabsContentProps extends React.HTMLAttributes<HTMLDivElement> {
value: string;
children: React.ReactNode;
/>
)
}
function TabsContent({
className,
value,
children,
...props
}: TabsContentProps) {
const { activeTab } = useTabs();
if (activeTab !== value) {
return null;
}
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
return (
<div
<TabsPrimitive.Content
data-slot="tabs-content"
role="tabpanel"
id={`tabs-content-${value}`}
className={cn('flex-1 outline-none', className)}
className={cn("flex-1 outline-none", className)}
{...props}
>
{children}
</div>
);
/>
)
}
export { Tabs, TabsList, TabsTrigger, TabsContent };
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }