commit 735ed8d1d722d43906bfdda102e42e60898a4dd1 Author: Zhongwei Li Date: Sat Nov 29 18:22:33 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..afae8d7 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,14 @@ +{ + "name": "tailwind-4", + "description": "Tailwind CSS v4 patterns: CSS-first config, oklch colors, container queries, @utility directive", + "version": "1.0.0", + "author": { + "name": "Design Session with Claude Code" + }, + "skills": [ + "./skills" + ], + "hooks": [ + "./hooks" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f002b6a --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# tailwind-4 + +Tailwind CSS v4 patterns: CSS-first config, oklch colors, container queries, @utility directive diff --git a/hooks/hooks.json b/hooks/hooks.json new file mode 100644 index 0000000..2971f09 --- /dev/null +++ b/hooks/hooks.json @@ -0,0 +1,53 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/init-session.sh", + "timeout": 1000, + "description": "Initialize session state for skill recommendations" + } + ] + } + ], + "PreToolUse": [ + { + "matcher": "Read|Write|Edit", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/recommend-skills.sh", + "timeout": 1000, + "description": "Recommend relevant Tailwind v4 skills based on file patterns" + } + ] + }, + { + "matcher": "Write", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-config.sh", + "timeout": 1000, + "description": "Block deprecated tailwind.config.js files in Tailwind v4" + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "Write|Edit", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-tailwind-v4.sh", + "timeout": 5000, + "description": "Validate Tailwind v4 patterns and suggest fixes" + } + ] + } + ] + } +} diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..93eab85 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,105 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:djankies/claude-configs:tailwind-4", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "a18d0811809f9a00e5fae6a690f1553fa0797c12", + "treeHash": "419af0c5882d739b7013b72a661c8eaa04711332393cec717af929d0415fa41e", + "generatedAt": "2025-11-28T10:16:30.280280Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "tailwind-4", + "description": "Tailwind CSS v4 patterns: CSS-first config, oklch colors, container queries, @utility directive", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "42897bffbfaaa4c3744b9f69c419a63cc9104cbe8fb51f60b722d54693a7cab8" + }, + { + "path": "hooks/hooks.json", + "sha256": "4c256357ff8ec095214f0d311e54557a5af20e572cf5e2c7395070bf213d08ee" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "84d2c0695cd1940d7686789c2e894a370968d3981f51f5cd6f458cb056137b1c" + }, + { + "path": "skills/creating-custom-utilities/SKILL.md", + "sha256": "db188b2620c91f8cd8a92a580c42120b96b0e0cbc33146e59d2ab82aee17035a" + }, + { + "path": "skills/configuring-tailwind-v4/SKILL.md", + "sha256": "c069b146429ebe7e68e76b535a8effcdc10ed3a357550049abf0fd71f9fc29ee" + }, + { + "path": "skills/configuring-tailwind-v4/references/nextjs-setup.md", + "sha256": "59755429d76eee68d51c560c640d7a623ed30f9099ba2bc666c94c44764272fd" + }, + { + "path": "skills/configuring-tailwind-v4/references/vite-setup.md", + "sha256": "b31177502b1a96edb7aed256da05fc5bf11b265a314c9cf4d19d739ad51ecbde" + }, + { + "path": "skills/configuring-tailwind-v4/references/postcss-setup.md", + "sha256": "3f847c3161b86d3032b2ee47ad4a5ec498efe4340f6d1ad99b5a363e0cc7a36a" + }, + { + "path": "skills/using-theme-variables/SKILL.md", + "sha256": "7327b3f4d6058aa6d87bad4477d2c5e765311acb61523ab72342f3c84c99b6d7" + }, + { + "path": "skills/using-theme-variables/references/namespace-reference.md", + "sha256": "aa3492dbeccaebc4538cef607f66c7d771b17506220fc65b6a4e31d6d7416022" + }, + { + "path": "skills/using-theme-variables/references/color-conversion.md", + "sha256": "96531fadf4315046a15c72f8b6fa8070c106f8337eef86faeaac636208489729" + }, + { + "path": "skills/reviewing-tailwind-patterns/SKILL.md", + "sha256": "d0c41d56b526381efa56a70a7e705376293ef9d58f7c93340a4d6bb2335329d9" + }, + { + "path": "skills/handling-animations/SKILL.md", + "sha256": "ad5cd945e64c2d56d44d138a5cc03c15a12166d4a9f1fd603c74bdd4ab4520e0" + }, + { + "path": "skills/handling-animations/references/animation-library.md", + "sha256": "905656e759fdfaa31f68476fd9ef0c3ce04385f8fcb22072fd71361013b63614" + }, + { + "path": "skills/migrating-from-v3/SKILL.md", + "sha256": "2bf2744e271aa40308d3da5a674ece7678bb9f73bd0f29890dbeb01b4261b13b" + }, + { + "path": "skills/migrating-from-v3/references/breaking-changes.md", + "sha256": "f454d4a08774a9297cb7761813ba3c8461e8f2a90bae5d7c1d78262c94f555ed" + }, + { + "path": "skills/migrating-from-v3/references/migration-checklist.md", + "sha256": "723ff5da73470dc53739d73fe285139e13592e7e157366900941b9e14774990a" + }, + { + "path": "skills/using-container-queries/SKILL.md", + "sha256": "3bd3d9092809a8c503f80da51f64489e60215c4f63fa6da3d81f271d5e24d58c" + } + ], + "dirSha256": "419af0c5882d739b7013b72a661c8eaa04711332393cec717af929d0415fa41e" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/configuring-tailwind-v4/SKILL.md b/skills/configuring-tailwind-v4/SKILL.md new file mode 100644 index 0000000..173f412 --- /dev/null +++ b/skills/configuring-tailwind-v4/SKILL.md @@ -0,0 +1,172 @@ +--- +name: configuring-tailwind-v4 +description: Configure Tailwind CSS v4 using Vite plugin, PostCSS, or CLI with CSS-first configuration via @import and @theme directives. Use when setting up new projects or migrating build tools. +allowed-tools: Read, Write, Edit, Grep, Glob, Bash +--- + +# Configuring Tailwind v4 + +## Purpose + +Configure Tailwind CSS v4 using modern CSS-first configuration. Tailwind v4 eliminates JavaScript configuration files in favor of CSS-based setup using `@import` and `@theme` directives. + +## Installation Methods + +### Vite Projects (Recommended) + +**Step 1: Install Dependencies** + +```bash +npm install tailwindcss @tailwindcss/vite +``` + +**Step 2: Configure Vite Plugin** + +Add the Tailwind plugin to `vite.config.js`: + +```javascript +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [react(), tailwindcss()], +}); +``` + +**Step 3: Import Tailwind in CSS** + +Create or update your main CSS file (e.g., `src/index.css`): + +```css +@import 'tailwindcss'; +``` + +### PostCSS Projects + +**Step 1: Install Dependencies** + +```bash +npm install tailwindcss @tailwindcss/postcss +``` + +**Step 2: Configure PostCSS** + +Create `postcss.config.js`: + +```javascript +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +**Step 3: Import Tailwind in CSS** + +```css +@import 'tailwindcss'; +``` + +### CLI Usage + +**Step 1: Install CLI** + +```bash +npm install tailwindcss @tailwindcss/cli +``` + +**Step 2: Create Input CSS** + +```css +@import 'tailwindcss'; +``` + +**Step 3: Run Build Command** + +```bash +npx @tailwindcss/cli -i input.css -o output.css --watch +``` + +## CSS-First Configuration + +Tailwind v4 uses the `@theme` directive for all customization: + +```css +@import 'tailwindcss'; + +@theme { + --font-display: 'Satoshi', 'sans-serif'; + --font-body: 'Inter', 'sans-serif'; + + --color-brand-primary: oklch(0.65 0.25 270); + --color-brand-accent: oklch(0.75 0.22 320); + + --breakpoint-3xl: 120rem; + --breakpoint-4xl: 160rem; + + --spacing-18: 4.5rem; + --spacing-72: 18rem; + + --radius-4xl: 2rem; + + --shadow-brutal: 8px 8px 0 0 rgb(0 0 0); +} +``` + +## Automatic Content Detection + +Template files are discovered automatically using built-in heuristics. No content array configuration required. Files in `.gitignore` are automatically excluded. + +**Manual Source Control (when needed):** + +```css +@import 'tailwindcss'; + +@source "../node_modules/@my-company/ui-lib"; +@source "./legacy-components"; +``` + +**Exclude paths:** + +```css +@source not "./legacy"; +@source not "./docs"; +``` + +**Disable automatic detection:** + +```css +@import 'tailwindcss' source(none); +@source "./src"; +``` + +## Key Differences from v3 + +| v3 | v4 | +|---|---| +| `tailwind.config.js` | CSS `@theme` directive | +| `@tailwind base;` | `@import 'tailwindcss';` | +| `content: []` array | Automatic detection | +| `postcss-tailwindcss` | `@tailwindcss/postcss` | + +## Performance + +- Full builds: **3.78x faster** than v3 +- Incremental rebuilds with new CSS: **8.8x faster** +- Incremental rebuilds without new CSS: **182x faster** + +## Browser Requirements + +Tailwind v4 requires: +- Safari 16.4+ +- Chrome 111+ +- Firefox 128+ + +Projects requiring older browser support must stay on v3.4. + +## See Also + +- references/vite-setup.md - Complete Vite configuration examples +- references/postcss-setup.md - PostCSS configuration patterns +- references/nextjs-setup.md - Next.js specific setup diff --git a/skills/configuring-tailwind-v4/references/nextjs-setup.md b/skills/configuring-tailwind-v4/references/nextjs-setup.md new file mode 100644 index 0000000..424b4a0 --- /dev/null +++ b/skills/configuring-tailwind-v4/references/nextjs-setup.md @@ -0,0 +1,373 @@ +# Next.js Setup Guide + +## Next.js 15+ with App Router + +**Install dependencies:** + +```bash +npx create-next-app@latest my-app +cd my-app +npm install tailwindcss @tailwindcss/postcss +``` + +**postcss.config.js:** + +```javascript +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +**app/globals.css:** + +```css +@import 'tailwindcss'; + +@theme { + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + + --color-primary: oklch(0.65 0.25 270); + --color-secondary: oklch(0.75 0.22 320); +} +``` + +**app/layout.tsx:** + +```typescript +import type { Metadata } from 'next'; +import { Geist, Geist_Mono } from 'next/font/google'; +import './globals.css'; + +const geistSans = Geist({ + variable: '--font-geist-sans', + subsets: ['latin'], +}); + +const geistMono = Geist_Mono({ + variable: '--font-geist-mono', + subsets: ['latin'], +}); + +export const metadata: Metadata = { + title: 'My App', + description: 'Built with Next.js and Tailwind CSS v4', +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} +``` + +**app/page.tsx:** + +```typescript +export default function Home() { + return ( +
+

+ Next.js + Tailwind v4 +

+

+ CSS-first configuration with @theme directive +

+
+ ); +} +``` + +## Pages Router Setup + +**pages/_app.tsx:** + +```typescript +import type { AppProps } from 'next/app'; +import '@/styles/globals.css'; + +export default function App({ Component, pageProps }: AppProps) { + return ; +} +``` + +**styles/globals.css:** + +```css +@import 'tailwindcss'; + +@theme { + --color-primary: oklch(0.65 0.25 270); +} +``` + +**pages/index.tsx:** + +```typescript +export default function Home() { + return ( +
+

+ Next.js Pages Router + Tailwind v4 +

+
+ ); +} +``` + +## Dark Mode Setup + +**app/layout.tsx:** + +```typescript +import './globals.css'; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + {children} + + + ); +} +``` + +**Dynamic dark mode with next-themes:** + +```bash +npm install next-themes +``` + +**app/providers.tsx:** + +```typescript +'use client'; + +import { ThemeProvider } from 'next-themes'; + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} +``` + +**app/layout.tsx:** + +```typescript +import { Providers } from './providers'; +import './globals.css'; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + {children} + + + ); +} +``` + +## Component Library Integration + +**Shared theme across apps:** + +**packages/ui/theme.css:** + +```css +@theme { + --*: initial; + + --font-sans: 'Inter', sans-serif; + --font-mono: 'JetBrains Mono', monospace; + + --color-primary: oklch(0.65 0.25 270); + --color-secondary: oklch(0.75 0.22 320); + --color-success: oklch(0.72 0.15 142); + --color-warning: oklch(0.78 0.18 60); + --color-error: oklch(0.65 0.22 25); +} +``` + +**apps/web/app/globals.css:** + +```css +@import 'tailwindcss'; +@import '@my-company/ui/theme.css'; +``` + +**postcss.config.js:** + +```javascript +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +## TypeScript Component Example + +**components/Button.tsx:** + +```typescript +import { ButtonHTMLAttributes, forwardRef } from 'react'; + +interface ButtonProps extends ButtonHTMLAttributes { + variant?: 'primary' | 'secondary' | 'outline'; + size?: 'sm' | 'md' | 'lg'; +} + +const Button = forwardRef( + ({ variant = 'primary', size = 'md', className = '', children, ...props }, ref) => { + const baseStyles = 'rounded-lg font-medium transition-colors'; + + const variantStyles = { + primary: 'bg-primary text-white hover:opacity-90', + secondary: 'bg-secondary text-white hover:opacity-90', + outline: 'border-2 border-primary text-primary hover:bg-primary hover:text-white', + }; + + const sizeStyles = { + sm: 'px-3 py-1.5 text-sm', + md: 'px-4 py-2 text-base', + lg: 'px-6 py-3 text-lg', + }; + + return ( + + ); + } +); + +Button.displayName = 'Button'; + +export default Button; +``` + +## Server Components with Tailwind + +**app/components/Card.tsx:** + +```typescript +interface CardProps { + title: string; + description: string; + children?: React.ReactNode; +} + +export default function Card({ title, description, children }: CardProps) { + return ( +
+

