From 3fbb9a18372f2b6a675dd6c039ba52be76f3eeb4 Mon Sep 17 00:00:00 2001
From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>
Date: Fri, 16 Jan 2026 08:30:14 +0900
Subject: updates
---
ui/tailwindcss/.claude/commands/add-plugin.md | 721 +++++++++++++++++++++
ui/tailwindcss/.claude/commands/analyze-usage.md | 545 ++++++++++++++++
ui/tailwindcss/.claude/commands/component.md | 18 +
.../.claude/commands/create-component.md | 716 ++++++++++++++++++++
ui/tailwindcss/.claude/commands/init-tailwind.md | 229 +++++++
ui/tailwindcss/.claude/commands/optimize-config.md | 412 ++++++++++++
ui/tailwindcss/.claude/commands/setup-dark-mode.md | 721 +++++++++++++++++++++
7 files changed, 3362 insertions(+)
create mode 100644 ui/tailwindcss/.claude/commands/add-plugin.md
create mode 100644 ui/tailwindcss/.claude/commands/analyze-usage.md
create mode 100644 ui/tailwindcss/.claude/commands/component.md
create mode 100644 ui/tailwindcss/.claude/commands/create-component.md
create mode 100644 ui/tailwindcss/.claude/commands/init-tailwind.md
create mode 100644 ui/tailwindcss/.claude/commands/optimize-config.md
create mode 100644 ui/tailwindcss/.claude/commands/setup-dark-mode.md
(limited to 'ui/tailwindcss/.claude/commands')
diff --git a/ui/tailwindcss/.claude/commands/add-plugin.md b/ui/tailwindcss/.claude/commands/add-plugin.md
new file mode 100644
index 0000000..36f16ed
--- /dev/null
+++ b/ui/tailwindcss/.claude/commands/add-plugin.md
@@ -0,0 +1,721 @@
+---
+name: add-plugin
+description: Add and configure TailwindCSS plugins for extended functionality, forms, typography, animations, and custom utilities
+tools: Bash, Edit, Read, Write
+---
+
+# Add TailwindCSS Plugin
+
+This command helps you add, configure, and optimize TailwindCSS plugins to extend functionality and enhance your design system.
+
+## What This Command Does
+
+1. **Plugin Installation**
+ - Installs official and community TailwindCSS plugins
+ - Configures plugin settings for optimal performance
+ - Integrates plugins with existing configuration
+ - Updates content paths for plugin-specific classes
+
+2. **Configuration Setup**
+ - Configures plugin options and customizations
+ - Sets up plugin-specific utility classes
+ - Optimizes for CSS bundle size and purging
+ - Integrates with design system tokens
+
+3. **Usage Examples**
+ - Provides implementation examples for each plugin
+ - Shows best practices and common patterns
+ - Demonstrates responsive and interactive usage
+ - Includes accessibility considerations
+
+4. **Performance Optimization**
+ - Configures plugins for optimal bundle size
+ - Sets up effective purging strategies
+ - Optimizes for build performance
+ - Monitors plugin impact on CSS output
+
+## Official Plugins
+
+### Typography Plugin (@tailwindcss/typography)
+
+#### Installation and Setup
+
+```bash
+# Install typography plugin
+npm install -D @tailwindcss/typography
+
+# Or with yarn
+yarn add -D @tailwindcss/typography
+```
+
+#### Configuration
+
+```javascript
+// tailwind.config.js
+module.exports = {
+ theme: {
+ extend: {
+ typography: ({ theme }) => ({
+ // Default prose styles
+ DEFAULT: {
+ css: {
+ maxWidth: 'none',
+ color: theme('colors.gray.700'),
+ '[class~="lead"]': {
+ color: theme('colors.gray.600'),
+ fontSize: theme('fontSize.xl')[0],
+ lineHeight: theme('fontSize.xl')[1].lineHeight,
+ },
+ a: {
+ color: theme('colors.blue.600'),
+ textDecoration: 'none',
+ fontWeight: theme('fontWeight.medium'),
+ '&:hover': {
+ color: theme('colors.blue.700'),
+ textDecoration: 'underline',
+ },
+ },
+ 'h1, h2, h3, h4, h5, h6': {
+ color: theme('colors.gray.900'),
+ fontWeight: theme('fontWeight.bold'),
+ },
+ h1: {
+ fontSize: theme('fontSize.4xl')[0],
+ lineHeight: theme('fontSize.4xl')[1].lineHeight,
+ },
+ h2: {
+ fontSize: theme('fontSize.3xl')[0],
+ lineHeight: theme('fontSize.3xl')[1].lineHeight,
+ },
+ h3: {
+ fontSize: theme('fontSize.2xl')[0],
+ lineHeight: theme('fontSize.2xl')[1].lineHeight,
+ },
+ code: {
+ color: theme('colors.gray.900'),
+ backgroundColor: theme('colors.gray.100'),
+ padding: theme('spacing.1'),
+ borderRadius: theme('borderRadius.sm'),
+ fontSize: theme('fontSize.sm')[0],
+ },
+ 'pre code': {
+ backgroundColor: 'transparent',
+ padding: 0,
+ },
+ pre: {
+ backgroundColor: theme('colors.gray.900'),
+ color: theme('colors.gray.100'),
+ padding: theme('spacing.4'),
+ borderRadius: theme('borderRadius.lg'),
+ overflow: 'auto',
+ },
+ blockquote: {
+ borderLeftWidth: theme('borderWidth.4'),
+ borderLeftColor: theme('colors.gray.300'),
+ paddingLeft: theme('spacing.4'),
+ fontStyle: 'italic',
+ color: theme('colors.gray.600'),
+ },
+ },
+ },
+
+ // Dark mode typography
+ invert: {
+ css: {
+ '--tw-prose-body': theme('colors.gray.300'),
+ '--tw-prose-headings': theme('colors.gray.100'),
+ '--tw-prose-lead': theme('colors.gray.400'),
+ '--tw-prose-links': theme('colors.blue.400'),
+ '--tw-prose-bold': theme('colors.gray.100'),
+ '--tw-prose-counters': theme('colors.gray.400'),
+ '--tw-prose-bullets': theme('colors.gray.500'),
+ '--tw-prose-hr': theme('colors.gray.700'),
+ '--tw-prose-quotes': theme('colors.gray.200'),
+ '--tw-prose-quote-borders': theme('colors.gray.700'),
+ '--tw-prose-captions': theme('colors.gray.400'),
+ '--tw-prose-code': theme('colors.gray.100'),
+ '--tw-prose-pre-code': theme('colors.gray.100'),
+ '--tw-prose-pre-bg': theme('colors.gray.800'),
+ '--tw-prose-th-borders': theme('colors.gray.600'),
+ '--tw-prose-td-borders': theme('colors.gray.700'),
+ },
+ },
+
+ // Size variants
+ sm: {
+ css: {
+ fontSize: theme('fontSize.sm')[0],
+ lineHeight: theme('fontSize.sm')[1].lineHeight,
+ h1: { fontSize: theme('fontSize.2xl')[0] },
+ h2: { fontSize: theme('fontSize.xl')[0] },
+ h3: { fontSize: theme('fontSize.lg')[0] },
+ },
+ },
+
+ lg: {
+ css: {
+ fontSize: theme('fontSize.lg')[0],
+ lineHeight: theme('fontSize.lg')[1].lineHeight,
+ h1: { fontSize: theme('fontSize.5xl')[0] },
+ h2: { fontSize: theme('fontSize.4xl')[0] },
+ h3: { fontSize: theme('fontSize.3xl')[0] },
+ },
+ },
+
+ xl: {
+ css: {
+ fontSize: theme('fontSize.xl')[0],
+ lineHeight: theme('fontSize.xl')[1].lineHeight,
+ h1: { fontSize: theme('fontSize.6xl')[0] },
+ h2: { fontSize: theme('fontSize.5xl')[0] },
+ h3: { fontSize: theme('fontSize.4xl')[0] },
+ },
+ },
+ }),
+ },
+ },
+ plugins: [
+ require('@tailwindcss/typography'),
+ ],
+}
+```
+
+#### Usage Examples
+
+```html
+
+
+ Article Title
+ This is a lead paragraph with emphasis.
+ Regular paragraph content with links and bold text .
+
+
+ This is a blockquote with proper styling.
+
+
+ console.log('Code blocks are styled too')
+
+
+
+
+ Dark Mode Compatible
+ Content that adapts to dark themes.
+
+
+
+
Small typography
+Large typography
+Extra large typography
+
+
+
+
Full width content without prose max-width constraint.
+
+```
+
+### Forms Plugin (@tailwindcss/forms)
+
+#### Installation and Setup
+
+```bash
+# Install forms plugin
+npm install -D @tailwindcss/forms
+```
+
+#### Configuration
+
+```javascript
+// tailwind.config.js
+module.exports = {
+ plugins: [
+ require('@tailwindcss/forms')({
+ strategy: 'class', // 'base' or 'class'
+ }),
+ ],
+}
+```
+
+#### Usage Examples
+
+```html
+
+
+```
+
+### Aspect Ratio Plugin (@tailwindcss/aspect-ratio)
+
+#### Installation and Setup
+
+```bash
+# Install aspect ratio plugin
+npm install -D @tailwindcss/aspect-ratio
+```
+
+#### Configuration
+
+```javascript
+// tailwind.config.js
+module.exports = {
+ plugins: [
+ require('@tailwindcss/aspect-ratio'),
+ ],
+}
+```
+
+#### Usage Examples
+
+```html
+
+
+ VIDEO
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Card Title 1
+
+
+
+
+
+
+
+
+
Card Title 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Container Queries Plugin (@tailwindcss/container-queries)
+
+#### Installation and Setup
+
+```bash
+# Install container queries plugin
+npm install -D @tailwindcss/container-queries
+```
+
+#### Configuration
+
+```javascript
+// tailwind.config.js
+module.exports = {
+ plugins: [
+ require('@tailwindcss/container-queries'),
+ ],
+}
+```
+
+#### Usage Examples
+
+```html
+
+
+
+
+
+
Product Title
+
Product description
+
+ $99.99
+
+ Add to Cart
+
+
+
+
+
+
+
+
+
+
+
Card Title
+
Card content that adapts to container size.
+
+
+
+
+
+
+
+
+
+
+
Main Content
+
+
+
+```
+
+## Popular Community Plugins
+
+### Line Clamp Plugin (@tailwindcss/line-clamp)
+
+#### Installation and Setup
+
+```bash
+# Install line clamp plugin (now built into Tailwind v3.3+)
+npm install -D @tailwindcss/line-clamp
+```
+
+#### Usage Examples
+
+```html
+
+
+ This is a long paragraph that will be clamped to exactly 3 lines with an ellipsis at the end when it overflows beyond the specified number of lines.
+
+
+
+
+
Single line with ellipsis
+
Two lines maximum with ellipsis
+
Up to four lines with ellipsis
+
No line clamping applied
+
+
+
+
+ Responsive line clamping that shows more lines on larger screens.
+
+```
+
+### Animations Plugin (tailwindcss-animate)
+
+#### Installation and Setup
+
+```bash
+# Install animations plugin
+npm install -D tailwindcss-animate
+```
+
+#### Configuration
+
+```javascript
+// tailwind.config.js
+module.exports = {
+ plugins: [
+ require('tailwindcss-animate'),
+ ],
+}
+```
+
+#### Usage Examples
+
+```html
+
+Fades in smoothly
+Slides up from bottom
+Scales in from center
+Bounces in with spring effect
+
+
+
+
+
+
+
+ Bounce on Hover
+
+
+
+
+ Wiggle on group hover
+
+
+
+
+
+
Item 1
+
Item 2
+
Item 3
+
+```
+
+### Debugging Plugin (tailwindcss-debug-screens)
+
+#### Installation and Setup
+
+```bash
+# Install debug plugin (development only)
+npm install -D tailwindcss-debug-screens
+```
+
+#### Configuration
+
+```javascript
+// tailwind.config.js
+module.exports = {
+ plugins: [
+ process.env.NODE_ENV === 'development' && require('tailwindcss-debug-screens'),
+ ].filter(Boolean),
+}
+```
+
+#### Usage
+
+```html
+
+
+
+
+```
+
+## Custom Plugin Development
+
+### Creating a Custom Plugin
+
+```javascript
+// plugins/custom-utilities.js
+const plugin = require('tailwindcss/plugin')
+
+module.exports = plugin(function({ addUtilities, addComponents, theme }) {
+ // Add custom utilities
+ addUtilities({
+ '.text-shadow': {
+ textShadow: '2px 2px 4px rgba(0, 0, 0, 0.1)',
+ },
+ '.text-shadow-lg': {
+ textShadow: '4px 4px 8px rgba(0, 0, 0, 0.2)',
+ },
+ '.scrollbar-hide': {
+ '-ms-overflow-style': 'none',
+ 'scrollbar-width': 'none',
+ '&::-webkit-scrollbar': {
+ display: 'none',
+ },
+ },
+ '.backdrop-blur-xs': {
+ backdropFilter: 'blur(2px)',
+ },
+ })
+
+ // Add custom components
+ addComponents({
+ '.btn-primary': {
+ backgroundColor: theme('colors.blue.600'),
+ color: theme('colors.white'),
+ padding: `${theme('spacing.2')} ${theme('spacing.4')}`,
+ borderRadius: theme('borderRadius.md'),
+ fontWeight: theme('fontWeight.medium'),
+ '&:hover': {
+ backgroundColor: theme('colors.blue.700'),
+ },
+ '&:focus': {
+ outline: 'none',
+ boxShadow: `0 0 0 3px ${theme('colors.blue.500')}33`,
+ },
+ },
+ '.card': {
+ backgroundColor: theme('colors.white'),
+ borderRadius: theme('borderRadius.lg'),
+ boxShadow: theme('boxShadow.md'),
+ padding: theme('spacing.6'),
+ },
+ })
+})
+```
+
+#### Using Custom Plugin
+
+```javascript
+// tailwind.config.js
+module.exports = {
+ plugins: [
+ require('./plugins/custom-utilities'),
+ ],
+}
+```
+
+### Advanced Custom Plugin with Variants
+
+```javascript
+// plugins/advanced-utilities.js
+const plugin = require('tailwindcss/plugin')
+
+module.exports = plugin(
+ function({ addUtilities, matchUtilities, theme }) {
+ // Static utilities
+ addUtilities({
+ '.writing-vertical': {
+ 'writing-mode': 'vertical-rl',
+ },
+ })
+
+ // Dynamic utilities with arbitrary values
+ matchUtilities(
+ {
+ 'text-shadow': (value) => ({
+ textShadow: value,
+ }),
+ },
+ { values: theme('textShadow') }
+ )
+
+ matchUtilities(
+ {
+ 'animation-delay': (value) => ({
+ animationDelay: value,
+ }),
+ },
+ { values: theme('animationDelay') }
+ )
+ },
+ {
+ // Extend theme
+ theme: {
+ textShadow: {
+ sm: '1px 1px 2px rgba(0, 0, 0, 0.1)',
+ DEFAULT: '2px 2px 4px rgba(0, 0, 0, 0.1)',
+ lg: '4px 4px 8px rgba(0, 0, 0, 0.15)',
+ },
+ animationDelay: {
+ '75': '75ms',
+ '100': '100ms',
+ '150': '150ms',
+ '200': '200ms',
+ '300': '300ms',
+ '500': '500ms',
+ '700': '700ms',
+ '1000': '1000ms',
+ },
+ },
+ }
+)
+```
+
+## Plugin Performance Optimization
+
+### Bundle Size Analysis Script
+
+```javascript
+// scripts/analyze-plugins.js
+const fs = require('fs')
+const postcss = require('postcss')
+const tailwindcss = require('tailwindcss')
+
+async function analyzePluginImpact(configPath) {
+ // Base configuration without plugins
+ const baseConfig = {
+ content: ['./test.html'],
+ plugins: [],
+ }
+
+ // Configuration with plugins
+ const pluginConfig = require(configPath)
+
+ // Generate CSS for both configurations
+ const baseCSS = await generateCSS(baseConfig)
+ const pluginCSS = await generateCSS(pluginConfig)
+
+ console.log('Plugin Impact Analysis:')
+ console.log(`Base CSS size: ${baseCSS.length} bytes`)
+ console.log(`With plugins: ${pluginCSS.length} bytes`)
+ console.log(`Difference: ${pluginCSS.length - baseCSS.length} bytes`)
+ console.log(`Increase: ${(((pluginCSS.length - baseCSS.length) / baseCSS.length) * 100).toFixed(2)}%`)
+}
+
+async function generateCSS(config) {
+ const result = await postcss([tailwindcss(config)])
+ .process('@tailwind base; @tailwind components; @tailwind utilities;', { from: undefined })
+
+ return result.css
+}
+
+analyzePluginImpact('./tailwind.config.js')
+```
+
+Remember: **Choose plugins based on actual needs, configure them properly, and monitor their impact on bundle size and performance!**
diff --git a/ui/tailwindcss/.claude/commands/analyze-usage.md b/ui/tailwindcss/.claude/commands/analyze-usage.md
new file mode 100644
index 0000000..18d5f0f
--- /dev/null
+++ b/ui/tailwindcss/.claude/commands/analyze-usage.md
@@ -0,0 +1,545 @@
+---
+name: analyze-usage
+description: Analyze TailwindCSS utility usage patterns, identify optimization opportunities, and generate usage reports
+tools: Read, Bash, Grep, Glob, Write
+---
+
+# Analyze TailwindCSS Usage
+
+This command analyzes your TailwindCSS usage patterns across your codebase to identify optimization opportunities, unused utilities, and usage statistics.
+
+## What This Command Does
+
+1. **Usage Pattern Analysis**
+ - Scans all template files for TailwindCSS class usage
+ - Identifies most and least used utility patterns
+ - Generates usage frequency reports
+ - Detects potential optimization opportunities
+
+2. **Bundle Size Analysis**
+ - Analyzes generated CSS bundle size
+ - Identifies largest utility categories
+ - Compares before/after optimization results
+ - Tracks bundle size over time
+
+3. **Code Quality Insights**
+ - Identifies overly complex utility combinations
+ - Suggests component extraction opportunities
+ - Detects inconsistent utility usage patterns
+ - Highlights potential refactoring opportunities
+
+4. **Performance Recommendations**
+ - Suggests safelist optimizations
+ - Identifies unused CSS that can be purged
+ - Recommends content path improvements
+ - Provides bundle optimization suggestions
+
+## Usage Examples
+
+### Basic Usage Analysis
+
+```bash
+# Analyze utility usage in all template files
+grep -r "class[Name]*=" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html" | \
+sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | \
+tr ' ' '\n' | \
+sort | uniq -c | sort -nr > tailwind-usage-report.txt
+
+# View top 20 most used utilities
+head -20 tailwind-usage-report.txt
+
+# View least used utilities
+tail -20 tailwind-usage-report.txt
+```
+
+### Advanced Pattern Analysis
+
+```bash
+# Find all TailwindCSS classes in codebase
+find src -name "*.{js,jsx,ts,tsx,vue,html}" -exec grep -l "class" {} \; | \
+xargs grep -o "class[Name]*=['\"][^'\"]*['\"]" | \
+sed -E 's/.*class[Name]*=["'\''`]([^"'\''`]*)["'\''`].*/\1/' | \
+tr ' ' '\n' | \
+grep -E '^[a-zA-Z]' | \
+sort | uniq -c | sort -nr
+```
+
+### Component Complexity Analysis
+
+```bash
+# Find components with many utility classes (potential extraction candidates)
+find src/components -name "*.{jsx,tsx}" -exec sh -c '
+ for file do
+ count=$(grep -o "class[Name]*=['\"][^'\"]*['\"]" "$file" | \
+ sed -E "s/.*class[Name]*=[\"\'\`]([^\"\'\`]*)[\"\'\`].*/\1/" | \
+ tr " " "\n" | wc -l)
+ echo "$count $file"
+ done
+' sh {} + | sort -nr | head -10
+```
+
+## Analysis Scripts
+
+### Comprehensive Usage Analyzer
+
+```javascript
+// scripts/analyze-tailwind-usage.js
+const fs = require('fs')
+const path = require('path')
+const glob = require('glob')
+
+class TailwindUsageAnalyzer {
+ constructor(options = {}) {
+ this.srcPaths = options.srcPaths || ['src/**/*.{js,jsx,ts,tsx,vue,html}']
+ this.outputPath = options.outputPath || './tailwind-analysis.json'
+ this.classPattern = /(?:class|className)(?:Name)?[`:=]\s*[`"']([^`"']*)[`"']/g
+ }
+
+ async analyze() {
+ const files = this.getTemplateFiles()
+ const results = {
+ totalFiles: files.length,
+ totalClasses: 0,
+ utilityStats: {},
+ fileStats: {},
+ categoryStats: {},
+ complexityStats: {},
+ timestamp: new Date().toISOString()
+ }
+
+ for (const file of files) {
+ const content = fs.readFileSync(file, 'utf8')
+ const fileClasses = this.extractClasses(content)
+
+ results.fileStats[file] = {
+ classCount: fileClasses.length,
+ uniqueClasses: [...new Set(fileClasses)].length,
+ complexity: this.calculateComplexity(fileClasses)
+ }
+
+ // Update utility stats
+ fileClasses.forEach(className => {
+ results.utilityStats[className] = (results.utilityStats[className] || 0) + 1
+ results.totalClasses++
+
+ // Categorize utility
+ const category = this.categorizeUtility(className)
+ results.categoryStats[category] = (results.categoryStats[category] || 0) + 1
+ })
+ }
+
+ // Calculate additional insights
+ results.insights = this.generateInsights(results)
+ results.recommendations = this.generateRecommendations(results)
+
+ // Save results
+ fs.writeFileSync(this.outputPath, JSON.stringify(results, null, 2))
+
+ return results
+ }
+
+ getTemplateFiles() {
+ const files = []
+ this.srcPaths.forEach(pattern => {
+ files.push(...glob.sync(pattern))
+ })
+ return files
+ }
+
+ extractClasses(content) {
+ const classes = []
+ let match
+
+ while ((match = this.classPattern.exec(content)) !== null) {
+ const classString = match[1]
+ const classList = classString.split(/\s+/).filter(cls => cls.length > 0)
+ classes.push(...classList)
+ }
+
+ return classes
+ }
+
+ categorizeUtility(className) {
+ const categories = {
+ layout: /^(block|inline|flex|grid|table|hidden|container)/,
+ spacing: /^(p|m|space)[trblxy]?-/,
+ sizing: /^(w|h|max-w|max-h|min-w|min-h)-/,
+ typography: /^(text|font|leading|tracking|whitespace)/,
+ colors: /^(bg|text|border|ring)-.+-(50|100|200|300|400|500|600|700|800|900|950)$/,
+ borders: /^(border|rounded|ring|divide)/,
+ effects: /^(shadow|opacity|blur)/,
+ filters: /^(filter|backdrop|brightness|contrast|grayscale)/,
+ animation: /^(animate|transition|duration|ease|delay)/,
+ transforms: /^(transform|scale|rotate|translate|skew)/,
+ interactivity: /^(cursor|select|resize|outline|appearance)/,
+ responsive: /^(sm|md|lg|xl|2xl):/,
+ state: /^(hover|focus|active|disabled|group|peer):/,
+ }
+
+ for (const [category, pattern] of Object.entries(categories)) {
+ if (pattern.test(className)) {
+ return category
+ }
+ }
+
+ return 'other'
+ }
+
+ calculateComplexity(classes) {
+ const uniqueClasses = new Set(classes)
+ const responsiveClasses = classes.filter(c => /^(sm|md|lg|xl|2xl):/.test(c))
+ const stateClasses = classes.filter(c => /^(hover|focus|active|group|peer):/.test(c))
+
+ return {
+ total: classes.length,
+ unique: uniqueClasses.size,
+ responsive: responsiveClasses.length,
+ interactive: stateClasses.length,
+ ratio: classes.length / uniqueClasses.size
+ }
+ }
+
+ generateInsights(results) {
+ const sortedUtilities = Object.entries(results.utilityStats)
+ .sort(([,a], [,b]) => b - a)
+
+ const sortedCategories = Object.entries(results.categoryStats)
+ .sort(([,a], [,b]) => b - a)
+
+ const complexFiles = Object.entries(results.fileStats)
+ .sort(([,a], [,b]) => b.complexity.total - a.complexity.total)
+ .slice(0, 10)
+
+ return {
+ mostUsedUtilities: sortedUtilities.slice(0, 20),
+ leastUsedUtilities: sortedUtilities.slice(-20),
+ topCategories: sortedCategories,
+ mostComplexFiles: complexFiles,
+ averageClassesPerFile: results.totalClasses / results.totalFiles,
+ uniqueUtilityCount: Object.keys(results.utilityStats).length
+ }
+ }
+
+ generateRecommendations(results) {
+ const recommendations = []
+
+ // Check for overused utilities
+ const overusedUtilities = results.insights.mostUsedUtilities
+ .filter(([,count]) => count > results.totalFiles * 0.8)
+
+ if (overusedUtilities.length > 0) {
+ recommendations.push({
+ type: 'component-extraction',
+ message: 'Consider extracting components for frequently used utility combinations',
+ utilities: overusedUtilities.slice(0, 5).map(([name]) => name)
+ })
+ }
+
+ // Check for complex files
+ const complexFiles = results.insights.mostComplexFiles
+ .filter(([,stats]) => stats.complexity.total > 50)
+
+ if (complexFiles.length > 0) {
+ recommendations.push({
+ type: 'complexity-reduction',
+ message: 'These files have high utility complexity and may benefit from refactoring',
+ files: complexFiles.slice(0, 5).map(([file]) => file)
+ })
+ }
+
+ // Check for unused categories
+ const lowUsageCategories = Object.entries(results.categoryStats)
+ .filter(([,count]) => count < results.totalClasses * 0.01)
+
+ if (lowUsageCategories.length > 0) {
+ recommendations.push({
+ type: 'config-optimization',
+ message: 'Consider removing unused utility categories from your build',
+ categories: lowUsageCategories.map(([name]) => name)
+ })
+ }
+
+ return recommendations
+ }
+}
+
+// Usage
+const analyzer = new TailwindUsageAnalyzer({
+ srcPaths: ['src/**/*.{jsx,tsx}', 'pages/**/*.{jsx,tsx}'],
+ outputPath: './reports/tailwind-usage.json'
+})
+
+analyzer.analyze().then(results => {
+ console.log('TailwindCSS Usage Analysis Complete!')
+ console.log(`Analyzed ${results.totalFiles} files`)
+ console.log(`Found ${results.totalClasses} utility class usages`)
+ console.log(`${results.insights.uniqueUtilityCount} unique utilities`)
+ console.log(`Average ${results.insights.averageClassesPerFile.toFixed(1)} classes per file`)
+
+ console.log('\nTop 10 Most Used Utilities:')
+ results.insights.mostUsedUtilities.slice(0, 10).forEach(([name, count]) => {
+ console.log(` ${name}: ${count} usages`)
+ })
+
+ console.log('\nRecommendations:')
+ results.recommendations.forEach(rec => {
+ console.log(` ${rec.type}: ${rec.message}`)
+ })
+})
+```
+
+### Bundle Size Analyzer
+
+```javascript
+// scripts/analyze-bundle-size.js
+const fs = require('fs')
+const gzipSize = require('gzip-size')
+const brotliSize = require('brotli-size')
+
+async function analyzeBundleSize(cssFilePath) {
+ const css = fs.readFileSync(cssFilePath, 'utf8')
+ const originalSize = Buffer.byteLength(css, 'utf8')
+
+ const gzipped = await gzipSize(css)
+ const brotlied = await brotliSize(css)
+
+ // Extract utility classes
+ const utilities = css.match(/\.[a-zA-Z][a-zA-Z0-9_-]*(?::[\w-]+)*(?:,\s*\.[a-zA-Z][a-zA-Z0-9_-]*(?::[\w-]+)*)*\s*{[^}]+}/g) || []
+
+ // Categorize utilities
+ const categories = {
+ layout: 0, spacing: 0, typography: 0, colors: 0,
+ borders: 0, effects: 0, animations: 0, responsive: 0
+ }
+
+ let categorySize = { ...categories }
+
+ utilities.forEach(rule => {
+ const size = Buffer.byteLength(rule, 'utf8')
+
+ if (/\.(flex|grid|block|inline)/.test(rule)) {
+ categorySize.layout += size
+ } else if (/\.(p|m|space)-/.test(rule)) {
+ categorySize.spacing += size
+ } else if (/\.(text|font)-/.test(rule)) {
+ categorySize.typography += size
+ } else if (/\.(bg|text|border)-.+-(50|100|200|300|400|500|600|700|800|900)/.test(rule)) {
+ categorySize.colors += size
+ } else if (/\.(border|rounded|ring)/.test(rule)) {
+ categorySize.borders += size
+ } else if (/\.(shadow|opacity|blur)/.test(rule)) {
+ categorySize.effects += size
+ } else if (/\.(animate|transition)/.test(rule)) {
+ categorySize.animations += size
+ } else if (/@media/.test(rule)) {
+ categorySize.responsive += size
+ }
+ })
+
+ return {
+ original: originalSize,
+ gzipped,
+ brotlied,
+ utilityCount: utilities.length,
+ categoryBreakdown: categorySize,
+ compressionRatio: {
+ gzip: (originalSize / gzipped).toFixed(2),
+ brotli: (originalSize / brotlied).toFixed(2)
+ }
+ }
+}
+
+// Generate size report
+async function generateSizeReport(cssPath) {
+ const analysis = await analyzeBundleSize(cssPath)
+
+ console.log('CSS Bundle Size Analysis')
+ console.log('========================')
+ console.log(`Original size: ${(analysis.original / 1024).toFixed(2)} KB`)
+ console.log(`Gzipped size: ${(analysis.gzipped / 1024).toFixed(2)} KB (${analysis.compressionRatio.gzip}x compression)`)
+ console.log(`Brotli size: ${(analysis.brotlied / 1024).toFixed(2)} KB (${analysis.compressionRatio.brotli}x compression)`)
+ console.log(`Utility rules: ${analysis.utilityCount}`)
+
+ console.log('\nSize by Category:')
+ Object.entries(analysis.categoryBreakdown)
+ .sort(([,a], [,b]) => b - a)
+ .forEach(([category, size]) => {
+ const percentage = ((size / analysis.original) * 100).toFixed(1)
+ console.log(` ${category}: ${(size / 1024).toFixed(2)} KB (${percentage}%)`)
+ })
+}
+
+// Usage: node scripts/analyze-bundle-size.js dist/styles.css
+generateSizeReport(process.argv[2])
+```
+
+## Usage Reports
+
+### HTML Report Generator
+
+```javascript
+// scripts/generate-usage-report.js
+function generateHTMLReport(analysisData) {
+ const html = `
+
+
+
+ TailwindCSS Usage Report
+
+
+
+ TailwindCSS Usage Analysis Report
+ Generated on: ${analysisData.timestamp}
+
+
+
Overview
+
${analysisData.totalFiles} files analyzed
+
${analysisData.totalClasses} utility usages
+
${analysisData.insights.uniqueUtilityCount} unique utilities
+
${analysisData.insights.averageClassesPerFile.toFixed(1)} avg classes/file
+
+
+
+
Top Utility Categories
+
+ Category Usage Count Percentage
+ ${analysisData.insights.topCategories.slice(0, 10).map(([cat, count]) => `
+
+ ${cat}
+ ${count}
+ ${((count / analysisData.totalClasses) * 100).toFixed(1)}%
+
+ `).join('')}
+
+
+
+
+
Most Used Utilities
+
+ Utility Usage Count Files
+ ${analysisData.insights.mostUsedUtilities.slice(0, 20).map(([util, count]) => `
+
+ ${util}
+ ${count}
+ ${Math.round((count / analysisData.totalFiles) * 100)}%
+
+ `).join('')}
+
+
+
+
+
Most Complex Files
+
+ File Total Classes Unique Classes Complexity Ratio
+ ${analysisData.insights.mostComplexFiles.slice(0, 10).map(([file, stats]) => `
+
+ ${file}
+ ${stats.complexity.total}
+ ${stats.complexity.unique}
+ ${stats.complexity.ratio.toFixed(2)}
+
+ `).join('')}
+
+
+
+
+
Recommendations
+
+ ${analysisData.recommendations.map(rec => `
+
+ ${rec.type.replace('-', ' ')}: ${rec.message}
+ ${rec.utilities ? `Utilities: ${rec.utilities.join(', ')} ` : ''}
+ ${rec.files ? `Files: ${rec.files.slice(0, 3).join(', ')} ` : ''}
+ ${rec.categories ? `Categories: ${rec.categories.join(', ')} ` : ''}
+
+ `).join('')}
+
+
+
+
+`
+
+ fs.writeFileSync('./reports/tailwind-usage-report.html', html)
+ console.log('HTML report generated: ./reports/tailwind-usage-report.html')
+}
+```
+
+## Automation and Monitoring
+
+### CI/CD Integration
+
+```yaml
+# .github/workflows/tailwind-analysis.yml
+name: TailwindCSS Usage Analysis
+
+on:
+ pull_request:
+ paths:
+ - 'src/**/*.{js,jsx,ts,tsx}'
+ - 'tailwind.config.js'
+
+jobs:
+ analyze:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: '18'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Run TailwindCSS usage analysis
+ run: node scripts/analyze-tailwind-usage.js
+
+ - name: Generate size analysis
+ run: |
+ npm run build:css
+ node scripts/analyze-bundle-size.js dist/styles.css > bundle-size-report.txt
+
+ - name: Comment PR with analysis
+ uses: actions/github-script@v6
+ with:
+ script: |
+ const fs = require('fs');
+ const analysis = JSON.parse(fs.readFileSync('./reports/tailwind-usage.json', 'utf8'));
+ const sizeReport = fs.readFileSync('bundle-size-report.txt', 'utf8');
+
+ const body = `## 📊 TailwindCSS Analysis
+
+ **Usage Statistics:**
+ - Files analyzed: ${analysis.totalFiles}
+ - Total utility usages: ${analysis.totalClasses}
+ - Unique utilities: ${analysis.insights.uniqueUtilityCount}
+ - Average classes per file: ${analysis.insights.averageClassesPerFile.toFixed(1)}
+
+ **Bundle Size:**
+ \`\`\`
+ ${sizeReport}
+ \`\`\`
+
+ **Top Recommendations:**
+ ${analysis.recommendations.slice(0, 3).map(rec => `- ${rec.message}`).join('\n')}
+ `;
+
+ github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: body
+ });
+```
+
+Remember: **Regular analysis helps maintain optimal TailwindCSS usage and identifies optimization opportunities early!**
diff --git a/ui/tailwindcss/.claude/commands/component.md b/ui/tailwindcss/.claude/commands/component.md
new file mode 100644
index 0000000..88f6ec1
--- /dev/null
+++ b/ui/tailwindcss/.claude/commands/component.md
@@ -0,0 +1,18 @@
+---
+description: Generate component with Tailwind utility classes
+argument-hint: "[component-name] [type]"
+allowed-tools: Write, Read, Edit
+---
+
+Generate Tailwind component: $ARGUMENTS
+
+Follow utility-first principles:
+1. Create component with proper utility classes
+2. Include responsive design patterns
+3. Add dark mode support if applicable
+4. Use semantic class combinations
+5. Include accessibility utilities
+
+Types: button, card, form, layout, navigation
+
+Example: `/component Button primary` or `/component Card hover`
diff --git a/ui/tailwindcss/.claude/commands/create-component.md b/ui/tailwindcss/.claude/commands/create-component.md
new file mode 100644
index 0000000..fab23f5
--- /dev/null
+++ b/ui/tailwindcss/.claude/commands/create-component.md
@@ -0,0 +1,716 @@
+---
+name: create-component
+description: Create reusable components using TailwindCSS utilities with proper patterns and best practices
+tools: Write, Edit, Read, Grep, Glob
+---
+
+# Create TailwindCSS Component
+
+This command helps create well-structured, reusable components using TailwindCSS utilities following best practices and design system patterns.
+
+## What This Command Does
+
+1. **Component Architecture**
+ - Creates component files with proper TailwindCSS utility composition
+ - Implements responsive design patterns
+ - Sets up proper TypeScript/PropTypes definitions
+ - Follows accessibility best practices
+
+2. **Utility Composition**
+ - Uses semantic utility class combinations
+ - Implements proper state management (hover, focus, active)
+ - Creates responsive variants using breakpoint prefixes
+ - Follows mobile-first methodology
+
+3. **Design System Integration**
+ - Uses design tokens from TailwindCSS configuration
+ - Implements consistent spacing and typography scales
+ - Applies proper color palette and semantic colors
+ - Follows component variant patterns
+
+4. **Performance Optimization**
+ - Uses efficient utility combinations
+ - Optimizes for CSS purging
+ - Implements proper class composition strategies
+ - Avoids unnecessary custom CSS
+
+## Component Templates
+
+### Button Component
+
+```jsx
+// components/Button.jsx
+import React from 'react'
+import { cva } from 'class-variance-authority'
+import { cn } from '@/lib/utils'
+
+const buttonVariants = cva(
+ // Base styles
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm 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: {
+ variant: {
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
+ },
+ size: {
+ default: "h-10 px-4 py-2",
+ sm: "h-9 rounded-md px-3",
+ lg: "h-11 rounded-md px-8",
+ icon: "h-10 w-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes {
+ variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'
+ size?: 'default' | 'sm' | 'lg' | 'icon'
+ loading?: boolean
+ leftIcon?: React.ReactNode
+ rightIcon?: React.ReactNode
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, loading, leftIcon, rightIcon, children, ...props }, ref) => {
+ return (
+
+ {loading ? (
+
+
+
+
+ ) : leftIcon ? (
+ {leftIcon}
+ ) : null}
+
+ {children}
+
+ {rightIcon && !loading && (
+ {rightIcon}
+ )}
+
+ )
+ }
+)
+
+Button.displayName = "Button"
+
+export { Button, buttonVariants }
+```
+
+### Card Component
+
+```jsx
+// components/Card.jsx
+import React from 'react'
+import { cn } from '@/lib/utils'
+
+const Card = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes & {
+ hover?: boolean
+ padding?: 'none' | 'sm' | 'md' | 'lg'
+ }
+>(({ className, hover = false, padding = 'md', children, ...props }, ref) => {
+ const paddingMap = {
+ none: '',
+ sm: 'p-4',
+ md: 'p-6',
+ lg: 'p-8'
+ }
+
+ return (
+
+ {children}
+
+ )
+})
+
+const CardHeader = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+
+const CardTitle = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+
+const CardDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+
+const CardContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+
+const CardFooter = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+
+Card.displayName = "Card"
+CardHeader.displayName = "CardHeader"
+CardTitle.displayName = "CardTitle"
+CardDescription.displayName = "CardDescription"
+CardContent.displayName = "CardContent"
+CardFooter.displayName = "CardFooter"
+
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
+```
+
+### Input Component
+
+```jsx
+// components/Input.jsx
+import React from 'react'
+import { cva } from 'class-variance-authority'
+import { cn } from '@/lib/utils'
+
+const inputVariants = cva(
+ "flex w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
+ {
+ variants: {
+ size: {
+ sm: "h-8 px-2 text-xs",
+ default: "h-10 px-3",
+ lg: "h-12 px-4 text-base",
+ },
+ state: {
+ default: "",
+ error: "border-destructive focus-visible:ring-destructive",
+ success: "border-green-500 focus-visible:ring-green-500",
+ },
+ },
+ defaultVariants: {
+ size: "default",
+ state: "default",
+ },
+ }
+)
+
+export interface InputProps
+ extends React.InputHTMLAttributes {
+ size?: 'sm' | 'default' | 'lg'
+ state?: 'default' | 'error' | 'success'
+ label?: string
+ helperText?: string
+ error?: string
+ leftIcon?: React.ReactNode
+ rightIcon?: React.ReactNode
+}
+
+const Input = React.forwardRef(
+ ({
+ className,
+ type,
+ size,
+ state,
+ label,
+ helperText,
+ error,
+ leftIcon,
+ rightIcon,
+ ...props
+ }, ref) => {
+ const inputState = error ? 'error' : state
+
+ return (
+
+ {label && (
+
+ {label}
+
+ )}
+
+
+ {leftIcon && (
+
+ {leftIcon}
+
+ )}
+
+
+
+ {rightIcon && (
+
+ {rightIcon}
+
+ )}
+
+
+ {(helperText || error) && (
+
+ {error || helperText}
+
+ )}
+
+ )
+ }
+)
+
+Input.displayName = "Input"
+
+export { Input, inputVariants }
+```
+
+### Badge Component
+
+```jsx
+// components/Badge.jsx
+import React from 'react'
+import { cva } from 'class-variance-authority'
+import { cn } from '@/lib/utils'
+
+const badgeVariants = cva(
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
+ {
+ variants: {
+ variant: {
+ default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
+ success: "border-transparent bg-green-500 text-white hover:bg-green-600",
+ warning: "border-transparent bg-yellow-500 text-white hover:bg-yellow-600",
+ outline: "text-foreground",
+ },
+ size: {
+ sm: "px-2 py-0.5 text-xs",
+ default: "px-2.5 py-0.5 text-xs",
+ lg: "px-3 py-1 text-sm",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ }
+)
+
+export interface BadgeProps
+ extends React.HTMLAttributes {
+ variant?: 'default' | 'secondary' | 'destructive' | 'success' | 'warning' | 'outline'
+ size?: 'sm' | 'default' | 'lg'
+ removable?: boolean
+ onRemove?: () => void
+}
+
+const Badge = React.forwardRef(
+ ({ className, variant, size, removable, onRemove, children, ...props }, ref) => {
+ return (
+
+ {children}
+ {removable && (
+
+
+
+
+
+ )}
+
+ )
+ }
+)
+
+Badge.displayName = "Badge"
+
+export { Badge, badgeVariants }
+```
+
+### Alert Component
+
+```jsx
+// components/Alert.jsx
+import React from 'react'
+import { cva } from 'class-variance-authority'
+import { cn } from '@/lib/utils'
+
+const alertVariants = cva(
+ "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
+ {
+ variants: {
+ variant: {
+ default: "bg-background text-foreground",
+ destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
+ success: "border-green-500/50 text-green-700 dark:text-green-400 [&>svg]:text-green-600",
+ warning: "border-yellow-500/50 text-yellow-700 dark:text-yellow-400 [&>svg]:text-yellow-600",
+ info: "border-blue-500/50 text-blue-700 dark:text-blue-400 [&>svg]:text-blue-600",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+const Alert = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes & {
+ variant?: 'default' | 'destructive' | 'success' | 'warning' | 'info'
+ dismissible?: boolean
+ onDismiss?: () => void
+ }
+>(({ className, variant, dismissible, onDismiss, children, ...props }, ref) => (
+
+ {children}
+ {dismissible && (
+
+
+
+
+ Close
+
+ )}
+
+))
+
+const AlertTitle = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+
+const AlertDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+
+Alert.displayName = "Alert"
+AlertTitle.displayName = "AlertTitle"
+AlertDescription.displayName = "AlertDescription"
+
+export { Alert, AlertTitle, AlertDescription }
+```
+
+## Layout Components
+
+### Container Component
+
+```jsx
+// components/Container.jsx
+import React from 'react'
+import { cn } from '@/lib/utils'
+
+export interface ContainerProps extends React.HTMLAttributes {
+ size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full'
+ padding?: boolean
+}
+
+const Container = React.forwardRef(
+ ({ className, size = 'lg', padding = true, ...props }, ref) => {
+ const sizeClasses = {
+ sm: 'max-w-2xl',
+ md: 'max-w-4xl',
+ lg: 'max-w-6xl',
+ xl: 'max-w-7xl',
+ '2xl': 'max-w-8xl',
+ full: 'max-w-full'
+ }
+
+ return (
+
+ )
+ }
+)
+
+Container.displayName = 'Container'
+
+export { Container }
+```
+
+### Grid Component
+
+```jsx
+// components/Grid.jsx
+import React from 'react'
+import { cn } from '@/lib/utils'
+
+export interface GridProps extends React.HTMLAttributes {
+ cols?: 1 | 2 | 3 | 4 | 5 | 6 | 12
+ gap?: 'none' | 'sm' | 'md' | 'lg' | 'xl'
+ responsive?: boolean
+}
+
+const Grid = React.forwardRef(
+ ({ className, cols = 1, gap = 'md', responsive = true, ...props }, ref) => {
+ const gapClasses = {
+ none: 'gap-0',
+ sm: 'gap-2',
+ md: 'gap-4',
+ lg: 'gap-6',
+ xl: 'gap-8'
+ }
+
+ const getResponsiveCols = (cols: number) => {
+ if (!responsive) return `grid-cols-${cols}`
+
+ switch (cols) {
+ case 1: return 'grid-cols-1'
+ case 2: return 'grid-cols-1 md:grid-cols-2'
+ case 3: return 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3'
+ case 4: return 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4'
+ case 5: return 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5'
+ case 6: return 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6'
+ case 12: return 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-12'
+ default: return `grid-cols-${cols}`
+ }
+ }
+
+ return (
+
+ )
+ }
+)
+
+Grid.displayName = 'Grid'
+
+export { Grid }
+```
+
+## Utility Functions
+
+### Class Name Utility
+
+```typescript
+// lib/utils.ts
+import { type ClassValue, clsx } from 'clsx'
+import { twMerge } from 'tailwind-merge'
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
+
+// Responsive utility
+export function responsive(
+ base: string,
+ sm?: string,
+ md?: string,
+ lg?: string,
+ xl?: string,
+ xxl?: string
+) {
+ return cn(
+ base,
+ sm && `sm:${sm}`,
+ md && `md:${md}`,
+ lg && `lg:${lg}`,
+ xl && `xl:${xl}`,
+ xxl && `2xl:${xxl}`
+ )
+}
+
+// Focus ring utility
+export function focusRing(color: string = 'ring-primary') {
+ return `focus:outline-none focus:ring-2 ${color} focus:ring-offset-2`
+}
+```
+
+## Component Generation Script
+
+### Auto-generate Component
+
+```javascript
+// scripts/create-component.js
+const fs = require('fs')
+const path = require('path')
+
+function createComponent(name, type = 'basic') {
+ const componentName = name.charAt(0).toUpperCase() + name.slice(1)
+ const fileName = `${componentName}.tsx`
+ const componentDir = `./components/${componentName}`
+
+ // Create component directory
+ if (!fs.existsSync(componentDir)) {
+ fs.mkdirSync(componentDir, { recursive: true })
+ }
+
+ const templates = {
+ basic: basicComponentTemplate,
+ form: formComponentTemplate,
+ layout: layoutComponentTemplate,
+ interactive: interactiveComponentTemplate
+ }
+
+ const template = templates[type] || templates.basic
+ const componentCode = template(componentName, name)
+
+ // Write component file
+ fs.writeFileSync(path.join(componentDir, fileName), componentCode)
+
+ // Create index file
+ const indexContent = `export { ${componentName} } from './${componentName}'\nexport type { ${componentName}Props } from './${componentName}'`
+ fs.writeFileSync(path.join(componentDir, 'index.ts'), indexContent)
+
+ console.log(`✅ Component ${componentName} created successfully!`)
+ console.log(`📁 Location: ${componentDir}`)
+ console.log(`📝 Files created:`)
+ console.log(` - ${fileName}`)
+ console.log(` - index.ts`)
+}
+
+function basicComponentTemplate(componentName, kebabName) {
+ return `import React from 'react'
+import { cn } from '@/lib/utils'
+
+export interface ${componentName}Props extends React.HTMLAttributes {
+ variant?: 'default' | 'secondary'
+ size?: 'sm' | 'md' | 'lg'
+}
+
+const ${componentName} = React.forwardRef(
+ ({ className, variant = 'default', size = 'md', children, ...props }, ref) => {
+ const variants = {
+ default: 'bg-background text-foreground',
+ secondary: 'bg-secondary text-secondary-foreground'
+ }
+
+ const sizes = {
+ sm: 'p-2 text-sm',
+ md: 'p-4 text-base',
+ lg: 'p-6 text-lg'
+ }
+
+ return (
+
+ {children}
+
+ )
+ }
+)
+
+${componentName}.displayName = '${componentName}'
+
+export { ${componentName} }
+`
+}
+
+// Usage: node scripts/create-component.js MyComponent basic
+const [,, name, type] = process.argv
+if (!name) {
+ console.error('Please provide a component name')
+ process.exit(1)
+}
+
+createComponent(name, type)
+```
+
+Remember: **Focus on utility composition, responsive design, accessibility, and performance optimization when creating TailwindCSS components!**
diff --git a/ui/tailwindcss/.claude/commands/init-tailwind.md b/ui/tailwindcss/.claude/commands/init-tailwind.md
new file mode 100644
index 0000000..604c47e
--- /dev/null
+++ b/ui/tailwindcss/.claude/commands/init-tailwind.md
@@ -0,0 +1,229 @@
+---
+name: init-tailwind
+description: Initialize TailwindCSS in a new project with optimal configuration
+tools: Write, Edit, Bash
+---
+
+# Initialize TailwindCSS Project
+
+This command sets up a new TailwindCSS project with best practices and optimal configuration.
+
+## What This Command Does
+
+1. **Install TailwindCSS and Dependencies**
+ - Installs TailwindCSS, PostCSS, and Autoprefixer
+ - Adds common TailwindCSS plugins
+ - Sets up development dependencies
+
+2. **Create Configuration Files**
+ - Generates optimized `tailwind.config.js`
+ - Creates `postcss.config.js`
+ - Sets up CSS entry point with Tailwind directives
+
+3. **Configure Content Paths**
+ - Sets up content scanning for your framework
+ - Optimizes purging configuration
+ - Adds safelist for dynamic classes
+
+## Usage Examples
+
+### Next.js Project
+
+```bash
+# Install TailwindCSS for Next.js
+npm install -D tailwindcss postcss autoprefixer @tailwindcss/typography @tailwindcss/forms @tailwindcss/aspect-ratio
+
+# Generate config files
+npx tailwindcss init -p
+
+# Configure for Next.js paths
+```
+
+### React/Vite Project
+
+```bash
+# Install TailwindCSS for Vite
+npm install -D tailwindcss postcss autoprefixer @tailwindcss/typography @tailwindcss/forms
+
+# Generate config
+npx tailwindcss init -p
+
+# Configure for React/Vite paths
+```
+
+### Vanilla HTML Project
+
+```bash
+# Install TailwindCSS CLI
+npm install -D tailwindcss
+
+# Generate config
+npx tailwindcss init
+
+# Build CSS file
+npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
+```
+
+## Configuration Templates
+
+### Optimized Tailwind Config
+
+```javascript
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ './pages/**/*.{js,ts,jsx,tsx,mdx}',
+ './components/**/*.{js,ts,jsx,tsx,mdx}',
+ './app/**/*.{js,ts,jsx,tsx,mdx}',
+ './src/**/*.{js,ts,jsx,tsx,mdx}',
+ ],
+ darkMode: 'class',
+ theme: {
+ extend: {
+ colors: {
+ primary: {
+ 50: '#eff6ff',
+ 100: '#dbeafe',
+ 200: '#bfdbfe',
+ 300: '#93c5fd',
+ 400: '#60a5fa',
+ 500: '#3b82f6',
+ 600: '#2563eb',
+ 700: '#1d4ed8',
+ 800: '#1e40af',
+ 900: '#1e3a8a',
+ 950: '#172554',
+ },
+ },
+ fontFamily: {
+ sans: ['Inter', 'system-ui', 'sans-serif'],
+ },
+ animation: {
+ 'fade-in': 'fadeIn 0.5s ease-in-out',
+ 'slide-up': 'slideUp 0.3s ease-out',
+ },
+ keyframes: {
+ fadeIn: {
+ '0%': { opacity: '0' },
+ '100%': { opacity: '1' },
+ },
+ slideUp: {
+ '0%': { transform: 'translateY(10px)', opacity: '0' },
+ '100%': { transform: 'translateY(0)', opacity: '1' },
+ },
+ },
+ },
+ },
+ plugins: [
+ require('@tailwindcss/typography'),
+ require('@tailwindcss/forms'),
+ require('@tailwindcss/aspect-ratio'),
+ ],
+}
+```
+
+### PostCSS Configuration
+
+```javascript
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
+```
+
+### CSS Entry Point
+
+```css
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ html {
+ font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
+ }
+
+ body {
+ @apply bg-white text-gray-900 dark:bg-gray-900 dark:text-gray-100;
+ }
+}
+
+@layer components {
+ .btn {
+ @apply inline-flex items-center justify-center rounded-md px-4 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50;
+ }
+
+ .btn-primary {
+ @apply bg-primary-600 text-white hover:bg-primary-700 focus-visible:ring-primary-500;
+ }
+}
+```
+
+## Project-Specific Optimizations
+
+### Next.js Optimization
+
+```javascript
+// next.config.js
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ experimental: {
+ optimizeCss: true,
+ },
+}
+module.exports = nextConfig
+```
+
+### Vite Optimization
+
+```javascript
+// vite.config.js
+import { defineConfig } from 'vite'
+
+export default defineConfig({
+ css: {
+ postcss: './postcss.config.js',
+ },
+ build: {
+ cssCodeSplit: true,
+ },
+})
+```
+
+## Package.json Scripts
+
+```json
+{
+ "scripts": {
+ "build-css": "tailwindcss -i ./src/input.css -o ./dist/output.css",
+ "watch-css": "tailwindcss -i ./src/input.css -o ./dist/output.css --watch",
+ "build-css-prod": "tailwindcss -i ./src/input.css -o ./dist/output.css --minify"
+ }
+}
+```
+
+## Best Practices Setup
+
+1. **Content Configuration**
+ - Include all template file paths
+ - Use specific extensions for better performance
+ - Exclude build directories and node_modules
+
+2. **Plugin Selection**
+ - Start with essential plugins (typography, forms)
+ - Add aspect-ratio for responsive images
+ - Consider container-queries for advanced layouts
+
+3. **Theme Configuration**
+ - Extend default theme rather than replacing
+ - Use semantic color names
+ - Define consistent spacing and typography scales
+
+4. **Performance**
+ - Enable CSS purging for production
+ - Use specific content paths
+ - Consider CSS-in-JS integration if needed
+
+Remember: **Start simple, extend gradually, and optimize for your specific use case!**
diff --git a/ui/tailwindcss/.claude/commands/optimize-config.md b/ui/tailwindcss/.claude/commands/optimize-config.md
new file mode 100644
index 0000000..f55ed0f
--- /dev/null
+++ b/ui/tailwindcss/.claude/commands/optimize-config.md
@@ -0,0 +1,412 @@
+---
+name: optimize-config
+description: Optimize TailwindCSS configuration for better performance, smaller bundle size, and efficient development workflow
+tools: Read, Edit, Bash, Grep, Glob
+---
+
+# Optimize TailwindCSS Configuration
+
+This command analyzes and optimizes your TailwindCSS setup for maximum performance and minimal bundle size.
+
+## What This Command Does
+
+1. **Content Path Optimization**
+ - Analyzes project structure to optimize content scanning
+ - Configures precise file patterns for better purging
+ - Excludes unnecessary directories and files
+
+2. **Bundle Size Analysis**
+ - Identifies unused utilities in your CSS bundle
+ - Optimizes safelist configuration
+ - Configures effective CSS purging strategies
+
+3. **Build Performance**
+ - Optimizes PostCSS pipeline configuration
+ - Configures caching strategies
+ - Sets up development vs production optimizations
+
+4. **Plugin and Theme Cleanup**
+ - Removes unused plugins and theme extensions
+ - Optimizes custom utility configurations
+ - Cleans up redundant theme settings
+
+## Usage Examples
+
+### Analyze Current Bundle Size
+
+```bash
+# Build CSS and analyze size
+npx tailwindcss -i ./src/styles.css -o ./dist/output.css
+wc -c ./dist/output.css
+
+# With minification
+npx tailwindcss -i ./src/styles.css -o ./dist/output.css --minify
+wc -c ./dist/output.css
+
+# Compress with Brotli
+brotli -q 11 ./dist/output.css
+ls -lh ./dist/output.css.br
+```
+
+### Content Path Optimization
+
+```javascript
+// Before: Generic paths
+module.exports = {
+ content: ["./src/**/*.{js,jsx,ts,tsx}"],
+}
+
+// After: Specific optimized paths
+module.exports = {
+ content: [
+ // Be specific about directories
+ './pages/**/*.{js,ts,jsx,tsx,mdx}',
+ './components/**/*.{js,ts,jsx,tsx}',
+ './app/**/*.{js,ts,jsx,tsx}',
+ './lib/**/*.{js,ts}',
+
+ // Include component libraries if used
+ './node_modules/@your-ui-lib/**/*.{js,ts,jsx,tsx}',
+
+ // Exclude unnecessary files
+ '!./node_modules',
+ '!./.git',
+ '!./.next',
+ '!./dist',
+ '!./coverage',
+ ],
+}
+```
+
+### Advanced Content Configuration
+
+```javascript
+module.exports = {
+ content: [
+ {
+ files: ['./src/**/*.{js,ts,jsx,tsx}'],
+ // Custom extraction for complex patterns
+ transform: {
+ js: (content) => {
+ // Extract classes from template literals
+ return content.match(/(?:class|className)(?:Name)?[`:=]\s*[`"']([^`"']*)[`"']/g) || []
+ }
+ }
+ },
+ {
+ files: ['./components/**/*.{js,ts,jsx,tsx}'],
+ // Extract dynamic class compositions
+ transform: {
+ jsx: (content) => {
+ const matches = content.match(/(?:clsx|cn|twMerge)\([^)]*\)/g) || []
+ return matches.join(' ')
+ }
+ }
+ }
+ ]
+}
+```
+
+## Performance Optimizations
+
+### Production Build Configuration
+
+```javascript
+// postcss.config.js - Environment-specific optimization
+module.exports = {
+ plugins: [
+ require('tailwindcss'),
+ require('autoprefixer'),
+
+ // Production-only optimizations
+ ...(process.env.NODE_ENV === 'production' ? [
+ require('@fullhuman/postcss-purgecss')({
+ content: [
+ './pages/**/*.{js,ts,jsx,tsx}',
+ './components/**/*.{js,ts,jsx,tsx}',
+ ],
+ defaultExtractor: content => content.match(/[\w-/:]+(? {
+ // CSS optimization for production
+ if (!dev && !isServer) {
+ config.optimization.splitChunks.cacheGroups.styles = {
+ name: 'styles',
+ test: /\.(css|scss)$/,
+ chunks: 'all',
+ enforce: true,
+ }
+ }
+
+ return config
+ },
+}
+
+module.exports = nextConfig
+```
+
+### Vite Optimization
+
+```javascript
+// vite.config.js
+import { defineConfig } from 'vite'
+
+export default defineConfig({
+ css: {
+ postcss: './postcss.config.js',
+ devSourcemap: true,
+ },
+
+ build: {
+ cssCodeSplit: true,
+ cssMinify: 'esbuild',
+
+ rollupOptions: {
+ output: {
+ manualChunks: {
+ 'tailwind-base': ['tailwindcss/base'],
+ 'tailwind-components': ['tailwindcss/components'],
+ 'tailwind-utilities': ['tailwindcss/utilities']
+ }
+ }
+ },
+
+ reportCompressedSize: true,
+ chunkSizeWarningLimit: 1000,
+ },
+})
+```
+
+## Safelist Optimization
+
+### Smart Safelist Configuration
+
+```javascript
+module.exports = {
+ safelist: [
+ // Dynamic color variations
+ {
+ pattern: /^(bg|text|border)-(red|green|blue|yellow|purple)-(50|100|500|600|700|900)$/,
+ variants: ['hover', 'focus', 'active', 'disabled'],
+ },
+
+ // Animation and state classes
+ {
+ pattern: /^(opacity|scale|rotate|translate[xy]?)-(0|25|50|75|100)$/,
+ variants: ['group-hover', 'peer-focus', 'motion-reduce'],
+ },
+
+ // Responsive grid columns (often dynamically generated)
+ /^grid-cols-(1|2|3|4|6|12)$/,
+
+ // Common state classes
+ /^(animate|transition)-.+/,
+
+ // Dynamic spacing that might be calculated
+ {
+ pattern: /^(p|m|w|h)-(0|1|2|4|8|16|32|64)$/,
+ variants: ['sm', 'md', 'lg', 'xl', '2xl'],
+ },
+ ],
+
+ // Block classes that should never be included
+ blocklist: [
+ 'container', // If using custom container
+ 'debug-*', // Debug utilities
+ ],
+}
+```
+
+## Bundle Analysis Tools
+
+### CSS Analysis Script
+
+```javascript
+// scripts/analyze-css.js
+const fs = require('fs')
+const path = require('path')
+
+function analyzeCSSBundle(filePath) {
+ const css = fs.readFileSync(filePath, 'utf8')
+
+ // Extract all utility classes
+ const utilities = css.match(/\.[a-zA-Z][a-zA-Z0-9_-]*\s*{/g) || []
+ const uniqueUtilities = [...new Set(utilities.map(u => u.replace(/\s*{$/, '')))]
+
+ // File size analysis
+ const stats = fs.statSync(filePath)
+ const sizeKB = (stats.size / 1024).toFixed(2)
+
+ console.log(`CSS Bundle Analysis:`)
+ console.log(`- File size: ${sizeKB}KB`)
+ console.log(`- Utility classes: ${uniqueUtilities.length}`)
+ console.log(`- Average bytes per utility: ${(stats.size / uniqueUtilities.length).toFixed(2)}`)
+
+ // Most common utility patterns
+ const patterns = {}
+ uniqueUtilities.forEach(utility => {
+ const pattern = utility.replace(/\d+/g, '#').replace(/-(xs|sm|md|lg|xl|2xl)$/, '-*')
+ patterns[pattern] = (patterns[pattern] || 0) + 1
+ })
+
+ const topPatterns = Object.entries(patterns)
+ .sort(([,a], [,b]) => b - a)
+ .slice(0, 10)
+
+ console.log('\nTop utility patterns:')
+ topPatterns.forEach(([pattern, count]) => {
+ console.log(`- ${pattern}: ${count} variants`)
+ })
+}
+
+// Usage: node scripts/analyze-css.js dist/output.css
+analyzeCSSBundle(process.argv[2])
+```
+
+### Unused CSS Detection
+
+```bash
+# Using PurgeCSS to find unused CSS
+npm install -g purgecss
+
+# Analyze unused CSS
+purgecss --css dist/styles.css \
+ --content 'src/**/*.{js,jsx,ts,tsx}' \
+ --output temp/ \
+ --rejected
+
+# Compare sizes
+echo "Original size:" && wc -c dist/styles.css
+echo "Purged size:" && wc -c temp/styles.css
+```
+
+## Monitoring and Automation
+
+### GitHub Actions for Bundle Size Monitoring
+
+```yaml
+# .github/workflows/css-size-check.yml
+name: CSS Bundle Size Check
+
+on: [pull_request]
+
+jobs:
+ css-size:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: '18'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build CSS
+ run: npm run build:css
+
+ - name: Check bundle size
+ run: |
+ SIZE=$(wc -c < dist/styles.css)
+ echo "CSS bundle size: $SIZE bytes"
+ if [ $SIZE -gt 100000 ]; then
+ echo "❌ CSS bundle is too large (>100KB)"
+ exit 1
+ else
+ echo "✅ CSS bundle size is acceptable"
+ fi
+
+ - name: Comment PR
+ uses: actions/github-script@v6
+ with:
+ script: |
+ const fs = require('fs');
+ const size = fs.statSync('dist/styles.css').size;
+ const sizeKB = (size / 1024).toFixed(2);
+
+ github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: `📊 CSS Bundle Size: ${sizeKB}KB`
+ });
+```
+
+### Pre-commit Hook for CSS Optimization
+
+```bash
+#!/bin/sh
+# .husky/pre-commit
+
+# Build CSS and check size
+npm run build:css
+
+# Check if CSS file is too large
+SIZE=$(wc -c < dist/styles.css)
+if [ $SIZE -gt 100000 ]; then
+ echo "❌ CSS bundle is too large (${SIZE} bytes > 100KB)"
+ echo "Consider optimizing your Tailwind configuration"
+ exit 1
+fi
+
+echo "✅ CSS bundle size is acceptable (${SIZE} bytes)"
+```
+
+## Optimization Checklist
+
+### Performance Checklist
+
+- [ ] Content paths are specific and exclude unnecessary files
+- [ ] Safelist includes only genuinely dynamic classes
+- [ ] Unused plugins are removed from configuration
+- [ ] CSS is minified in production builds
+- [ ] CSS code splitting is enabled where possible
+- [ ] Bundle size is monitored in CI/CD pipeline
+
+### Development Experience Checklist
+
+- [ ] Hot reload works efficiently with content changes
+- [ ] Build times are optimized for development
+- [ ] Source maps are available for debugging
+- [ ] Error reporting is clear for configuration issues
+
+### Production Checklist
+
+- [ ] CSS is compressed (Gzip/Brotli)
+- [ ] Critical CSS is inlined where beneficial
+- [ ] Unused CSS is properly purged
+- [ ] Bundle analysis is automated
+- [ ] Performance monitoring is in place
+
+Remember: **Optimize for your specific use case, measure before and after, and maintain monitoring over time!**
diff --git a/ui/tailwindcss/.claude/commands/setup-dark-mode.md b/ui/tailwindcss/.claude/commands/setup-dark-mode.md
new file mode 100644
index 0000000..7b18b13
--- /dev/null
+++ b/ui/tailwindcss/.claude/commands/setup-dark-mode.md
@@ -0,0 +1,721 @@
+---
+name: setup-dark-mode
+description: Set up comprehensive dark mode support with TailwindCSS using CSS variables, theme switching, and system preferences
+tools: Write, Edit, Read, Bash
+---
+
+# Setup Dark Mode with TailwindCSS
+
+This command sets up a complete dark mode system using TailwindCSS with CSS variables, automatic theme detection, and smooth transitions.
+
+## What This Command Does
+
+1. **CSS Variables Configuration**
+ - Sets up semantic color system using CSS variables
+ - Configures light and dark theme variants
+ - Creates smooth transition system between themes
+ - Implements proper contrast ratios for accessibility
+
+2. **Theme Configuration**
+ - Configures TailwindCSS for class-based dark mode
+ - Sets up color palette using CSS variables
+ - Creates theme-aware utility classes
+ - Optimizes for design system consistency
+
+3. **JavaScript Theme Controller**
+ - Detects system theme preferences
+ - Provides manual theme switching functionality
+ - Persists user theme preferences
+ - Handles theme transitions smoothly
+
+4. **Component Integration**
+ - Creates theme-aware components
+ - Implements proper dark mode patterns
+ - Sets up theme toggle components
+ - Provides theme context for React/Vue apps
+
+## Configuration Setup
+
+### TailwindCSS Configuration
+
+```javascript
+// tailwind.config.js
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ './pages/**/*.{js,ts,jsx,tsx,mdx}',
+ './components/**/*.{js,ts,jsx,tsx,mdx}',
+ './app/**/*.{js,ts,jsx,tsx,mdx}',
+ './src/**/*.{js,ts,jsx,tsx,mdx}',
+ ],
+ darkMode: 'class', // Enable class-based dark mode
+ theme: {
+ extend: {
+ colors: {
+ // CSS variable-based color system
+ background: 'hsl(var(--background))',
+ foreground: 'hsl(var(--foreground))',
+
+ card: {
+ DEFAULT: 'hsl(var(--card))',
+ foreground: 'hsl(var(--card-foreground))',
+ },
+
+ popover: {
+ DEFAULT: 'hsl(var(--popover))',
+ foreground: 'hsl(var(--popover-foreground))',
+ },
+
+ primary: {
+ DEFAULT: 'hsl(var(--primary))',
+ foreground: 'hsl(var(--primary-foreground))',
+ },
+
+ secondary: {
+ DEFAULT: 'hsl(var(--secondary))',
+ foreground: 'hsl(var(--secondary-foreground))',
+ },
+
+ muted: {
+ DEFAULT: 'hsl(var(--muted))',
+ foreground: 'hsl(var(--muted-foreground))',
+ },
+
+ accent: {
+ DEFAULT: 'hsl(var(--accent))',
+ foreground: 'hsl(var(--accent-foreground))',
+ },
+
+ destructive: {
+ DEFAULT: 'hsl(var(--destructive))',
+ foreground: 'hsl(var(--destructive-foreground))',
+ },
+
+ border: 'hsl(var(--border))',
+ input: 'hsl(var(--input))',
+ ring: 'hsl(var(--ring))',
+
+ // Semantic colors
+ success: {
+ DEFAULT: 'hsl(var(--success))',
+ foreground: 'hsl(var(--success-foreground))',
+ },
+
+ warning: {
+ DEFAULT: 'hsl(var(--warning))',
+ foreground: 'hsl(var(--warning-foreground))',
+ },
+
+ info: {
+ DEFAULT: 'hsl(var(--info))',
+ foreground: 'hsl(var(--info-foreground))',
+ },
+ },
+
+ borderRadius: {
+ lg: 'var(--radius)',
+ md: 'calc(var(--radius) - 2px)',
+ sm: 'calc(var(--radius) - 4px)',
+ },
+
+ boxShadow: {
+ 'sm': 'var(--shadow-sm)',
+ 'DEFAULT': 'var(--shadow)',
+ 'md': 'var(--shadow-md)',
+ 'lg': 'var(--shadow-lg)',
+ 'xl': 'var(--shadow-xl)',
+ },
+ },
+ },
+ plugins: [],
+}
+```
+
+### CSS Variables Setup
+
+```css
+/* globals.css */
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ :root {
+ /* Light theme colors */
+ --background: 0 0% 100%;
+ --foreground: 222.2 84% 4.9%;
+
+ --card: 0 0% 100%;
+ --card-foreground: 222.2 84% 4.9%;
+
+ --popover: 0 0% 100%;
+ --popover-foreground: 222.2 84% 4.9%;
+
+ --primary: 221.2 83.2% 53.3%;
+ --primary-foreground: 210 40% 98%;
+
+ --secondary: 210 40% 96.1%;
+ --secondary-foreground: 222.2 47.4% 11.2%;
+
+ --muted: 210 40% 96.1%;
+ --muted-foreground: 215.4 16.3% 46.9%;
+
+ --accent: 210 40% 96.1%;
+ --accent-foreground: 222.2 47.4% 11.2%;
+
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 210 40% 98%;
+
+ --border: 214.3 31.8% 91.4%;
+ --input: 214.3 31.8% 91.4%;
+ --ring: 222.2 84% 4.9%;
+
+ /* Semantic colors */
+ --success: 142.1 76.2% 36.3%;
+ --success-foreground: 355.7 100% 97.3%;
+
+ --warning: 32.5 94.6% 43.7%;
+ --warning-foreground: 26 83.3% 14.1%;
+
+ --info: 217.2 91.2% 59.8%;
+ --info-foreground: 210 40% 98%;
+
+ /* Design tokens */
+ --radius: 0.5rem;
+
+ /* Shadows */
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
+ --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
+ --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
+ }
+
+ .dark {
+ /* Dark theme colors */
+ --background: 222.2 84% 4.9%;
+ --foreground: 210 40% 98%;
+
+ --card: 222.2 84% 4.9%;
+ --card-foreground: 210 40% 98%;
+
+ --popover: 222.2 84% 4.9%;
+ --popover-foreground: 210 40% 98%;
+
+ --primary: 217.2 91.2% 59.8%;
+ --primary-foreground: 222.2 84% 4.9%;
+
+ --secondary: 217.2 32.6% 17.5%;
+ --secondary-foreground: 210 40% 98%;
+
+ --muted: 217.2 32.6% 17.5%;
+ --muted-foreground: 215 20.2% 65.1%;
+
+ --accent: 217.2 32.6% 17.5%;
+ --accent-foreground: 210 40% 98%;
+
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 210 40% 98%;
+
+ --border: 217.2 32.6% 17.5%;
+ --input: 217.2 32.6% 17.5%;
+ --ring: 212.7 26.8% 83.9%;
+
+ /* Semantic colors for dark theme */
+ --success: 142.1 70.6% 45.3%;
+ --success-foreground: 144.9 80.4% 10%;
+
+ --warning: 32.5 94.6% 43.7%;
+ --warning-foreground: 26 83.3% 14.1%;
+
+ --info: 217.2 91.2% 59.8%;
+ --info-foreground: 222.2 84% 4.9%;
+
+ /* Dark theme shadows */
+ --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
+ --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.4), 0 1px 2px -1px rgb(0 0 0 / 0.3);
+ --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.4), 0 2px 4px -2px rgb(0 0 0 / 0.3);
+ --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.4), 0 4px 6px -4px rgb(0 0 0 / 0.3);
+ --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.4), 0 8px 10px -6px rgb(0 0 0 / 0.3);
+ }
+
+ /* Global base styles */
+ * {
+ @apply border-border;
+ }
+
+ body {
+ @apply bg-background text-foreground;
+ font-feature-settings: "rlig" 1, "calt" 1;
+ }
+
+ /* Smooth theme transitions */
+ html {
+ transition: color-scheme 0.2s ease-in-out;
+ }
+
+ * {
+ transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, color 0.2s ease-in-out;
+ }
+
+ /* Focus styles */
+ .focus-visible {
+ @apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2;
+ }
+}
+
+/* Custom scrollbar for dark mode */
+@layer utilities {
+ .scrollbar-thin {
+ scrollbar-width: thin;
+ }
+
+ .scrollbar-track-transparent {
+ scrollbar-color: hsl(var(--muted)) transparent;
+ }
+
+ .dark .scrollbar-track-transparent {
+ scrollbar-color: hsl(var(--muted)) transparent;
+ }
+}
+```
+
+## Theme Management
+
+### JavaScript Theme Controller
+
+```javascript
+// lib/theme.js
+class ThemeManager {
+ constructor() {
+ this.theme = 'system'
+ this.systemTheme = 'light'
+ this.init()
+ }
+
+ init() {
+ // Get stored theme or default to system
+ this.theme = localStorage.getItem('theme') || 'system'
+
+ // Listen for system theme changes
+ this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
+ this.systemTheme = this.mediaQuery.matches ? 'dark' : 'light'
+
+ this.mediaQuery.addEventListener('change', (e) => {
+ this.systemTheme = e.matches ? 'dark' : 'light'
+ if (this.theme === 'system') {
+ this.applyTheme()
+ }
+ })
+
+ // Apply initial theme
+ this.applyTheme()
+ }
+
+ setTheme(theme) {
+ this.theme = theme
+ localStorage.setItem('theme', theme)
+ this.applyTheme()
+ this.notifyListeners()
+ }
+
+ applyTheme() {
+ const root = document.documentElement
+ const isDark = this.theme === 'dark' || (this.theme === 'system' && this.systemTheme === 'dark')
+
+ if (isDark) {
+ root.classList.add('dark')
+ root.style.colorScheme = 'dark'
+ } else {
+ root.classList.remove('dark')
+ root.style.colorScheme = 'light'
+ }
+ }
+
+ getTheme() {
+ return this.theme
+ }
+
+ getEffectiveTheme() {
+ return this.theme === 'system' ? this.systemTheme : this.theme
+ }
+
+ // Event listener system
+ listeners = new Set()
+
+ subscribe(callback) {
+ this.listeners.add(callback)
+ return () => this.listeners.delete(callback)
+ }
+
+ notifyListeners() {
+ this.listeners.forEach(callback => {
+ callback({
+ theme: this.theme,
+ effectiveTheme: this.getEffectiveTheme()
+ })
+ })
+ }
+}
+
+// Create global instance
+const themeManager = new ThemeManager()
+
+export { themeManager }
+```
+
+### React Theme Hook
+
+```jsx
+// hooks/useTheme.js
+import { useState, useEffect } from 'react'
+import { themeManager } from '@/lib/theme'
+
+export function useTheme() {
+ const [theme, setThemeState] = useState(themeManager.getTheme())
+ const [effectiveTheme, setEffectiveTheme] = useState(themeManager.getEffectiveTheme())
+
+ useEffect(() => {
+ const unsubscribe = themeManager.subscribe(({ theme, effectiveTheme }) => {
+ setThemeState(theme)
+ setEffectiveTheme(effectiveTheme)
+ })
+
+ return unsubscribe
+ }, [])
+
+ const setTheme = (newTheme) => {
+ themeManager.setTheme(newTheme)
+ }
+
+ return {
+ theme,
+ effectiveTheme,
+ setTheme,
+ themes: ['light', 'dark', 'system']
+ }
+}
+```
+
+### React Theme Provider
+
+```jsx
+// providers/ThemeProvider.jsx
+import React, { createContext, useContext, useEffect, useState } from 'react'
+
+const ThemeProviderContext = createContext({
+ theme: 'system',
+ setTheme: () => null,
+})
+
+export function ThemeProvider({ children, defaultTheme = 'system' }) {
+ const [theme, setTheme] = useState(() => {
+ if (typeof window !== 'undefined') {
+ return localStorage.getItem('theme') || defaultTheme
+ }
+ return defaultTheme
+ })
+
+ 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) => {
+ localStorage.setItem('theme', theme)
+ setTheme(theme)
+ },
+ }
+
+ return (
+
+ {children}
+
+ )
+}
+
+export const useTheme = () => {
+ const context = useContext(ThemeProviderContext)
+
+ if (context === undefined)
+ throw new Error('useTheme must be used within a ThemeProvider')
+
+ return context
+}
+```
+
+## Theme Toggle Components
+
+### Simple Theme Toggle
+
+```jsx
+// components/ThemeToggle.jsx
+import React from 'react'
+import { Moon, Sun } from 'lucide-react'
+import { useTheme } from '@/hooks/useTheme'
+import { Button } from '@/components/ui/Button'
+
+export function ThemeToggle() {
+ const { effectiveTheme, setTheme } = useTheme()
+
+ const toggleTheme = () => {
+ setTheme(effectiveTheme === 'light' ? 'dark' : 'light')
+ }
+
+ return (
+
+
+
+
+ )
+}
+```
+
+### Advanced Theme Selector
+
+```jsx
+// components/ThemeSelector.jsx
+import React from 'react'
+import { Monitor, Moon, Sun } from 'lucide-react'
+import { useTheme } from '@/hooks/useTheme'
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from '@/components/ui/DropdownMenu'
+import { Button } from '@/components/ui/Button'
+
+export function ThemeSelector() {
+ const { theme, setTheme } = useTheme()
+
+ const themes = [
+ { value: 'light', label: 'Light', icon: Sun },
+ { value: 'dark', label: 'Dark', icon: Moon },
+ { value: 'system', label: 'System', icon: Monitor },
+ ]
+
+ const currentTheme = themes.find(t => t.value === theme)
+
+ return (
+
+
+
+
+ {currentTheme.label}
+
+
+
+
+ {themes.map(({ value, label, icon: Icon }) => (
+ setTheme(value)}
+ className="cursor-pointer"
+ >
+
+ {label}
+ {theme === value && (
+ ✓
+ )}
+
+ ))}
+
+
+ )
+}
+```
+
+### Animated Theme Toggle
+
+```jsx
+// components/AnimatedThemeToggle.jsx
+import React from 'react'
+import { useTheme } from '@/hooks/useTheme'
+import { cn } from '@/lib/utils'
+
+export function AnimatedThemeToggle() {
+ const { effectiveTheme, setTheme } = useTheme()
+ const isDark = effectiveTheme === 'dark'
+
+ const toggleTheme = () => {
+ setTheme(isDark ? 'light' : 'dark')
+ }
+
+ return (
+
+
+ {/* Sun icon */}
+
+
+
+
+ {/* Moon icon */}
+
+
+
+
+
+ )
+}
+```
+
+## Theme-Aware Components
+
+### Dark Mode Image Component
+
+```jsx
+// components/ThemeAwareImage.jsx
+import React from 'react'
+import { useTheme } from '@/hooks/useTheme'
+
+export function ThemeAwareImage({
+ lightSrc,
+ darkSrc,
+ alt,
+ className,
+ ...props
+}) {
+ const { effectiveTheme } = useTheme()
+ const src = effectiveTheme === 'dark' ? darkSrc : lightSrc
+
+ return (
+
+ )
+}
+```
+
+### Theme Detection Script
+
+```html
+
+
+```
+
+## Testing Dark Mode
+
+### Dark Mode Test Suite
+
+```javascript
+// tests/dark-mode.test.js
+import { render, screen, fireEvent } from '@testing-library/react'
+import { ThemeProvider } from '@/providers/ThemeProvider'
+import { ThemeToggle } from '@/components/ThemeToggle'
+
+describe('Dark Mode', () => {
+ beforeEach(() => {
+ localStorage.clear()
+ document.documentElement.className = ''
+ })
+
+ test('applies dark mode class when theme is dark', () => {
+ render(
+
+ Test content
+
+ )
+
+ expect(document.documentElement).toHaveClass('dark')
+ })
+
+ test('toggles theme when button is clicked', () => {
+ render(
+
+
+
+ )
+
+ const toggleButton = screen.getByLabelText(/toggle theme/i)
+ fireEvent.click(toggleButton)
+
+ expect(document.documentElement).toHaveClass('dark')
+ })
+
+ test('persists theme preference', () => {
+ render(
+
+
+
+ )
+
+ const toggleButton = screen.getByLabelText(/toggle theme/i)
+ fireEvent.click(toggleButton)
+
+ expect(localStorage.getItem('theme')).toBe('dark')
+ })
+})
+```
+
+Remember: **Dark mode should enhance user experience with proper contrast ratios, smooth transitions, and respect for user preferences!**
--
cgit v1.2.3