| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- #!/bin/bash
- # Exit on error
- set -e
- # Detect Node version
- NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
- echo "🔍 Detected Node.js version: $NODE_VERSION"
- if [ "$NODE_VERSION" -lt 18 ]; then
- echo "❌ Error: Node.js 18 or higher is required"
- echo " Current version: $(node -v)"
- exit 1
- fi
- # Set Vite version based on Node version
- if [ "$NODE_VERSION" -ge 20 ]; then
- VITE_VERSION="latest"
- echo "✅ Using Vite latest (Node 20+)"
- else
- VITE_VERSION="5.4.11"
- echo "✅ Using Vite $VITE_VERSION (Node 18 compatible)"
- fi
- # Detect OS and set sed syntax
- if [[ "$OSTYPE" == "darwin"* ]]; then
- SED_INPLACE="sed -i ''"
- else
- SED_INPLACE="sed -i"
- fi
- # Check if pnpm is installed
- if ! command -v pnpm &> /dev/null; then
- echo "📦 pnpm not found. Installing pnpm..."
- npm install -g pnpm
- fi
- # Check if project name is provided
- if [ -z "$1" ]; then
- echo "❌ Usage: ./create-react-shadcn-complete.sh <project-name>"
- exit 1
- fi
- PROJECT_NAME="$1"
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
- COMPONENTS_TARBALL="$SCRIPT_DIR/shadcn-components.tar.gz"
- # Check if components tarball exists
- if [ ! -f "$COMPONENTS_TARBALL" ]; then
- echo "❌ Error: shadcn-components.tar.gz not found in script directory"
- echo " Expected location: $COMPONENTS_TARBALL"
- exit 1
- fi
- echo "🚀 Creating new React + Vite project: $PROJECT_NAME"
- # Create new Vite project (always use latest create-vite, pin vite version later)
- pnpm create vite "$PROJECT_NAME" --template react-ts
- # Navigate into project directory
- cd "$PROJECT_NAME"
- echo "🧹 Cleaning up Vite template..."
- $SED_INPLACE '/<link rel="icon".*vite\.svg/d' index.html
- $SED_INPLACE 's/<title>.*<\/title>/<title>'"$PROJECT_NAME"'<\/title>/' index.html
- echo "📦 Installing base dependencies..."
- pnpm install
- # Pin Vite version for Node 18
- if [ "$NODE_VERSION" -lt 20 ]; then
- echo "📌 Pinning Vite to $VITE_VERSION for Node 18 compatibility..."
- pnpm add -D vite@$VITE_VERSION
- fi
- echo "📦 Installing Tailwind CSS and dependencies..."
- pnpm install -D tailwindcss@3.4.1 postcss autoprefixer @types/node tailwindcss-animate
- pnpm install class-variance-authority clsx tailwind-merge lucide-react next-themes
- echo "⚙️ Creating Tailwind and PostCSS configuration..."
- cat > postcss.config.js << 'EOF'
- export default {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
- }
- EOF
- echo "📝 Configuring Tailwind with shadcn theme..."
- cat > tailwind.config.js << 'EOF'
- /** @type {import('tailwindcss').Config} */
- module.exports = {
- darkMode: ["class"],
- content: [
- "./index.html",
- "./src/**/*.{js,ts,jsx,tsx}",
- ],
- theme: {
- extend: {
- colors: {
- border: "hsl(var(--border))",
- input: "hsl(var(--input))",
- ring: "hsl(var(--ring))",
- background: "hsl(var(--background))",
- foreground: "hsl(var(--foreground))",
- primary: {
- DEFAULT: "hsl(var(--primary))",
- foreground: "hsl(var(--primary-foreground))",
- },
- secondary: {
- DEFAULT: "hsl(var(--secondary))",
- foreground: "hsl(var(--secondary-foreground))",
- },
- destructive: {
- DEFAULT: "hsl(var(--destructive))",
- foreground: "hsl(var(--destructive-foreground))",
- },
- muted: {
- DEFAULT: "hsl(var(--muted))",
- foreground: "hsl(var(--muted-foreground))",
- },
- accent: {
- DEFAULT: "hsl(var(--accent))",
- foreground: "hsl(var(--accent-foreground))",
- },
- popover: {
- DEFAULT: "hsl(var(--popover))",
- foreground: "hsl(var(--popover-foreground))",
- },
- card: {
- DEFAULT: "hsl(var(--card))",
- foreground: "hsl(var(--card-foreground))",
- },
- },
- borderRadius: {
- lg: "var(--radius)",
- md: "calc(var(--radius) - 2px)",
- sm: "calc(var(--radius) - 4px)",
- },
- keyframes: {
- "accordion-down": {
- from: { height: "0" },
- to: { height: "var(--radix-accordion-content-height)" },
- },
- "accordion-up": {
- from: { height: "var(--radix-accordion-content-height)" },
- to: { height: "0" },
- },
- },
- animation: {
- "accordion-down": "accordion-down 0.2s ease-out",
- "accordion-up": "accordion-up 0.2s ease-out",
- },
- },
- },
- plugins: [require("tailwindcss-animate")],
- }
- EOF
- # Add Tailwind directives and CSS variables to index.css
- echo "🎨 Adding Tailwind directives and CSS variables..."
- cat > src/index.css << 'EOF'
- @tailwind base;
- @tailwind components;
- @tailwind utilities;
- @layer base {
- :root {
- --background: 0 0% 100%;
- --foreground: 0 0% 3.9%;
- --card: 0 0% 100%;
- --card-foreground: 0 0% 3.9%;
- --popover: 0 0% 100%;
- --popover-foreground: 0 0% 3.9%;
- --primary: 0 0% 9%;
- --primary-foreground: 0 0% 98%;
- --secondary: 0 0% 96.1%;
- --secondary-foreground: 0 0% 9%;
- --muted: 0 0% 96.1%;
- --muted-foreground: 0 0% 45.1%;
- --accent: 0 0% 96.1%;
- --accent-foreground: 0 0% 9%;
- --destructive: 0 84.2% 60.2%;
- --destructive-foreground: 0 0% 98%;
- --border: 0 0% 89.8%;
- --input: 0 0% 89.8%;
- --ring: 0 0% 3.9%;
- --radius: 0.5rem;
- }
- .dark {
- --background: 0 0% 3.9%;
- --foreground: 0 0% 98%;
- --card: 0 0% 3.9%;
- --card-foreground: 0 0% 98%;
- --popover: 0 0% 3.9%;
- --popover-foreground: 0 0% 98%;
- --primary: 0 0% 98%;
- --primary-foreground: 0 0% 9%;
- --secondary: 0 0% 14.9%;
- --secondary-foreground: 0 0% 98%;
- --muted: 0 0% 14.9%;
- --muted-foreground: 0 0% 63.9%;
- --accent: 0 0% 14.9%;
- --accent-foreground: 0 0% 98%;
- --destructive: 0 62.8% 30.6%;
- --destructive-foreground: 0 0% 98%;
- --border: 0 0% 14.9%;
- --input: 0 0% 14.9%;
- --ring: 0 0% 83.1%;
- }
- }
- @layer base {
- * {
- @apply border-border;
- }
- body {
- @apply bg-background text-foreground;
- }
- }
- EOF
- # Add path aliases to tsconfig.json
- echo "🔧 Adding path aliases to tsconfig.json..."
- node -e "
- const fs = require('fs');
- const config = JSON.parse(fs.readFileSync('tsconfig.json', 'utf8'));
- config.compilerOptions = config.compilerOptions || {};
- config.compilerOptions.baseUrl = '.';
- config.compilerOptions.paths = { '@/*': ['./src/*'] };
- fs.writeFileSync('tsconfig.json', JSON.stringify(config, null, 2));
- "
- # Add path aliases to tsconfig.app.json
- echo "🔧 Adding path aliases to tsconfig.app.json..."
- node -e "
- const fs = require('fs');
- const path = 'tsconfig.app.json';
- const content = fs.readFileSync(path, 'utf8');
- // Remove comments manually
- const lines = content.split('\n').filter(line => !line.trim().startsWith('//'));
- const jsonContent = lines.join('\n');
- const config = JSON.parse(jsonContent.replace(/\/\*[\s\S]*?\*\//g, '').replace(/,(\s*[}\]])/g, '\$1'));
- config.compilerOptions = config.compilerOptions || {};
- config.compilerOptions.baseUrl = '.';
- config.compilerOptions.paths = { '@/*': ['./src/*'] };
- fs.writeFileSync(path, JSON.stringify(config, null, 2));
- "
- # Update vite.config.ts
- echo "⚙️ Updating Vite configuration..."
- cat > vite.config.ts << 'EOF'
- import path from "path";
- import react from "@vitejs/plugin-react";
- import { defineConfig } from "vite";
- export default defineConfig({
- plugins: [react()],
- resolve: {
- alias: {
- "@": path.resolve(__dirname, "./src"),
- },
- },
- });
- EOF
- # Install all shadcn/ui dependencies
- echo "📦 Installing shadcn/ui dependencies..."
- pnpm install @radix-ui/react-accordion @radix-ui/react-aspect-ratio @radix-ui/react-avatar @radix-ui/react-checkbox @radix-ui/react-collapsible @radix-ui/react-context-menu @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-hover-card @radix-ui/react-label @radix-ui/react-menubar @radix-ui/react-navigation-menu @radix-ui/react-popover @radix-ui/react-progress @radix-ui/react-radio-group @radix-ui/react-scroll-area @radix-ui/react-select @radix-ui/react-separator @radix-ui/react-slider @radix-ui/react-slot @radix-ui/react-switch @radix-ui/react-tabs @radix-ui/react-toast @radix-ui/react-toggle @radix-ui/react-toggle-group @radix-ui/react-tooltip
- pnpm install sonner cmdk vaul embla-carousel-react react-day-picker react-resizable-panels date-fns react-hook-form @hookform/resolvers zod
- # Extract shadcn components from tarball
- echo "📦 Extracting shadcn/ui components..."
- tar -xzf "$COMPONENTS_TARBALL" -C src/
- # Create components.json for reference
- echo "📝 Creating components.json config..."
- cat > components.json << 'EOF'
- {
- "$schema": "https://ui.shadcn.com/schema.json",
- "style": "default",
- "rsc": false,
- "tsx": true,
- "tailwind": {
- "config": "tailwind.config.js",
- "css": "src/index.css",
- "baseColor": "slate",
- "cssVariables": true,
- "prefix": ""
- },
- "aliases": {
- "components": "@/components",
- "utils": "@/lib/utils",
- "ui": "@/components/ui",
- "lib": "@/lib",
- "hooks": "@/hooks"
- }
- }
- EOF
- echo "✅ Setup complete! You can now use Tailwind CSS and shadcn/ui in your project."
- echo ""
- echo "📦 Included components (40+ total):"
- echo " - accordion, alert, aspect-ratio, avatar, badge, breadcrumb"
- echo " - button, calendar, card, carousel, checkbox, collapsible"
- echo " - command, context-menu, dialog, drawer, dropdown-menu"
- echo " - form, hover-card, input, label, menubar, navigation-menu"
- echo " - popover, progress, radio-group, resizable, scroll-area"
- echo " - select, separator, sheet, skeleton, slider, sonner"
- echo " - switch, table, tabs, textarea, toast, toggle, toggle-group, tooltip"
- echo ""
- echo "To start developing:"
- echo " cd $PROJECT_NAME"
- echo " pnpm dev"
- echo ""
- echo "📚 Import components like:"
- echo " import { Button } from '@/components/ui/button'"
- echo " import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'"
- echo " import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog'"
|