+ {title} +

+

+ {description} +

+ {children &&
{children}
} +
+ ); +} +``` + +## Environment-Specific Styling + +**app/globals.css:** + +```css +@import 'tailwindcss'; + +@theme { + --color-primary: oklch(0.65 0.25 270); +} + +@layer base { + body { + @apply antialiased; + } +} +``` + +## Performance Optimization + +**next.config.js:** + +```javascript +const nextConfig = { + experimental: { + optimizeCss: true, + }, +}; + +export default nextConfig; +``` + +**Production build:** + +```bash +NODE_ENV=production npm run build +``` + +## Deployment + +**Vercel:** + +No additional configuration needed. Vercel automatically detects PostCSS config. + +**Self-hosted:** + +```bash +npm run build +npm start +``` + +**Docker:** + +```dockerfile +FROM node:20-alpine AS builder + +WORKDIR /app +COPY package*.json ./ +RUN npm ci +COPY . . +RUN npm run build + +FROM node:20-alpine AS runner +WORKDIR /app +COPY --from=builder /app/.next ./.next +COPY --from=builder /app/public ./public +COPY --from=builder /app/package*.json ./ +RUN npm ci --production + +EXPOSE 3000 +CMD ["npm", "start"] +``` diff --git a/skills/configuring-tailwind-v4/references/postcss-setup.md b/skills/configuring-tailwind-v4/references/postcss-setup.md new file mode 100644 index 0000000..369c412 --- /dev/null +++ b/skills/configuring-tailwind-v4/references/postcss-setup.md @@ -0,0 +1,307 @@ +# PostCSS Setup Examples + +## Basic PostCSS Configuration + +**Install dependencies:** + +```bash +npm install tailwindcss @tailwindcss/postcss +``` + +**postcss.config.js:** + +```javascript +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +**input.css:** + +```css +@import 'tailwindcss'; + +@theme { + --color-primary: oklch(0.65 0.25 270); +} +``` + +## CommonJS Format + +**postcss.config.cjs:** + +```javascript +module.exports = { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +## Next.js Integration + +**Install dependencies:** + +```bash +npm install tailwindcss @tailwindcss/postcss +``` + +**postcss.config.js:** + +```javascript +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +**app/globals.css or styles/globals.css:** + +```css +@import 'tailwindcss'; + +@theme { + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); + --color-primary: oklch(0.65 0.25 270); +} +``` + +**app/layout.tsx:** + +```typescript +import './globals.css'; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} +``` + +## Webpack Integration + +**webpack.config.js:** + +```javascript +module.exports = { + module: { + rules: [ + { + test: /\.css$/, + use: [ + 'style-loader', + 'css-loader', + { + loader: 'postcss-loader', + options: { + postcssOptions: { + plugins: { + '@tailwindcss/postcss': {}, + }, + }, + }, + }, + ], + }, + ], + }, +}; +``` + +## Custom PostCSS Plugins + +**Note:** Tailwind v4 replaces the need for `postcss-import` and `autoprefixer`. + +**postcss.config.js:** + +```javascript +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +## Build Scripts + +**package.json:** + +```json +{ + "scripts": { + "dev": "postcss src/input.css -o dist/output.css --watch", + "build": "NODE_ENV=production postcss src/input.css -o dist/output.css" + } +} +``` + +## Angular Integration + +**Install dependencies:** + +```bash +npm install tailwindcss @tailwindcss/postcss +``` + +**Create postcss.config.js:** + +```javascript +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +**angular.json:** + +```json +{ + "projects": { + "my-app": { + "architect": { + "build": { + "options": { + "postcssConfig": "postcss.config.js", + "styles": ["src/styles.css"] + } + } + } + } + } +} +``` + +**src/styles.css:** + +```css +@import 'tailwindcss'; + +@theme { + --color-primary: oklch(0.65 0.25 270); +} +``` + +## Nuxt 3 Integration + +**Install dependencies:** + +```bash +npm install tailwindcss @tailwindcss/postcss +``` + +**nuxt.config.ts:** + +```typescript +export default defineNuxtConfig({ + postcss: { + plugins: { + '@tailwindcss/postcss': {}, + }, + }, +}); +``` + +**assets/css/main.css:** + +```css +@import 'tailwindcss'; + +@theme { + --color-primary: oklch(0.65 0.25 270); +} +``` + +**app.vue:** + +```vue + + + +``` + +## Gatsby Integration + +**Install dependencies:** + +```bash +npm install tailwindcss @tailwindcss/postcss gatsby-plugin-postcss +``` + +**gatsby-config.js:** + +```javascript +module.exports = { + plugins: ['gatsby-plugin-postcss'], +}; +``` + +**postcss.config.js:** + +```javascript +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +**src/styles/global.css:** + +```css +@import 'tailwindcss'; + +@theme { + --color-primary: oklch(0.65 0.25 270); +} +``` + +**gatsby-browser.js:** + +```javascript +import './src/styles/global.css'; +``` + +## Common Issues + +**Module parse failed: Unexpected character '@'** + +Ensure PostCSS is configured correctly and using `@tailwindcss/postcss`: + +```javascript +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; +``` + +**Styles not applying** + +Check that: +1. CSS import is present: `@import "tailwindcss";` +2. PostCSS config uses correct plugin +3. Template files aren't in `.gitignore` +4. Class names are complete strings + +**Production builds missing styles** + +Set `NODE_ENV=production`: + +```bash +NODE_ENV=production npm run build +``` diff --git a/skills/configuring-tailwind-v4/references/vite-setup.md b/skills/configuring-tailwind-v4/references/vite-setup.md new file mode 100644 index 0000000..af7c1d0 --- /dev/null +++ b/skills/configuring-tailwind-v4/references/vite-setup.md @@ -0,0 +1,212 @@ +# Vite Setup Examples + +## Basic React + Vite Setup + +**Install dependencies:** + +```bash +npm create vite@latest my-app -- --template react +cd my-app +npm install tailwindcss @tailwindcss/vite +``` + +**vite.config.js:** + +```javascript +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [react(), tailwindcss()], +}); +``` + +**src/index.css:** + +```css +@import 'tailwindcss'; + +@theme { + --color-brand: oklch(0.65 0.25 270); + --font-sans: 'Inter', sans-serif; +} +``` + +**src/main.jsx:** + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; +import './index.css'; + +ReactDOM.createRoot(document.getElementById('root')).render( + + + +); +``` + +## Vue + Vite Setup + +**Install dependencies:** + +```bash +npm create vite@latest my-app -- --template vue +cd my-app +npm install tailwindcss @tailwindcss/vite +``` + +**vite.config.js:** + +```javascript +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}); +``` + +**src/style.css:** + +```css +@import 'tailwindcss'; + +@theme { + --color-primary: oklch(0.65 0.25 142); + --font-sans: 'Roboto', sans-serif; +} +``` + +## Svelte + Vite Setup + +**Install dependencies:** + +```bash +npm create vite@latest my-app -- --template svelte +cd my-app +npm install tailwindcss @tailwindcss/vite +``` + +**vite.config.js:** + +```javascript +import { defineConfig } from 'vite'; +import { svelte } from '@sveltejs/vite-plugin-svelte'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}); +``` + +**src/app.css:** + +```css +@import 'tailwindcss'; +``` + +## Multi-Environment Configuration + +**Development with watch mode:** + +```javascript +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig(({ mode }) => ({ + plugins: [ + react(), + tailwindcss({ + watch: mode === 'development', + }), + ], +})); +``` + +## Monorepo Setup + +**Root vite.config.js:** + +```javascript +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [react(), tailwindcss()], + resolve: { + alias: { + '@ui': '/packages/ui/src', + '@shared': '/packages/shared/src', + }, + }, +}); +``` + +**Root CSS with package sources:** + +```css +@import 'tailwindcss'; + +@source "../packages/ui"; +@source "../packages/shared"; + +@theme { + --color-brand: oklch(0.65 0.25 270); +} +``` + +## Custom Build Output + +```javascript +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [react(), tailwindcss()], + build: { + outDir: 'dist', + cssCodeSplit: true, + rollupOptions: { + output: { + assetFileNames: 'assets/[name].[hash][extname]', + }, + }, + }, +}); +``` + +## Performance Optimization + +**Exclude unnecessary directories:** + +```css +@import 'tailwindcss'; + +@source not "./docs"; +@source not "./legacy"; +@source not "./scripts"; +``` + +**Production build:** + +```bash +NODE_ENV=production npm run build +``` + +**Build time monitoring:** + +```bash +time npm run build +``` + +Expected performance: +- Full builds: ~100ms +- Incremental rebuilds: ~5ms +- No-change rebuilds: ~192µs diff --git a/skills/creating-custom-utilities/SKILL.md b/skills/creating-custom-utilities/SKILL.md new file mode 100644 index 0000000..361fc6f --- /dev/null +++ b/skills/creating-custom-utilities/SKILL.md @@ -0,0 +1,423 @@ +--- +name: creating-custom-utilities +description: Create custom utilities with @utility directive supporting static utilities, functional utilities with values, theme-based utilities, and multi-value utilities. Use when extending Tailwind with custom CSS properties or patterns. +allowed-tools: Read, Write, Edit, Grep, Glob +--- + +# Creating Custom Utilities + +## Purpose + +The `@utility` directive creates custom utility classes with full variant support (hover, focus, responsive, etc.). This is the proper way to extend Tailwind v4 with custom utilities. + +## Static Utilities + +Define utilities with fixed values: + +```css +@utility content-auto { + content-visibility: auto; +} + +@utility content-hidden { + content-visibility: hidden; +} + +@utility text-balance { + text-wrap: balance; +} + +@utility text-pretty { + text-wrap: pretty; +} + +@utility bg-glass { + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.2); +} +``` + +**Usage:** + +```html +
+

+
+``` + +Static utilities work with all variants automatically. + +## Functional Utilities with Integer Values + +Create utilities that accept numeric values: + +```css +@utility mt-* { + margin-top: calc(0.25rem * --value(integer)); +} + +@utility truncate-* { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: --value(integer); + overflow: hidden; +} + +@utility text-stroke-* { + -webkit-text-stroke-width: --value(integer) px; +} +``` + +**Usage:** + +```html +
+

+

+``` + +The `--value(integer)` function extracts the numeric value from the class name. + +## Theme-Based Utilities + +Reference theme variables using `--value(--namespace- *)`: + +```css +@theme { + --tab-size-2: 2; + --tab-size-4: 4; + --tab-size-8: 8; + --tab-size-github: 8; +} + +@utility tab-* { + tab-size: --value(--tab-size- *); +} +``` + +**Usage:** + +```html +
...
+
...
+``` + +**Another example:** + +```css +@theme { + --aspect-square: 1 / 1; + --aspect-video: 16 / 9; + --aspect-portrait: 3 / 4; +} + +@utility aspect-* { + aspect-ratio: --value(--aspect- *); +} +``` + +**Usage:** + +```html + +