507 lines
10 KiB
JavaScript
507 lines
10 KiB
JavaScript
/** @type {import('tailwindcss').Config} */
|
||
|
||
// Tailwind default palette names
|
||
const defaultColors = [
|
||
'slate',
|
||
'gray',
|
||
'zinc',
|
||
'neutral',
|
||
'stone',
|
||
'red',
|
||
'orange',
|
||
'amber',
|
||
'yellow',
|
||
'lime',
|
||
'green',
|
||
'emerald',
|
||
'teal',
|
||
'cyan',
|
||
'sky',
|
||
'blue',
|
||
'indigo',
|
||
'violet',
|
||
'purple',
|
||
'fuchsia',
|
||
'pink',
|
||
'rose',
|
||
];
|
||
|
||
// Custom palette extension
|
||
const customColors = ['primary'];
|
||
|
||
// Shade steps
|
||
const colorShades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
|
||
|
||
// Utility prefixes that take color tokens
|
||
const colorPrefixes = [
|
||
'text',
|
||
'bg',
|
||
'border',
|
||
'ring',
|
||
'divide',
|
||
'placeholder',
|
||
'from',
|
||
'via',
|
||
'to',
|
||
'stroke',
|
||
'fill',
|
||
'accent',
|
||
'caret',
|
||
'outline',
|
||
];
|
||
|
||
// Build safelist entries for color utilities
|
||
function generateColorSafelist() {
|
||
const safelist = [];
|
||
const allColors = [...defaultColors, ...customColors];
|
||
|
||
// For each color-related prefix × palette name
|
||
colorPrefixes.forEach(prefix => {
|
||
allColors.forEach(color => {
|
||
// Shade-specific classes (e.g. text-blue-500)
|
||
colorShades.forEach(shade => {
|
||
safelist.push(`${prefix}-${color}-${shade}`);
|
||
});
|
||
// Base color token without shade
|
||
safelist.push(`${prefix}-${color}`);
|
||
});
|
||
});
|
||
|
||
// Special keywords: white, black, transparent, current
|
||
const specialColors = ['white', 'black', 'transparent', 'current'];
|
||
colorPrefixes.forEach(prefix => {
|
||
specialColors.forEach(color => {
|
||
safelist.push(`${prefix}-${color}`);
|
||
});
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default Tailwind spacing scale
|
||
const spacingValues = [
|
||
0,
|
||
0.5,
|
||
1,
|
||
1.5,
|
||
2,
|
||
2.5,
|
||
3,
|
||
3.5,
|
||
4,
|
||
5,
|
||
6,
|
||
7,
|
||
8,
|
||
9,
|
||
10,
|
||
11,
|
||
12,
|
||
14,
|
||
16,
|
||
20,
|
||
24,
|
||
28,
|
||
32,
|
||
36,
|
||
40,
|
||
44,
|
||
48,
|
||
52,
|
||
56,
|
||
60,
|
||
64,
|
||
72,
|
||
80,
|
||
96,
|
||
// Extra spacing keys used in this project
|
||
18,
|
||
88,
|
||
// Keyword spacing tokens
|
||
'px',
|
||
'auto',
|
||
'full',
|
||
'screen',
|
||
];
|
||
|
||
// Padding / margin utility prefixes
|
||
const spacingPrefixes = {
|
||
padding: ['p', 'px', 'py', 'pt', 'pr', 'pb', 'pl'],
|
||
margin: ['m', 'mx', 'my', 'mt', 'mr', 'mb', 'ml'],
|
||
};
|
||
|
||
// Safelist spacing utilities
|
||
function generateSpacingSafelist() {
|
||
const safelist = [];
|
||
const allPrefixes = [...spacingPrefixes.padding, ...spacingPrefixes.margin];
|
||
|
||
// For each prefix × spacing value
|
||
allPrefixes.forEach(prefix => {
|
||
spacingValues.forEach(value => {
|
||
// Numeric spacing (p-3, m-4, fractional keys, …)
|
||
if (typeof value === 'number') {
|
||
// Numeric keys; Tailwind normalizes fractional classes
|
||
safelist.push(`${prefix}-${value}`);
|
||
} else {
|
||
// Keyword spacing (px, auto, full, screen)
|
||
safelist.push(`${prefix}-${value}`);
|
||
}
|
||
});
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default border-width scale
|
||
const borderWidthValues = [0, 1, 2, 4, 8];
|
||
|
||
// Border-width utility prefixes
|
||
const borderWidthPrefixes = [
|
||
'border',
|
||
'border-t',
|
||
'border-r',
|
||
'border-b',
|
||
'border-l',
|
||
'border-x',
|
||
'border-y',
|
||
];
|
||
|
||
// Safelist border-width utilities
|
||
function generateBorderWidthSafelist() {
|
||
const safelist = [];
|
||
|
||
// For each prefix × width value
|
||
borderWidthPrefixes.forEach(prefix => {
|
||
borderWidthValues.forEach(value => {
|
||
// e.g. border-0, border-2, border-4, border-8
|
||
safelist.push(`${prefix}-${value}`);
|
||
});
|
||
});
|
||
|
||
// Plain `border` (default 1px)
|
||
safelist.push('border');
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default border-style keywords
|
||
const borderStyleValues = [
|
||
'solid',
|
||
'dashed',
|
||
'dotted',
|
||
'double',
|
||
'hidden',
|
||
'none',
|
||
];
|
||
|
||
// Safelist border-style utilities
|
||
function generateBorderStyleSafelist() {
|
||
const safelist = [];
|
||
|
||
// border-solid, border-dashed, …
|
||
borderStyleValues.forEach(style => {
|
||
safelist.push(`border-${style}`);
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default font-weight tokens
|
||
const fontWeightValues = [
|
||
'thin', // 100
|
||
'extralight', // 200
|
||
'light', // 300
|
||
'normal', // 400
|
||
'medium', // 500
|
||
'semibold', // 600
|
||
'bold', // 700
|
||
'extrabold', // 800
|
||
'black', // 900
|
||
];
|
||
|
||
// Safelist font-weight utilities
|
||
function generateFontWeightSafelist() {
|
||
const safelist = [];
|
||
|
||
// font-thin, font-light, font-bold, …
|
||
fontWeightValues.forEach(weight => {
|
||
safelist.push(`font-${weight}`);
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default text-size keys
|
||
// Matches Tailwind docs: xs … 9xl
|
||
const fontSizeValues = [
|
||
'xs',
|
||
'sm',
|
||
'base',
|
||
'lg',
|
||
'xl',
|
||
'2xl',
|
||
'3xl',
|
||
'4xl',
|
||
'5xl',
|
||
'6xl',
|
||
'7xl',
|
||
'8xl',
|
||
'9xl',
|
||
];
|
||
|
||
// Safelist text-* size utilities
|
||
function generateFontSizeSafelist() {
|
||
const safelist = [];
|
||
|
||
// text-sm, text-base, text-lg, …
|
||
fontSizeValues.forEach(size => {
|
||
safelist.push(`text-${size}`);
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default line-height keys
|
||
// Matches Tailwind: none … loose, numeric 3–10
|
||
const lineHeightValues = [
|
||
'none',
|
||
'tight',
|
||
'snug',
|
||
'normal',
|
||
'relaxed',
|
||
'loose',
|
||
'3',
|
||
'4',
|
||
'5',
|
||
'6',
|
||
'7',
|
||
'8',
|
||
'9',
|
||
'10',
|
||
];
|
||
|
||
// Safelist leading-* utilities
|
||
function generateLineHeightSafelist() {
|
||
const safelist = [];
|
||
|
||
// leading-none, leading-tight, leading-5, …
|
||
lineHeightValues.forEach(value => {
|
||
safelist.push(`leading-${value}`);
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default letter-spacing tokens
|
||
// Matches Tailwind tracking scale
|
||
const letterSpacingValues = [
|
||
'tighter',
|
||
'tight',
|
||
'normal',
|
||
'wide',
|
||
'wider',
|
||
'widest',
|
||
];
|
||
|
||
// Safelist tracking-* utilities
|
||
function generateLetterSpacingSafelist() {
|
||
const safelist = [];
|
||
|
||
// tracking-tighter, tracking-wide, …
|
||
letterSpacingValues.forEach(value => {
|
||
safelist.push(`tracking-${value}`);
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default text-align keywords
|
||
// Matches Tailwind text-* alignment
|
||
const textAlignValues = ['left', 'center', 'right', 'justify', 'start', 'end'];
|
||
|
||
// Safelist text-align utilities (text-left, …)
|
||
function generateTextAlignSafelist() {
|
||
const safelist = [];
|
||
|
||
// Note: shares `text-` prefix with font sizes in safelist
|
||
textAlignValues.forEach(value => {
|
||
safelist.push(`text-${value}`);
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default opacity percentage steps
|
||
// Matches Tailwind opacity scale
|
||
const opacityValues = [
|
||
0, 5, 10, 20, 25, 30, 40, 50, 60, 70, 75, 80, 90, 95, 100,
|
||
];
|
||
|
||
// Safelist opacity-* utilities
|
||
function generateOpacitySafelist() {
|
||
const safelist = [];
|
||
|
||
// opacity-0, opacity-50, opacity-100, …
|
||
opacityValues.forEach(value => {
|
||
safelist.push(`opacity-${value}`);
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default border-radius keys
|
||
// Matches Tailwind rounded-* scale
|
||
const borderRadiusValues = [
|
||
'none',
|
||
'sm',
|
||
'md',
|
||
'lg',
|
||
'xl',
|
||
'2xl',
|
||
'3xl',
|
||
'full',
|
||
];
|
||
|
||
// rounded-* utility prefixes
|
||
const borderRadiusPrefixes = [
|
||
'rounded',
|
||
'rounded-t',
|
||
'rounded-r',
|
||
'rounded-b',
|
||
'rounded-l',
|
||
'rounded-tl',
|
||
'rounded-tr',
|
||
'rounded-bl',
|
||
'rounded-br',
|
||
];
|
||
|
||
// Safelist rounded utilities
|
||
function generateBorderRadiusSafelist() {
|
||
const safelist = [];
|
||
|
||
// For each rounded prefix × radius token
|
||
borderRadiusPrefixes.forEach(prefix => {
|
||
borderRadiusValues.forEach(value => {
|
||
// rounded-md, rounded-lg, rounded-tl-sm, …
|
||
safelist.push(`${prefix}-${value}`);
|
||
});
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
// Default box-shadow tokens
|
||
// Matches Tailwind shadow-* scale
|
||
const shadowValues = ['sm', 'md', 'lg', 'xl', '2xl', 'inner', 'none'];
|
||
|
||
// Safelist shadow-* utilities
|
||
function generateShadowSafelist() {
|
||
const safelist = [];
|
||
|
||
// shadow-sm, shadow-md, shadow-lg, …
|
||
shadowValues.forEach(value => {
|
||
safelist.push(`shadow-${value}`);
|
||
});
|
||
|
||
return safelist;
|
||
}
|
||
|
||
export default {
|
||
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
||
// Merge every generated utility into safelist so dynamic class names are not purged
|
||
safelist: [
|
||
...generateColorSafelist(),
|
||
...generateSpacingSafelist(),
|
||
...generateBorderWidthSafelist(),
|
||
...generateBorderStyleSafelist(),
|
||
...generateFontWeightSafelist(),
|
||
...generateFontSizeSafelist(),
|
||
...generateLineHeightSafelist(),
|
||
...generateLetterSpacingSafelist(),
|
||
...generateTextAlignSafelist(),
|
||
...generateOpacitySafelist(),
|
||
...generateBorderRadiusSafelist(),
|
||
...generateShadowSafelist(),
|
||
],
|
||
theme: {
|
||
extend: {
|
||
colors: {
|
||
primary: {
|
||
50: '#eff6ff',
|
||
100: '#dbeafe',
|
||
200: '#bfdbfe',
|
||
300: '#93c5fd',
|
||
400: '#60a5fa',
|
||
500: '#3b82f6',
|
||
600: '#2563eb',
|
||
700: '#1d4ed8',
|
||
800: '#1e40af',
|
||
900: '#1e3a8a',
|
||
},
|
||
gray: {
|
||
50: '#f9fafb',
|
||
100: '#f3f4f6',
|
||
200: '#e5e7eb',
|
||
300: '#d1d5db',
|
||
400: '#9ca3af',
|
||
500: '#6b7280',
|
||
600: '#4b5563',
|
||
700: '#374151',
|
||
800: '#1f2937',
|
||
900: '#111827',
|
||
},
|
||
},
|
||
fontFamily: {
|
||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||
mono: ['Fira Code', 'monospace'],
|
||
},
|
||
spacing: {
|
||
18: '4.5rem',
|
||
88: '22rem',
|
||
},
|
||
borderRadius: {
|
||
'4xl': '2rem',
|
||
},
|
||
boxShadow: {
|
||
soft: '0 2px 15px -3px rgba(0, 0, 0, 0.07), 0 10px 20px -2px rgba(0, 0, 0, 0.04)',
|
||
},
|
||
animation: {
|
||
'fade-in': 'fadeIn 0.5s ease-in-out',
|
||
'slide-up': 'slideUp 0.3s ease-out',
|
||
'bounce-slow': 'bounce 2s infinite',
|
||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||
},
|
||
keyframes: {
|
||
fadeIn: {
|
||
'0%': { opacity: '0' },
|
||
'100%': { opacity: '1' },
|
||
},
|
||
slideUp: {
|
||
'0%': { transform: 'translateY(10px)', opacity: '0' },
|
||
'100%': { transform: 'translateY(0)', opacity: '1' },
|
||
},
|
||
'accordion-down': {
|
||
from: { height: '0' },
|
||
to: { height: 'var(--radix-accordion-content-height)' },
|
||
},
|
||
'accordion-up': {
|
||
from: { height: 'var(--radix-accordion-content-height)' },
|
||
to: { height: '0' },
|
||
},
|
||
},
|
||
},
|
||
},
|
||
plugins: [
|
||
function ({ addUtilities }) {
|
||
const newUtilities = {
|
||
'.text-balance': {
|
||
'text-wrap': 'balance',
|
||
},
|
||
};
|
||
addUtilities(newUtilities);
|
||
},
|
||
],
|
||
darkMode: 'class',
|
||
};
|