initial commit
This commit is contained in:
151
templates/component.template.tsx
Normal file
151
templates/component.template.tsx
Normal file
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Component Template
|
||||
*
|
||||
* Usage: Copy this file to create new components
|
||||
* 1. Replace TEMPLATE_NAME with your component name
|
||||
* 2. Define the props interface
|
||||
* 3. Implement your component logic
|
||||
*/
|
||||
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
// Component props interface
|
||||
interface TemplateComponentProps {
|
||||
// Define your props here
|
||||
className?: string
|
||||
children?: React.ReactNode
|
||||
// Add other props as needed
|
||||
title?: string
|
||||
description?: string
|
||||
variant?: 'default' | 'secondary' | 'outline'
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
disabled?: boolean
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* TEMPLATE_NAME Component
|
||||
*
|
||||
* @param props - Component properties
|
||||
* @returns JSX element
|
||||
*/
|
||||
export function TemplateComponent({
|
||||
className,
|
||||
children,
|
||||
title,
|
||||
description,
|
||||
variant = 'default',
|
||||
size = 'md',
|
||||
disabled = false,
|
||||
onClick,
|
||||
...props
|
||||
}: TemplateComponentProps) {
|
||||
// State management
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
// Event handlers
|
||||
const handleClick = async () => {
|
||||
if (disabled || isLoading) return
|
||||
|
||||
setIsLoading(true)
|
||||
try {
|
||||
await onClick?.()
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
// CSS class variations
|
||||
const variants = {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
||||
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
||||
}
|
||||
|
||||
const sizes = {
|
||||
sm: 'h-8 px-3 text-sm',
|
||||
md: 'h-10 px-4 py-2',
|
||||
lg: 'h-12 px-8 text-lg',
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
// Base styles
|
||||
'inline-flex items-center justify-center rounded-md font-medium transition-colors',
|
||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
||||
'disabled:pointer-events-none disabled:opacity-50',
|
||||
// Variants
|
||||
variants[variant],
|
||||
sizes[size],
|
||||
// Loading state
|
||||
isLoading && 'cursor-not-allowed opacity-70',
|
||||
className
|
||||
)}
|
||||
onClick={handleClick}
|
||||
{...props}
|
||||
>
|
||||
{/* Loading spinner */}
|
||||
{isLoading && (
|
||||
<svg
|
||||
className="mr-2 h-4 w-4 animate-spin"
|
||||
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"
|
||||
/>
|
||||
<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"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex flex-col items-center">
|
||||
{title && <h3 className="font-semibold">{title}</h3>}
|
||||
{description && <p className="text-sm text-muted-foreground">{description}</p>}
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative component patterns:
|
||||
*
|
||||
* 1. Server Component (remove 'use client' and useState)
|
||||
* 2. Compound Components:
|
||||
*
|
||||
* export function TemplateComponent({ children }: { children: React.ReactNode }) {
|
||||
* return <div className="template-wrapper">{children}</div>;
|
||||
* }
|
||||
*
|
||||
* TemplateComponent.Header = function Header({ children }: { children: React.ReactNode }) {
|
||||
* return <header className="template-header">{children}</header>;
|
||||
* };
|
||||
*
|
||||
* TemplateComponent.Body = function Body({ children }: { children: React.ReactNode }) {
|
||||
* return <main className="template-body">{children}</main>;
|
||||
* };
|
||||
*
|
||||
* 3. Forward Ref:
|
||||
*
|
||||
* export const TemplateComponent = forwardRef<HTMLDivElement, TemplateComponentProps>(
|
||||
* ({ className, ...props }, ref) => {
|
||||
* return <div ref={ref} className={cn('template-base', className)} {...props} />;
|
||||
* }
|
||||
* );
|
||||
* TemplateComponent.displayName = "TemplateComponent";
|
||||
*/
|
||||
Reference in New Issue
Block a user