Files
pulse/components/ui/card.tsx
Usman Baig 033d735c3a Replace dashboard BarChart with 21st.dev LineChart component
Swap the main site dashboard chart from a bar chart to a line chart
using 21st.dev's line-charts-6 component with dot grid background,
glow shadow, and animated active dots. Add Badge trend indicators
on metric cards using Phosphor icons. All existing features preserved
(annotations, comparison, export, live indicator, interval controls).

New UI primitives: line-charts-6, badge-2, card, button-1, avatar.
Added shadcn-compatible CSS variables and Tailwind color mappings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 22:53:35 +01:00

148 lines
4.1 KiB
TypeScript

'use client';
import * as React from 'react';
import { cn } from '@/lib/utils';
import { cva, type VariantProps } from 'class-variance-authority';
// Define CardContext
type CardContextType = {
variant: 'default' | 'accent';
};
const CardContext = React.createContext<CardContextType>({
variant: 'default', // Default value
});
// Hook to use CardContext
const useCardContext = () => {
const context = React.useContext(CardContext);
if (!context) {
throw new Error('useCardContext must be used within a Card component');
}
return context;
};
// Variants
const cardVariants = cva('flex flex-col items-stretch text-card-foreground rounded-xl', {
variants: {
variant: {
default: 'bg-card border border-border shadow-xs black/5',
accent: 'bg-muted shadow-xs p-1',
},
},
defaultVariants: {
variant: 'default',
},
});
const cardHeaderVariants = cva('flex items-center justify-between flex-wrap px-5 min-h-14 gap-2.5', {
variants: {
variant: {
default: 'border-b border-border',
accent: '',
},
},
defaultVariants: {
variant: 'default',
},
});
const cardContentVariants = cva('grow p-5', {
variants: {
variant: {
default: '',
accent: 'bg-card rounded-t-xl [&:last-child]:rounded-b-xl',
},
},
defaultVariants: {
variant: 'default',
},
});
const cardTableVariants = cva('grid grow', {
variants: {
variant: {
default: '',
accent: 'bg-card rounded-xl',
},
},
defaultVariants: {
variant: 'default',
},
});
const cardFooterVariants = cva('flex items-center px-5 min-h-14', {
variants: {
variant: {
default: 'border-t border-border',
accent: 'bg-card rounded-b-xl mt-[2px]',
},
},
defaultVariants: {
variant: 'default',
},
});
// Card Component
function Card({
className,
variant = 'default',
...props
}: React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof cardVariants>) {
return (
<CardContext.Provider value={{ variant: variant || 'default' }}>
<div data-slot="card" className={cn(cardVariants({ variant }), className)} {...props} />
</CardContext.Provider>
);
}
// CardHeader Component
function CardHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
const { variant } = useCardContext();
return <div data-slot="card-header" className={cn(cardHeaderVariants({ variant }), className)} {...props} />;
}
// CardContent Component
function CardContent({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
const { variant } = useCardContext();
return <div data-slot="card-content" className={cn(cardContentVariants({ variant }), className)} {...props} />;
}
// CardTable Component
function CardTable({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
const { variant } = useCardContext();
return <div data-slot="card-table" className={cn(cardTableVariants({ variant }), className)} {...props} />;
}
// CardFooter Component
function CardFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
const { variant } = useCardContext();
return <div data-slot="card-footer" className={cn(cardFooterVariants({ variant }), className)} {...props} />;
}
// Other Components
function CardHeading({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return <div data-slot="card-heading" className={cn('space-y-1', className)} {...props} />;
}
function CardToolbar({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return <div data-slot="card-toolbar" className={cn('flex items-center gap-2.5', className)} {...props} />;
}
function CardTitle({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) {
return (
<h3
data-slot="card-title"
className={cn('text-base font-semibold leading-none tracking-tight', className)}
{...props}
/>
);
}
function CardDescription({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return <div data-slot="card-description" className={cn('text-sm text-muted-foreground', className)} {...props} />;
}
// Exports
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardHeading, CardTable, CardTitle, CardToolbar };