diff options
Diffstat (limited to 'ui/shadcn/.claude/commands')
| -rw-r--r-- | ui/shadcn/.claude/commands/add-component.md | 53 | ||||
| -rw-r--r-- | ui/shadcn/.claude/commands/add.md | 17 | ||||
| -rw-r--r-- | ui/shadcn/.claude/commands/analyze-accessibility.md | 172 | ||||
| -rw-r--r-- | ui/shadcn/.claude/commands/create-data-table.md | 231 | ||||
| -rw-r--r-- | ui/shadcn/.claude/commands/create-variant.md | 68 | ||||
| -rw-r--r-- | ui/shadcn/.claude/commands/migrate-component.md | 239 | ||||
| -rw-r--r-- | ui/shadcn/.claude/commands/optimize-bundle.md | 220 | ||||
| -rw-r--r-- | ui/shadcn/.claude/commands/setup-dark-mode.md | 243 | ||||
| -rw-r--r-- | ui/shadcn/.claude/commands/setup-form.md | 126 |
9 files changed, 1369 insertions, 0 deletions
diff --git a/ui/shadcn/.claude/commands/add-component.md b/ui/shadcn/.claude/commands/add-component.md new file mode 100644 index 0000000..64652fd --- /dev/null +++ b/ui/shadcn/.claude/commands/add-component.md @@ -0,0 +1,53 @@ +--- +description: Add shadcn/ui components to your project +argument-hint: "[component-names...]" +allowed-tools: Bash, Read, Write +--- + +Add one or more shadcn/ui components to your project. + +## Instructions + +1. Check if shadcn/ui is initialized in the project +2. If not initialized, suggest running `npx shadcn@latest init` first +3. For each component requested: + - Run `npx shadcn@latest add [component]` + - Verify component was added successfully + - Check for any peer dependencies +4. If components have dependencies on each other, install in correct order +5. Provide usage examples for the installed components + +## Component Dependencies + +Some components depend on others: +- `form` requires `button`, `label`, `input` +- `data-table` requires `table`, `button`, `dropdown-menu`, `input` +- `date-picker` requires `button`, `calendar`, `popover` +- `combobox` requires `command`, `popover`, `button` + +## Common Components + +**Layout**: card, separator, aspect-ratio, scroll-area +**Forms**: input, label, button, select, checkbox, radio-group, switch, textarea, form +**Overlays**: dialog, alert-dialog, sheet, popover, tooltip, hover-card +**Navigation**: navigation-menu, tabs, breadcrumb, pagination +**Data**: table, data-table, badge, avatar, progress +**Feedback**: alert, toast, skeleton, sonner + +## Arguments + +- Component names separated by spaces: `button card dialog` +- Or use `--all` to add all available components + +## Example + +If the user says: `/add-component form select date-picker` + +Execute: +```bash +npx shadcn@latest add form +npx shadcn@latest add select +npx shadcn@latest add date-picker +``` + +Then provide usage examples for each component added.
\ No newline at end of file diff --git a/ui/shadcn/.claude/commands/add.md b/ui/shadcn/.claude/commands/add.md new file mode 100644 index 0000000..353b229 --- /dev/null +++ b/ui/shadcn/.claude/commands/add.md @@ -0,0 +1,17 @@ +--- +description: Add shadcn/ui component to project +argument-hint: "[component-name] [variant]" +allowed-tools: Bash, Read, Write, Edit +--- + +Add shadcn/ui component: $ARGUMENTS + +Steps: +1. Check if components.json exists +2. Install the specified component using shadcn CLI +3. Update imports and dependencies if needed +4. Show component usage examples + +Available components: button, card, dialog, form, input, label, select, table, toast, etc. + +Example: `/add button` or `/add dialog form` diff --git a/ui/shadcn/.claude/commands/analyze-accessibility.md b/ui/shadcn/.claude/commands/analyze-accessibility.md new file mode 100644 index 0000000..1faadf9 --- /dev/null +++ b/ui/shadcn/.claude/commands/analyze-accessibility.md @@ -0,0 +1,172 @@ +--- +description: Run accessibility audit on components +argument-hint: "[component-path]" +allowed-tools: Read, Bash, WebFetch +--- + +Analyze components for accessibility issues and provide recommendations. + +## Instructions + +1. If no path specified, analyze all components in `components/ui/` +2. Check for common accessibility issues +3. Verify WCAG 2.1 AA compliance +4. Provide specific recommendations for fixes +5. Generate accessibility report + +## Checks to Perform + +### HTML Semantics +- [ ] Proper heading hierarchy (h1 → h2 → h3) +- [ ] Semantic HTML elements used appropriately +- [ ] Lists use ul/ol with li elements +- [ ] Buttons vs links used correctly + +### ARIA Implementation +- [ ] Required ARIA attributes present +- [ ] ARIA roles used appropriately +- [ ] aria-label or aria-labelledby for interactive elements +- [ ] aria-describedby for additional context +- [ ] Live regions for dynamic content + +### Keyboard Navigation +- [ ] All interactive elements keyboard accessible +- [ ] Tab order is logical +- [ ] Focus indicators visible +- [ ] Escape key closes modals/popups +- [ ] Arrow keys work in menus/lists + +### Forms +- [ ] All inputs have associated labels +- [ ] Required fields marked with aria-required +- [ ] Error messages associated with inputs +- [ ] Form validation accessible + +### Images & Media +- [ ] Images have alt text +- [ ] Decorative images have empty alt="" +- [ ] Videos have captions/transcripts +- [ ] Audio has transcripts + +### Color & Contrast +- [ ] Text contrast ratio ≥ 4.5:1 (normal text) +- [ ] Text contrast ratio ≥ 3:1 (large text) +- [ ] Focus indicators have sufficient contrast +- [ ] Information not conveyed by color alone + +### Motion & Animation +- [ ] Respects prefers-reduced-motion +- [ ] Animations can be paused/stopped +- [ ] No flashing content (seizure risk) + +## Automated Testing + +Install and run automated tools: +```bash +# Install testing dependencies +npm install -D @axe-core/react jest-axe + +# Run axe-core tests +npx axe <url> + +# Use React Testing Library +npm test -- --coverage +``` + +## Manual Testing Checklist + +1. **Keyboard Only Navigation** + - Disconnect mouse + - Navigate using Tab, Shift+Tab, Enter, Space, Arrows, Escape + - Verify all features accessible + +2. **Screen Reader Testing** + - NVDA (Windows) + - JAWS (Windows) + - VoiceOver (macOS: Cmd+F5) + - Verify content makes sense when read aloud + +3. **Browser Extensions** + - axe DevTools + - WAVE (WebAIM) + - Lighthouse (Chrome DevTools) + +4. **Visual Testing** + - 200% zoom level + - High contrast mode + - Grayscale mode + - Disable CSS + +## Report Format + +```markdown +# Accessibility Audit Report + +## Summary +- Components analyzed: X +- Critical issues: X +- Warnings: X +- Passed checks: X + +## Critical Issues +1. **[Component]**: [Issue description] + - Impact: [High/Medium/Low] + - Fix: [Specific recommendation] + +## Warnings +1. **[Component]**: [Warning description] + - Recommendation: [Improvement suggestion] + +## Passed Checks +- ✓ Keyboard navigation working +- ✓ ARIA attributes present +- ✓ Color contrast sufficient + +## Recommendations +1. Immediate fixes needed for... +2. Consider improving... +3. Best practices to adopt... +``` + +## Common Fixes + +### Missing Labels +```tsx +// ❌ Bad +<input type="text" /> + +// ✅ Good +<label htmlFor="email">Email</label> +<input id="email" type="text" /> +``` + +### Focus Management +```tsx +// Add focus trap for modals +import { FocusTrap } from '@radix-ui/react-focus-trap' + +<FocusTrap> + <DialogContent>...</DialogContent> +</FocusTrap> +``` + +### Screen Reader Announcements +```tsx +// Live region for dynamic content +<div role="status" aria-live="polite" aria-atomic="true"> + {message} +</div> +``` + +## Example + +If the user says: `/analyze-accessibility` + +1. Scan all components in components/ui/ +2. Check each component against accessibility checklist +3. Run automated tests if available +4. Generate detailed report with: + - Issues found + - Specific fixes needed + - Code examples + - Priority levels
\ No newline at end of file diff --git a/ui/shadcn/.claude/commands/create-data-table.md b/ui/shadcn/.claude/commands/create-data-table.md new file mode 100644 index 0000000..cd1273b --- /dev/null +++ b/ui/shadcn/.claude/commands/create-data-table.md @@ -0,0 +1,231 @@ +--- +description: Create an advanced data table with sorting, filtering, and pagination +argument-hint: <table-name> +allowed-tools: Read, Write, Bash +--- + +Create a fully-featured data table using TanStack Table and shadcn/ui components. + +## Instructions + +1. Install required dependencies: + - `@tanstack/react-table` + - Required shadcn components: `table`, `button`, `input`, `dropdown-menu` + +2. Create data table with features: + - Column definitions with proper types + - Sorting functionality + - Filtering (global and column) + - Pagination + - Row selection + - Column visibility toggle + - Export functionality (optional) + +## Template Structure + +```tsx +// components/[table-name]/columns.tsx +import { ColumnDef } from "@tanstack/react-table" +import { Button } from "@/components/ui/button" +import { ArrowUpDown, MoreHorizontal } from "lucide-react" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { Checkbox } from "@/components/ui/checkbox" + +export type [DataType] = { + id: string + // Define data structure +} + +export const columns: ColumnDef<[DataType]>[] = [ + { + id: "select", + header: ({ table }) => ( + <Checkbox + checked={table.getIsAllPageRowsSelected()} + onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)} + aria-label="Select all" + /> + ), + cell: ({ row }) => ( + <Checkbox + checked={row.getIsSelected()} + onCheckedChange={(value) => row.toggleSelected(!!value)} + aria-label="Select row" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: "field", + header: ({ column }) => ( + <Button + variant="ghost" + onClick={() => column.toggleSorting(column.getIsSorted() === "asc")} + > + Field Name + <ArrowUpDown className="ml-2 h-4 w-4" /> + </Button> + ), + cell: ({ row }) => <div>{row.getValue("field")}</div>, + }, + { + id: "actions", + cell: ({ row }) => { + const item = row.original + return ( + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant="ghost" className="h-8 w-8 p-0"> + <MoreHorizontal className="h-4 w-4" /> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end"> + <DropdownMenuLabel>Actions</DropdownMenuLabel> + <DropdownMenuItem>Edit</DropdownMenuItem> + <DropdownMenuItem>Delete</DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + ) + }, + }, +] + +// components/[table-name]/data-table.tsx +import { + ColumnDef, + flexRender, + getCoreRowModel, + getFilteredRowModel, + getPaginationRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" +import { Input } from "@/components/ui/input" +import { Button } from "@/components/ui/button" +import { DataTableViewOptions } from "./data-table-view-options" +import { DataTablePagination } from "./data-table-pagination" + +interface DataTableProps<TData, TValue> { + columns: ColumnDef<TData, TValue>[] + data: TData[] + searchKey?: string +} + +export function DataTable<TData, TValue>({ + columns, + data, + searchKey, +}: DataTableProps<TData, TValue>) { + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + }) + + return ( + <div className="space-y-4"> + <div className="flex items-center justify-between"> + {searchKey && ( + <Input + placeholder={`Filter by ${searchKey}...`} + value={(table.getColumn(searchKey)?.getFilterValue() as string) ?? ""} + onChange={(event) => + table.getColumn(searchKey)?.setFilterValue(event.target.value) + } + className="max-w-sm" + /> + )} + <DataTableViewOptions table={table} /> + </div> + <div className="rounded-md border"> + <Table> + <TableHeader> + {table.getHeaderGroups().map((headerGroup) => ( + <TableRow key={headerGroup.id}> + {headerGroup.headers.map((header) => ( + <TableHead key={header.id}> + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + </TableHead> + ))} + </TableRow> + ))} + </TableHeader> + <TableBody> + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + <TableRow + key={row.id} + data-state={row.getIsSelected() && "selected"} + > + {row.getVisibleCells().map((cell) => ( + <TableCell key={cell.id}> + {flexRender(cell.column.columnDef.cell, cell.getContext())} + </TableCell> + ))} + </TableRow> + )) + ) : ( + <TableRow> + <TableCell colSpan={columns.length} className="h-24 text-center"> + No results. + </TableCell> + </TableRow> + )} + </TableBody> + </Table> + </div> + <DataTablePagination table={table} /> + </div> + ) +} +``` + +## Features to Include + +- **Sorting**: Click column headers to sort +- **Filtering**: Global search and column filters +- **Pagination**: Navigate through pages +- **Selection**: Select individual or all rows +- **Column Visibility**: Show/hide columns +- **Row Actions**: Edit, delete, view details +- **Export**: CSV/Excel export +- **Responsive**: Mobile-friendly view + +## Example + +If the user says: `/create-data-table users` + +1. Install dependencies: +```bash +npm install @tanstack/react-table +npx shadcn@latest add table button input dropdown-menu checkbox +``` + +2. Create column definitions for users table +3. Create data table component +4. Add pagination component +5. Add column visibility toggle +6. Provide usage example
\ No newline at end of file diff --git a/ui/shadcn/.claude/commands/create-variant.md b/ui/shadcn/.claude/commands/create-variant.md new file mode 100644 index 0000000..03279b7 --- /dev/null +++ b/ui/shadcn/.claude/commands/create-variant.md @@ -0,0 +1,68 @@ +--- +description: Add a new variant to an existing shadcn/ui component +argument-hint: <component-name> <variant-type>=<variant-name> +allowed-tools: Read, Edit, MultiEdit +--- + +Add a new variant to an existing shadcn/ui component using CVA (class-variance-authority). + +## Instructions + +1. Locate the component file in `components/ui/[component].tsx` +2. Find the existing CVA variants configuration +3. Add the new variant to the appropriate variant type +4. Update TypeScript types if needed +5. Provide usage example of the new variant + +## Arguments + +- `component-name`: The component to modify (e.g., `button`, `card`) +- `variant-type`: The type of variant (`variant`, `size`, or custom) +- `variant-name`: The name of the new variant + +## Example + +If the user says: `/create-variant button size=xl` + +1. Open `components/ui/button.tsx` +2. Find the `buttonVariants` CVA configuration +3. Add to the `size` variants: + +```tsx +const buttonVariants = cva( + "...", + { + variants: { + variant: { ... }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + // NEW VARIANT + xl: "h-12 rounded-md px-10 text-lg", + }, + }, + } +) +``` + +4. Show usage: +```tsx +<Button size="xl">Extra Large Button</Button> +``` + +## Common Variant Types + +- **variant**: Visual style (default, destructive, outline, secondary, ghost, link) +- **size**: Component size (sm, default, lg, xl) +- **state**: Interactive state (active, disabled, loading) +- **theme**: Theme-specific (brand, success, warning, info) + +## Best Practices + +1. Keep variant names consistent across components +2. Update TypeScript types when adding variants +3. Test the variant with all other variant combinations +4. Ensure accessibility is maintained +5. Document the new variant in comments
\ No newline at end of file diff --git a/ui/shadcn/.claude/commands/migrate-component.md b/ui/shadcn/.claude/commands/migrate-component.md new file mode 100644 index 0000000..30f763f --- /dev/null +++ b/ui/shadcn/.claude/commands/migrate-component.md @@ -0,0 +1,239 @@ +--- +description: Migrate existing component to shadcn/ui patterns +argument-hint: <component-file> +allowed-tools: Read, Write, Edit, MultiEdit, Bash +--- + +Convert an existing component to follow shadcn/ui patterns and best practices. + +## Instructions + +1. Analyze the existing component +2. Identify required shadcn/ui dependencies +3. Refactor to use: + - CVA for variants + - cn() for class merging + - Radix UI primitives (if applicable) + - Proper TypeScript types + - forwardRef pattern + - Accessibility attributes +4. Maintain backward compatibility where possible +5. Create migration guide + +## Migration Patterns + +### From Styled Components/Emotion +```tsx +// ❌ Before - Styled Components +const StyledButton = styled.button` + background: ${props => props.primary ? 'blue' : 'gray'}; + color: white; + padding: 10px 20px; + &:hover { + opacity: 0.8; + } +` + +// ✅ After - shadcn/ui pattern +import { cva, type VariantProps } from "class-variance-authority" +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2", + { + variants: { + variant: { + primary: "bg-blue-600 text-white hover:bg-blue-700", + secondary: "bg-gray-600 text-white hover:bg-gray-700", + }, + }, + defaultVariants: { + variant: "primary", + }, + } +) + +const Button = React.forwardRef< + HTMLButtonElement, + React.ButtonHTMLAttributes<HTMLButtonElement> & + VariantProps<typeof buttonVariants> +>(({ className, variant, ...props }, ref) => { + return ( + <button + ref={ref} + className={cn(buttonVariants({ variant, className }))} + {...props} + /> + ) +}) +Button.displayName = "Button" +``` + +### From Material-UI/Ant Design +```tsx +// ❌ Before - MUI +import { Button, TextField, Dialog } from '@mui/material' + +<Dialog open={open} onClose={handleClose}> + <DialogTitle>Title</DialogTitle> + <DialogContent> + <TextField label="Name" /> + </DialogContent> + <DialogActions> + <Button onClick={handleClose}>Cancel</Button> + </DialogActions> +</Dialog> + +// ✅ After - shadcn/ui +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Button } from "@/components/ui/button" + +<Dialog open={open} onOpenChange={setOpen}> + <DialogContent> + <DialogHeader> + <DialogTitle>Title</DialogTitle> + </DialogHeader> + <div className="grid gap-4 py-4"> + <div className="grid gap-2"> + <Label htmlFor="name">Name</Label> + <Input id="name" /> + </div> + </div> + <DialogFooter> + <Button variant="outline" onClick={() => setOpen(false)}> + Cancel + </Button> + </DialogFooter> + </DialogContent> +</Dialog> +``` + +### From Bootstrap/Traditional CSS +```tsx +// ❌ Before - Bootstrap classes +<div className="card"> + <div className="card-header"> + <h5 className="card-title">Title</h5> + </div> + <div className="card-body"> + <p className="card-text">Content</p> + <button className="btn btn-primary">Action</button> + </div> +</div> + +// ✅ After - shadcn/ui +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card" +import { Button } from "@/components/ui/button" + +<Card> + <CardHeader> + <CardTitle>Title</CardTitle> + </CardHeader> + <CardContent> + <p>Content</p> + </CardContent> + <CardFooter> + <Button>Action</Button> + </CardFooter> +</Card> +``` + +## Migration Checklist + +### Structure +- [ ] Convert to functional component +- [ ] Add forwardRef if needed +- [ ] Add displayName +- [ ] Export component and variants + +### Styling +- [ ] Replace CSS-in-JS with Tailwind classes +- [ ] Implement CVA for variants +- [ ] Use cn() for class merging +- [ ] Convert theme tokens to CSS variables + +### Types +- [ ] Add proper TypeScript interfaces +- [ ] Extend HTML element props +- [ ] Add VariantProps type +- [ ] Export types separately + +### Behavior +- [ ] Replace UI library with Radix primitives +- [ ] Add asChild support if applicable +- [ ] Implement controlled/uncontrolled patterns +- [ ] Add proper event handlers + +### Accessibility +- [ ] Add ARIA attributes +- [ ] Ensure keyboard navigation +- [ ] Add focus management +- [ ] Include screen reader support + +## Common Replacements + +| Old Library | shadcn/ui Replacement | +|------------|----------------------| +| MUI Button | Button with variants | +| Ant Select | Select with Radix | +| Bootstrap Modal | Dialog component | +| Chakra Menu | DropdownMenu | +| Semantic UI Form | Form with React Hook Form | + +## Migration Guide Template + +```markdown +# Migration Guide: [ComponentName] + +## Breaking Changes +- Changed prop: `color` → `variant` +- Removed prop: `size="medium"` (now default) +- New required prop: `asChild` for composition + +## API Changes +```tsx +// Before +<OldComponent color="primary" size="large" /> + +// After +<NewComponent variant="default" size="lg" /> +``` + +## Styling Changes +- Uses Tailwind classes instead of CSS modules +- Theme variables now use CSS custom properties +- Dark mode handled automatically + +## Usage Examples +[Provide before/after examples] +``` + +## Example + +If the user says: `/migrate-component components/CustomButton.jsx` + +1. Read and analyze CustomButton.jsx +2. Identify styling system used +3. Create new button following shadcn patterns: + - Add CVA variants + - Convert styles to Tailwind + - Add proper TypeScript types + - Include forwardRef +4. Test compatibility +5. Provide migration guide
\ No newline at end of file diff --git a/ui/shadcn/.claude/commands/optimize-bundle.md b/ui/shadcn/.claude/commands/optimize-bundle.md new file mode 100644 index 0000000..3a820f3 --- /dev/null +++ b/ui/shadcn/.claude/commands/optimize-bundle.md @@ -0,0 +1,220 @@ +--- +description: Analyze and optimize bundle size +argument-hint: +allowed-tools: Bash, Read, Edit, MultiEdit +--- + +Analyze bundle size and optimize for production. + +## Instructions + +1. Run bundle analysis +2. Identify large dependencies +3. Find unused code +4. Implement optimization strategies +5. Generate optimization report + +## Analysis Tools + +### Next.js +```bash +# Install bundle analyzer +npm install -D @next/bundle-analyzer + +# Configure next.config.js +const withBundleAnalyzer = require('@next/bundle-analyzer')({ + enabled: process.env.ANALYZE === 'true', +}) + +module.exports = withBundleAnalyzer({ + // your config +}) + +# Run analysis +ANALYZE=true npm run build +``` + +### Vite +```bash +# Install rollup plugin +npm install -D rollup-plugin-visualizer + +# Add to vite.config.ts +import { visualizer } from 'rollup-plugin-visualizer' + +plugins: [ + visualizer({ + open: true, + gzipSize: true, + brotliSize: true, + }) +] + +# Run build +npm run build +``` + +### General +```bash +# webpack-bundle-analyzer +npm install -D webpack-bundle-analyzer + +# source-map-explorer +npm install -D source-map-explorer +npm run build +npx source-map-explorer 'build/static/js/*.js' +``` + +## Optimization Strategies + +### 1. Code Splitting +```tsx +// Dynamic imports +const HeavyComponent = lazy(() => import('./HeavyComponent')) + +// Route-based splitting (Next.js) +export default function Page() { + return <div>Auto code-split by route</div> +} + +// Conditional loading +if (userNeedsFeature) { + const module = await import('./feature') + module.initialize() +} +``` + +### 2. Tree Shaking +```tsx +// ❌ Bad - imports entire library +import _ from 'lodash' + +// ✅ Good - imports only what's needed +import debounce from 'lodash/debounce' + +// For shadcn/ui - already optimized! +// Components are copied, not imported from package +``` + +### 3. Component Optimization +```tsx +// Memoize expensive components +const MemoizedComponent = memo(ExpensiveComponent) + +// Lazy load heavy components +const Chart = lazy(() => import('./Chart')) + +<Suspense fallback={<Skeleton />}> + <Chart /> +</Suspense> +``` + +### 4. Asset Optimization +```tsx +// Next.js Image optimization +import Image from 'next/image' + +<Image + src="/hero.jpg" + width={1200} + height={600} + priority + alt="Hero" +/> + +// Font optimization +import { Inter } from 'next/font/google' + +const inter = Inter({ + subsets: ['latin'], + display: 'swap', +}) +``` + +### 5. Dependency Optimization +```json +// Use lighter alternatives +{ + "dependencies": { + // "moment": "^2.29.0", // 67kb + "date-fns": "^2.29.0", // 13kb (tree-shakeable) + + // "lodash": "^4.17.0", // 71kb + "lodash-es": "^4.17.0", // Tree-shakeable + } +} +``` + +### 6. Tailwind CSS Optimization +```js +// tailwind.config.js +module.exports = { + content: [ + // Be specific to avoid scanning unnecessary files + './app/**/*.{js,ts,jsx,tsx}', + './components/**/*.{js,ts,jsx,tsx}', + ], + // Remove unused styles in production + purge: process.env.NODE_ENV === 'production' ? [ + './app/**/*.{js,ts,jsx,tsx}', + './components/**/*.{js,ts,jsx,tsx}', + ] : [], +} +``` + +## Optimization Checklist + +- [ ] Enable production mode +- [ ] Remove console.logs and debug code +- [ ] Minify JavaScript and CSS +- [ ] Enable gzip/brotli compression +- [ ] Optimize images (WebP, AVIF) +- [ ] Lazy load non-critical resources +- [ ] Use CDN for static assets +- [ ] Implement caching strategies +- [ ] Remove unused dependencies +- [ ] Tree shake imports + +## Report Format + +```markdown +# Bundle Optimization Report + +## Current Stats +- Total bundle size: XXXkb +- Gzipped size: XXXkb +- Largest chunks: [...] + +## Issues Found +1. Large dependency: [package] (XXXkb) +2. Duplicate code in: [files] +3. Unused exports in: [modules] + +## Optimizations Applied +1. ✅ Code split [component] +2. ✅ Lazy loaded [routes] +3. ✅ Replaced [heavy-lib] with [light-lib] + +## Results +- Bundle size reduced by: XX% +- Initial load improved by: XXms +- Lighthouse score: XX → XX + +## Recommendations +1. Consider replacing... +2. Lazy load... +3. Split chunk for... +``` + +## Example + +If the user says: `/optimize-bundle` + +1. Analyze current bundle size +2. Identify optimization opportunities: + - Large dependencies to replace + - Components to lazy load + - Unused code to remove +3. Implement optimizations +4. Re-analyze and compare results +5. Generate detailed report
\ No newline at end of file diff --git a/ui/shadcn/.claude/commands/setup-dark-mode.md b/ui/shadcn/.claude/commands/setup-dark-mode.md new file mode 100644 index 0000000..c9867b6 --- /dev/null +++ b/ui/shadcn/.claude/commands/setup-dark-mode.md @@ -0,0 +1,243 @@ +--- +description: Configure dark mode for your framework +argument-hint: "[framework]" +allowed-tools: Read, Write, Edit, Bash +--- + +Set up dark mode with theme switching for your specific framework. + +## Instructions + +Based on the framework detected or specified: +1. Install required dependencies +2. Set up theme provider +3. Configure CSS variables +4. Create theme toggle component +5. Set up persistence (cookies/localStorage) + +## Framework Configurations + +### Next.js (App Router) +```bash +npm install next-themes +``` + +Create `components/theme-provider.tsx`: +```tsx +"use client" + +import * as React from "react" +import { ThemeProvider as NextThemesProvider } from "next-themes" +import { type ThemeProviderProps } from "next-themes/dist/types" + +export function ThemeProvider({ children, ...props }: ThemeProviderProps) { + return <NextThemesProvider {...props}>{children}</NextThemesProvider> +} +``` + +Wrap in `app/layout.tsx`: +```tsx +<ThemeProvider + attribute="class" + defaultTheme="system" + enableSystem + disableTransitionOnChange +> + {children} +</ThemeProvider> +``` + +### Vite +Create `components/theme-provider.tsx`: +```tsx +import { createContext, useContext, useEffect, useState } from "react" + +type Theme = "dark" | "light" | "system" + +const ThemeProviderContext = createContext<{ + theme: Theme + setTheme: (theme: Theme) => void +}>({ + theme: "system", + setTheme: () => null, +}) + +export function ThemeProvider({ children }: { children: React.ReactNode }) { + const [theme, setTheme] = useState<Theme>( + () => (localStorage.getItem("theme") as Theme) || "system" + ) + + useEffect(() => { + const root = window.document.documentElement + root.classList.remove("light", "dark") + + if (theme === "system") { + const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") + .matches + ? "dark" + : "light" + root.classList.add(systemTheme) + return + } + + root.classList.add(theme) + }, [theme]) + + const value = { + theme, + setTheme: (theme: Theme) => { + localStorage.setItem("theme", theme) + setTheme(theme) + }, + } + + return ( + <ThemeProviderContext.Provider value={value}> + {children} + </ThemeProviderContext.Provider> + ) +} + +export const useTheme = () => { + const context = useContext(ThemeProviderContext) + if (context === undefined) + throw new Error("useTheme must be used within a ThemeProvider") + return context +} +``` + +### Remix +```bash +npm install remix-themes +``` + +In `app/root.tsx`: +```tsx +import { themeSessionResolver } from "remix-themes" +import { + PreventFlashOnWrongTheme, + ThemeProvider, + useTheme, +} from "remix-themes" + +export async function loader({ request }: LoaderFunctionArgs) { + const { getTheme } = await themeSessionResolver(request) + return { theme: getTheme() } +} + +export default function App() { + const data = useLoaderData<typeof loader>() + const [theme] = useTheme() + + return ( + <html lang="en" className={theme ?? ""}> + <head> + <PreventFlashOnWrongTheme ssrTheme={Boolean(data.theme)} /> + </head> + <body> + <ThemeProvider + specifiedTheme={data.theme} + themeAction="/action/set-theme" + > + <Outlet /> + </ThemeProvider> + </body> + </html> + ) +} +``` + +### Astro +In layout file: +```astro +<script is:inline> + const theme = (() => { + if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) { + return localStorage.getItem('theme') + } + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + return 'dark' + } + return 'light' + })() + + if (theme === 'light') { + document.documentElement.classList.remove('dark') + } else { + document.documentElement.classList.add('dark') + } + window.localStorage.setItem('theme', theme) +</script> +``` + +## Theme Toggle Component + +Create `components/theme-toggle.tsx`: +```tsx +import { Moon, Sun } from "lucide-react" +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { useTheme } from "@/components/theme-provider" // or "next-themes" + +export function ThemeToggle() { + const { setTheme } = useTheme() + + return ( + <DropdownMenu> + <DropdownMenuTrigger asChild> + <Button variant="outline" size="icon"> + <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" /> + <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /> + <span className="sr-only">Toggle theme</span> + </Button> + </DropdownMenuTrigger> + <DropdownMenuContent align="end"> + <DropdownMenuItem onClick={() => setTheme("light")}> + Light + </DropdownMenuItem> + <DropdownMenuItem onClick={() => setTheme("dark")}> + Dark + </DropdownMenuItem> + <DropdownMenuItem onClick={() => setTheme("system")}> + System + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + ) +} +``` + +## CSS Configuration + +Ensure `globals.css` has: +```css +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + /* ... other variables ... */ + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + /* ... other variables ... */ + } +} +``` + +## Example + +If the user says: `/setup-dark-mode next` + +1. Install next-themes +2. Create ThemeProvider component +3. Wrap app in ThemeProvider +4. Create ThemeToggle component +5. Add to navigation/header +6. Test theme switching
\ No newline at end of file diff --git a/ui/shadcn/.claude/commands/setup-form.md b/ui/shadcn/.claude/commands/setup-form.md new file mode 100644 index 0000000..068a80f --- /dev/null +++ b/ui/shadcn/.claude/commands/setup-form.md @@ -0,0 +1,126 @@ +--- +description: Set up a form with React Hook Form and Zod validation +argument-hint: <form-name> +allowed-tools: Read, Write, Edit, Bash +--- + +Create a complete form setup with React Hook Form, Zod validation, and shadcn/ui form components. + +## Instructions + +1. Install required dependencies if not present: + - `react-hook-form` + - `@hookform/resolvers` + - `zod` + - Required shadcn components: `form`, `input`, `button`, etc. + +2. Create the form with: + - Zod schema for validation + - Form component with React Hook Form + - Proper error handling + - Loading states + - Success feedback + +## Template Structure + +```tsx +// lib/validations/[form-name].ts +import * as z from "zod" + +export const [formName]Schema = z.object({ + // Define fields +}) + +export type [FormName]Values = z.infer<typeof [formName]Schema> + +// components/forms/[form-name]-form.tsx +import { useForm } from "react-hook-form" +import { zodResolver } from "@hookform/resolvers/zod" +import { [formName]Schema, type [FormName]Values } from "@/lib/validations/[form-name]" +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { Input } from "@/components/ui/input" +import { Button } from "@/components/ui/button" +import { toast } from "@/components/ui/use-toast" + +export function [FormName]Form() { + const form = useForm<[FormName]Values>({ + resolver: zodResolver([formName]Schema), + defaultValues: { + // Set defaults + }, + }) + + async function onSubmit(data: [FormName]Values) { + try { + // Handle submission + toast({ + title: "Success", + description: "Form submitted successfully", + }) + } catch (error) { + toast({ + title: "Error", + description: "Something went wrong", + variant: "destructive", + }) + } + } + + return ( + <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6"> + {/* Form fields */} + <Button + type="submit" + disabled={form.formState.isSubmitting} + > + {form.formState.isSubmitting ? "Submitting..." : "Submit"} + </Button> + </form> + </Form> + ) +} +``` + +## Common Form Types + +- **contact-form**: Name, email, message +- **login-form**: Email/username, password +- **register-form**: Name, email, password, confirm password +- **profile-form**: Avatar, bio, social links +- **settings-form**: Preferences, notifications +- **checkout-form**: Billing, shipping, payment + +## Field Types to Consider + +- Text inputs (email, url, tel, password) +- Textareas for long text +- Select dropdowns +- Radio groups +- Checkboxes +- Date pickers +- File uploads +- Number inputs with validation + +## Example + +If the user says: `/setup-form contact` + +1. Install dependencies: +```bash +npm install react-hook-form @hookform/resolvers zod +npx shadcn@latest add form input textarea button +``` + +2. Create validation schema +3. Create form component with name, email, message fields +4. Add proper validation rules +5. Include submit handler with loading state
\ No newline at end of file |
