Skip to content

Commit

Permalink
Merge pull request #29 from Siddami/dev_cncomponentstyling
Browse files Browse the repository at this point in the history
Dev cncomponentstyling
  • Loading branch information
basii199 authored Mar 6, 2025
2 parents 53e5d63 + a7e068b commit 9807b29
Show file tree
Hide file tree
Showing 2 changed files with 243 additions and 20 deletions.
90 changes: 70 additions & 20 deletions components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,83 @@ const buttonVariants = cva(
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
icon: "size-9",
},
fullWidth: {
true: "w-full",
false: "",
},
},
defaultVariants: {
variant: "default",
size: "default",
fullWidth: false,
},
}
)

function Button({
className,
variant,
size,
asChild = false,
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot : "button"

return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
fullWidth?: boolean
loading?: boolean
leftIcon?: React.ReactNode
rightIcon?: React.ReactNode
}

export { Button, buttonVariants }
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({
className,
variant,
size,
fullWidth,
asChild = false,
loading = false,
leftIcon,
rightIcon,
children,
disabled,
...props
}, ref) => {
const Comp = asChild ? Slot : "button"
const isDisabled = disabled || loading

return (
<Comp
className={cn(buttonVariants({ variant, size, fullWidth, className }))}
ref={ref}
disabled={isDisabled}
{...props}
>
{loading && (
<svg
className="animate-spin -ml-1 mr-2 h-4 w-4"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
)}

{!loading && leftIcon && <span className="button-icon">{leftIcon}</span>}
{children}
{!loading && rightIcon && <span className="button-icon">{rightIcon}</span>}
</Comp>
)
}
)
Button.displayName = "Button"

export { Button }
173 changes: 173 additions & 0 deletions components/ui/card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import * as React from "react"
import { cn } from "@/lib/utils"
import { cva, type VariantProps } from "class-variance-authority"

const cardVariants = cva(
"rounded-xl border shadow-sm",
{
variants: {
variant: {
default: "bg-card text-card-foreground",
outlined: "bg-white border-2",
elevated: "bg-white shadow-md",
ghost: "bg-transparent border-none shadow-none"
},
size: {
default: "w-full",
sm: "w-64",
md: "w-80",
lg: "w-96"
},
highlight: {
true: "border-primary border-2",
false: ""
},
layout: {
col: "flex flex-col gap-6",
row: "flex flex-row items-center gap-6"
}
},
defaultVariants: {
variant: "default",
size: "default",
highlight: false,
layout: "col"
}
}
)

interface CardProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof cardVariants> {}

const CardRoot = React.forwardRef<HTMLDivElement, CardProps>(({
className,
variant,
size,
highlight,
layout,
children,
...props
}, ref) => {
return (
<div
ref={ref}
data-slot="card"
className={cn(cardVariants({ variant, size, highlight, layout, className }))}
{...props}
>
{children}
</div>
)
})
CardRoot.displayName = "Card"

const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-slot="card-header"
className={cn("flex flex-col gap-1.5 px-6", className)}
{...props}
/>
)
})
CardHeader.displayName = "Card.Header"

const CardTitle = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-slot="card-title"
className={cn("text-xl leading-none font-semibold", className)}
{...props}
/>
)
})
CardTitle.displayName = "Card.Title"

const CardDescription = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-slot="card-description"
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
)
})
CardDescription.displayName = "Card.Description"

const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-slot="card-content"
className={cn("px-6 flex-grow", className)}
{...props}
/>
)
})
CardContent.displayName = "Card.Content"

const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-slot="card-footer"
className={cn("flex items-center px-6 mt-auto", className)}
{...props}
/>
)
})
CardFooter.displayName = "Card.Footer"

// Helper function for simple card creation
const createCard = (
content: React.ReactNode,
title?: React.ReactNode,
description?: React.ReactNode,
footer?: React.ReactNode,
cardProps?: Omit<CardProps, 'children'>
) => {
return (
<CardRoot {...cardProps}>
{(title || description) && (
<CardHeader>
{title && <CardTitle>{title}</CardTitle>}
{description && <CardDescription>{description}</CardDescription>}
</CardHeader>
)}
<CardContent>{content}</CardContent>
{footer && <CardFooter>{footer}</CardFooter>}
</CardRoot>
);
};


const Card = Object.assign(CardRoot, {
Header: CardHeader,
Title: CardTitle,
Description: CardDescription,
Content: CardContent,
Footer: CardFooter,
create: createCard
});


export { Card }

0 comments on commit 9807b29

Please sign in to comment.