-
-
Save nicooprat/2753f44875d2894183a8d588d6e411c0 to your computer and use it in GitHub Desktop.
| // Setting variables like this wouldn't be possible because SASS would | |
| // get through this file before Tailwind does (because it's PostCSS) | |
| $--color-primary: theme('colors.blue'); | |
| $--font-serif: theme('fontFamily.serif'); | |
| body { | |
| color: rgba($--color-primary, .5); | |
| font-family: $font-serif; | |
| } | |
| // It can also be useful to customize some plugins using SASS, | |
| // like ElementUI: https://github.com/ElemeFE/element/blob/dev/packages/theme-chalk/src/common/var.scss | |
| $--color-white: theme('colors.white'); | |
| $--color-black: theme('colors.black'); |
| // https://raw.githubusercontent.com/tailwindcss/tailwindcss/master/stubs/defaultConfig.stub.js | |
| module.exports = { | |
| prefix: '', | |
| important: false, | |
| separator: ':', | |
| theme: { | |
| screens: { | |
| sm: '640px', | |
| md: '768px', | |
| lg: '1024px', | |
| xl: '1280px', | |
| }, | |
| colors: { | |
| transparent: 'transparent', | |
| black: '#000', | |
| white: '#fff', | |
| gray: { | |
| 100: '#f7fafc', | |
| 200: '#edf2f7', | |
| 300: '#e2e8f0', | |
| 400: '#cbd5e0', | |
| 500: '#a0aec0', | |
| 600: '#718096', | |
| 700: '#4a5568', | |
| 800: '#2d3748', | |
| 900: '#1a202c', | |
| }, | |
| red: { | |
| 100: '#fff5f5', | |
| 200: '#fed7d7', | |
| 300: '#feb2b2', | |
| 400: '#fc8181', | |
| 500: '#f56565', | |
| 600: '#e53e3e', | |
| 700: '#c53030', | |
| 800: '#9b2c2c', | |
| 900: '#742a2a', | |
| }, | |
| orange: { | |
| 100: '#fffaf0', | |
| 200: '#feebc8', | |
| 300: '#fbd38d', | |
| 400: '#f6ad55', | |
| 500: '#ed8936', | |
| 600: '#dd6b20', | |
| 700: '#c05621', | |
| 800: '#9c4221', | |
| 900: '#7b341e', | |
| }, | |
| yellow: { | |
| 100: '#fffff0', | |
| 200: '#fefcbf', | |
| 300: '#faf089', | |
| 400: '#f6e05e', | |
| 500: '#ecc94b', | |
| 600: '#d69e2e', | |
| 700: '#b7791f', | |
| 800: '#975a16', | |
| 900: '#744210', | |
| }, | |
| green: { | |
| 100: '#f0fff4', | |
| 200: '#c6f6d5', | |
| 300: '#9ae6b4', | |
| 400: '#68d391', | |
| 500: '#48bb78', | |
| 600: '#38a169', | |
| 700: '#2f855a', | |
| 800: '#276749', | |
| 900: '#22543d', | |
| }, | |
| teal: { | |
| 100: '#e6fffa', | |
| 200: '#b2f5ea', | |
| 300: '#81e6d9', | |
| 400: '#4fd1c5', | |
| 500: '#38b2ac', | |
| 600: '#319795', | |
| 700: '#2c7a7b', | |
| 800: '#285e61', | |
| 900: '#234e52', | |
| }, | |
| blue: { | |
| 100: '#ebf8ff', | |
| 200: '#bee3f8', | |
| 300: '#90cdf4', | |
| 400: '#63b3ed', | |
| 500: '#4299e1', | |
| 600: '#3182ce', | |
| 700: '#2b6cb0', | |
| 800: '#2c5282', | |
| 900: '#2a4365', | |
| }, | |
| indigo: { | |
| 100: '#ebf4ff', | |
| 200: '#c3dafe', | |
| 300: '#a3bffa', | |
| 400: '#7f9cf5', | |
| 500: '#667eea', | |
| 600: '#5a67d8', | |
| 700: '#4c51bf', | |
| 800: '#434190', | |
| 900: '#3c366b', | |
| }, | |
| purple: { | |
| 100: '#faf5ff', | |
| 200: '#e9d8fd', | |
| 300: '#d6bcfa', | |
| 400: '#b794f4', | |
| 500: '#9f7aea', | |
| 600: '#805ad5', | |
| 700: '#6b46c1', | |
| 800: '#553c9a', | |
| 900: '#44337a', | |
| }, | |
| pink: { | |
| 100: '#fff5f7', | |
| 200: '#fed7e2', | |
| 300: '#fbb6ce', | |
| 400: '#f687b3', | |
| 500: '#ed64a6', | |
| 600: '#d53f8c', | |
| 700: '#b83280', | |
| 800: '#97266d', | |
| 900: '#702459', | |
| }, | |
| }, | |
| spacing: { | |
| px: '1px', | |
| '0': '0', | |
| '1': '0.25rem', | |
| '2': '0.5rem', | |
| '3': '0.75rem', | |
| '4': '1rem', | |
| '5': '1.25rem', | |
| '6': '1.5rem', | |
| '8': '2rem', | |
| '10': '2.5rem', | |
| '12': '3rem', | |
| '16': '4rem', | |
| '20': '5rem', | |
| '24': '6rem', | |
| '32': '8rem', | |
| '40': '10rem', | |
| '48': '12rem', | |
| '56': '14rem', | |
| '64': '16rem', | |
| }, | |
| backgroundColor: theme => theme('colors'), | |
| backgroundPosition: { | |
| bottom: 'bottom', | |
| center: 'center', | |
| left: 'left', | |
| 'left-bottom': 'left bottom', | |
| 'left-top': 'left top', | |
| right: 'right', | |
| 'right-bottom': 'right bottom', | |
| 'right-top': 'right top', | |
| top: 'top', | |
| }, | |
| backgroundSize: { | |
| auto: 'auto', | |
| cover: 'cover', | |
| contain: 'contain', | |
| }, | |
| borderColor: theme => ({ | |
| ...theme('colors'), | |
| default: theme('colors.gray.300', 'currentColor'), | |
| }), | |
| borderRadius: { | |
| none: '0', | |
| sm: '0.125rem', | |
| default: '0.25rem', | |
| lg: '0.5rem', | |
| full: '9999px', | |
| }, | |
| borderWidth: { | |
| default: '1px', | |
| '0': '0', | |
| '2': '2px', | |
| '4': '4px', | |
| '8': '8px', | |
| }, | |
| boxShadow: { | |
| default: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)', | |
| md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)', | |
| lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)', | |
| xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)', | |
| '2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)', | |
| inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)', | |
| outline: '0 0 0 3px rgba(66, 153, 225, 0.5)', | |
| none: 'none', | |
| }, | |
| container: {}, | |
| cursor: { | |
| auto: 'auto', | |
| default: 'default', | |
| pointer: 'pointer', | |
| wait: 'wait', | |
| text: 'text', | |
| move: 'move', | |
| 'not-allowed': 'not-allowed', | |
| }, | |
| fill: { | |
| current: 'currentColor', | |
| }, | |
| flex: { | |
| '1': '1 1 0%', | |
| auto: '1 1 auto', | |
| initial: '0 1 auto', | |
| none: 'none', | |
| }, | |
| flexGrow: { | |
| '0': '0', | |
| default: '1', | |
| }, | |
| flexShrink: { | |
| '0': '0', | |
| default: '1', | |
| }, | |
| fontFamily: { | |
| sans: [ | |
| '-apple-system', | |
| 'BlinkMacSystemFont', | |
| '"Segoe UI"', | |
| 'Roboto', | |
| '"Helvetica Neue"', | |
| 'Arial', | |
| '"Noto Sans"', | |
| 'sans-serif', | |
| '"Apple Color Emoji"', | |
| '"Segoe UI Emoji"', | |
| '"Segoe UI Symbol"', | |
| '"Noto Color Emoji"', | |
| ], | |
| serif: [ | |
| 'Georgia', | |
| 'Cambria', | |
| '"Times New Roman"', | |
| 'Times', | |
| 'serif', | |
| ], | |
| mono: [ | |
| 'Menlo', | |
| 'Monaco', | |
| 'Consolas', | |
| '"Liberation Mono"', | |
| '"Courier New"', | |
| 'monospace', | |
| ], | |
| }, | |
| fontSize: { | |
| xs: '0.75rem', | |
| sm: '0.875rem', | |
| base: '1rem', | |
| lg: '1.125rem', | |
| xl: '1.25rem', | |
| '2xl': '1.5rem', | |
| '3xl': '1.875rem', | |
| '4xl': '2.25rem', | |
| '5xl': '3rem', | |
| '6xl': '4rem', | |
| }, | |
| fontWeight: { | |
| hairline: '100', | |
| thin: '200', | |
| light: '300', | |
| normal: '400', | |
| medium: '500', | |
| semibold: '600', | |
| bold: '700', | |
| extrabold: '800', | |
| black: '900', | |
| }, | |
| height: theme => ({ | |
| auto: 'auto', | |
| ...theme('spacing'), | |
| full: '100%', | |
| screen: '100vh', | |
| }), | |
| inset: { | |
| '0': '0', | |
| auto: 'auto', | |
| }, | |
| letterSpacing: { | |
| tighter: '-0.05em', | |
| tight: '-0.025em', | |
| normal: '0', | |
| wide: '0.025em', | |
| wider: '0.05em', | |
| widest: '0.1em', | |
| }, | |
| lineHeight: { | |
| none: '1', | |
| tight: '1.25', | |
| snug: '1.375', | |
| normal: '1.5', | |
| relaxed: '1.625', | |
| loose: '2', | |
| }, | |
| listStyleType: { | |
| none: 'none', | |
| disc: 'disc', | |
| decimal: 'decimal', | |
| }, | |
| margin: (theme, { negative }) => ({ | |
| auto: 'auto', | |
| ...theme('spacing'), | |
| ...negative(theme('spacing')), | |
| }), | |
| maxHeight: { | |
| full: '100%', | |
| screen: '100vh', | |
| }, | |
| maxWidth: { | |
| xs: '20rem', | |
| sm: '24rem', | |
| md: '28rem', | |
| lg: '32rem', | |
| xl: '36rem', | |
| '2xl': '42rem', | |
| '3xl': '48rem', | |
| '4xl': '56rem', | |
| '5xl': '64rem', | |
| '6xl': '72rem', | |
| full: '100%', | |
| }, | |
| minHeight: { | |
| '0': '0', | |
| full: '100%', | |
| screen: '100vh', | |
| }, | |
| minWidth: { | |
| '0': '0', | |
| full: '100%', | |
| }, | |
| objectPosition: { | |
| bottom: 'bottom', | |
| center: 'center', | |
| left: 'left', | |
| 'left-bottom': 'left bottom', | |
| 'left-top': 'left top', | |
| right: 'right', | |
| 'right-bottom': 'right bottom', | |
| 'right-top': 'right top', | |
| top: 'top', | |
| }, | |
| opacity: { | |
| '0': '0', | |
| '25': '0.25', | |
| '50': '0.5', | |
| '75': '0.75', | |
| '100': '1', | |
| }, | |
| order: { | |
| first: '-9999', | |
| last: '9999', | |
| none: '0', | |
| '1': '1', | |
| '2': '2', | |
| '3': '3', | |
| '4': '4', | |
| '5': '5', | |
| '6': '6', | |
| '7': '7', | |
| '8': '8', | |
| '9': '9', | |
| '10': '10', | |
| '11': '11', | |
| '12': '12', | |
| }, | |
| padding: theme => theme('spacing'), | |
| stroke: { | |
| current: 'currentColor', | |
| }, | |
| textColor: theme => theme('colors'), | |
| width: theme => ({ | |
| auto: 'auto', | |
| ...theme('spacing'), | |
| '1/2': '50%', | |
| '1/3': '33.33333%', | |
| '2/3': '66.66667%', | |
| '1/4': '25%', | |
| '2/4': '50%', | |
| '3/4': '75%', | |
| '1/5': '20%', | |
| '2/5': '40%', | |
| '3/5': '60%', | |
| '4/5': '80%', | |
| '1/6': '16.66667%', | |
| '2/6': '33.33333%', | |
| '3/6': '50%', | |
| '4/6': '66.66667%', | |
| '5/6': '83.33333%', | |
| '1/12': '8.33333%', | |
| '2/12': '16.66667%', | |
| '3/12': '25%', | |
| '4/12': '33.33333%', | |
| '5/12': '41.66667%', | |
| '6/12': '50%', | |
| '7/12': '58.33333%', | |
| '8/12': '66.66667%', | |
| '9/12': '75%', | |
| '10/12': '83.33333%', | |
| '11/12': '91.66667%', | |
| full: '100%', | |
| screen: '100vw', | |
| }), | |
| zIndex: { | |
| auto: 'auto', | |
| '0': '0', | |
| '10': '10', | |
| '20': '20', | |
| '30': '30', | |
| '40': '40', | |
| '50': '50', | |
| }, | |
| }, | |
| variants: { | |
| alignContent: ['responsive'], | |
| alignItems: ['responsive'], | |
| alignSelf: ['responsive'], | |
| appearance: ['responsive'], | |
| backgroundAttachment: ['responsive'], | |
| backgroundColor: ['responsive', 'hover', 'focus'], | |
| backgroundPosition: ['responsive'], | |
| backgroundRepeat: ['responsive'], | |
| backgroundSize: ['responsive'], | |
| borderCollapse: ['responsive'], | |
| borderColor: ['responsive', 'hover', 'focus'], | |
| borderRadius: ['responsive'], | |
| borderStyle: ['responsive'], | |
| borderWidth: ['responsive'], | |
| boxShadow: ['responsive', 'hover', 'focus'], | |
| cursor: ['responsive'], | |
| display: ['responsive'], | |
| fill: ['responsive'], | |
| flex: ['responsive'], | |
| flexDirection: ['responsive'], | |
| flexGrow: ['responsive'], | |
| flexShrink: ['responsive'], | |
| flexWrap: ['responsive'], | |
| float: ['responsive'], | |
| fontFamily: ['responsive'], | |
| fontSize: ['responsive'], | |
| fontSmoothing: ['responsive'], | |
| fontStyle: ['responsive'], | |
| fontWeight: ['responsive', 'hover', 'focus'], | |
| height: ['responsive'], | |
| inset: ['responsive'], | |
| justifyContent: ['responsive'], | |
| letterSpacing: ['responsive'], | |
| lineHeight: ['responsive'], | |
| listStylePosition: ['responsive'], | |
| listStyleType: ['responsive'], | |
| margin: ['responsive'], | |
| maxHeight: ['responsive'], | |
| maxWidth: ['responsive'], | |
| minHeight: ['responsive'], | |
| minWidth: ['responsive'], | |
| objectFit: ['responsive'], | |
| objectPosition: ['responsive'], | |
| opacity: ['responsive'], | |
| order: ['responsive'], | |
| outline: ['responsive', 'focus'], | |
| overflow: ['responsive'], | |
| padding: ['responsive'], | |
| pointerEvents: ['responsive'], | |
| position: ['responsive'], | |
| resize: ['responsive'], | |
| stroke: ['responsive'], | |
| tableLayout: ['responsive'], | |
| textAlign: ['responsive'], | |
| textColor: ['responsive', 'hover', 'focus'], | |
| textDecoration: ['responsive', 'hover', 'focus'], | |
| textTransform: ['responsive'], | |
| userSelect: ['responsive'], | |
| verticalAlign: ['responsive'], | |
| visibility: ['responsive'], | |
| whitespace: ['responsive'], | |
| width: ['responsive'], | |
| wordBreak: ['responsive'], | |
| zIndex: ['responsive'], | |
| }, | |
| corePlugins: {}, | |
| plugins: [], | |
| } |
| const sass = require('node-sass'); | |
| const sassUtils = require('node-sass-utils')(sass); | |
| const { theme } = require('./tailwind.config.js'); | |
| const hexToRGBA = (hex) => { | |
| if (!/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) { | |
| return null; | |
| } | |
| let hexColor = hex.substring(1).split(''); | |
| if (hexColor.length === 3) { | |
| hexColor = [hexColor[0], hexColor[0], hexColor[1], hexColor[1], hexColor[2], hexColor[2]]; | |
| } | |
| return Number(`0xff${hexColor.join('')}`); | |
| }; | |
| const convertStringToSassDimension = (result) => { | |
| // Only attempt to convert strings | |
| if (sassUtils.typeOf(result) !== 'string') { | |
| return result; | |
| } | |
| const cssUnits = ['rem', 'em', 'vh', 'vw', 'vmin', 'vmax', 'ex', '%', 'px', 'cm', 'mm', 'in', 'pt', 'pc', 'ch']; | |
| const value = result.match(/[.0-9]+/g); | |
| const unit = result.match(/[a-zA-Z%]+/g); | |
| // If the string has a unit | |
| if (cssUnits.indexOf(unit) !== -1) { | |
| return new sassUtils.SassDimension(parseInt(value, 10), unit); | |
| } | |
| // Else if the string is a hex color string, make sure we return a sass color | |
| // to avoid errors when using darken, lighten, etc. | |
| if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(result)) { | |
| const rgba = hexToRGBA(result); | |
| return sass.types.Color(rgba); | |
| } | |
| return result; | |
| }; | |
| // sass-loader function to return specific theme item | |
| const getConfigItem = (keys) => { | |
| const itemValue = keys | |
| ? keys.getValue().split('.').reduce((object, item) => object[item] || {}, theme) | |
| : theme; | |
| let returnValue; | |
| if (itemValue) { | |
| if (sassUtils.typeOf(itemValue) === 'string') { | |
| returnValue = convertStringToSassDimension(itemValue); | |
| } else if (sassUtils.typeOf(itemValue) === 'array') { | |
| returnValue = convertStringToSassDimension(itemValue.join(', ')); | |
| } else if (sassUtils.typeOf(itemValue) === 'object') { | |
| returnValue = Object.keys(itemValue).reduce((object, item) => { | |
| let itemKeys = `${keys ? `${sassUtils.castToJs(keys)}.` : ''}${item}`; | |
| itemKeys = sassUtils.castToSass(itemKeys); | |
| return { | |
| ...object, | |
| [item]: getConfigItem(itemKeys), | |
| }; | |
| }, {}); | |
| } | |
| } | |
| return sassUtils.castToSass(returnValue); | |
| }; | |
| // sass-loader function to return the entire theme | |
| const getConfig = () => getConfigItem(); | |
| module.exports = { | |
| getConfig, | |
| getConfigItem, | |
| }; |
| const tailwindSassLoader = require('./tailwind.sass') | |
| module.exports = { | |
| css: { | |
| loaderOptions: { | |
| postcss: { | |
| plugins: (loader) => [ | |
| tailwindcss('./tailwind.config.js'), | |
| autoprefixer(), | |
| ], | |
| }, | |
| sass: { | |
| functions: { | |
| 'theme($keys)': tailwindSassLoader.getConfigItem, | |
| }, | |
| } | |
| }, | |
| } | |
| } |
Just made it work with Tailwind 1.0. See revisions for older versions compatible with beta.
This is such a handy script. Thank you very much :)
Hello,
It's a great idea.
But I'm using a laravelMix with webpack.mix.js and webpack.config.js. I dont know where should put this config:
sass: { functions: { 'theme($keys)': tailwindSassLoader.getConfigItem, }, }
my webpack.mix looks like:
`
const mix = require('laravel-mix');
const tailwindcss = require('tailwindcss');
mix.js('resources/js/app.js', 'public/js')
.vue()
.sass('resources/sass/app.sass', 'public/css')
.options({
processCssUrls: false,
postCss: [
tailwindcss('./tailwind.config.js')
]
})
.webpackConfig(require('./webpack.config'));
if (mix.inProduction()) {
mix.version();
}`
and webpack.config.js:
`
const path = require('path');
module.exports = {
resolve: {
alias: {
'@': path.resolve('resources/js'),
},
}
};
`
Can you help me? thanks! :)
I never used Mix, but it looks like it should be added there:
const mix = require('laravel-mix');
const tailwindcss = require('tailwindcss');
mix.js('resources/js/app.js', 'public/js')
.vue()
.sass('resources/sass/app.sass', 'public/css')
.options({
+functions: { 'theme($keys)': tailwindSassLoader.getConfigItem },
processCssUrls: false,
postCss: [
tailwindcss('./tailwind.config.js')
]
})
.webpackConfig(require('./webpack.config'));
if (mix.inProduction()) {
mix.version();
}Hello!
Yeah! thanks its works :)
Thanks for sharing. any idea on how to use in Angular ?
Sorry, no idea!
A couple of things I want to add:
- When using with Vite, the config is similar:
import { getConfigItem } from "./tailwind.sass";
// or const { getConfigItem } = require('./tailwind.sass.js');
export default defineConfig({
...
css: {
preprocessorOptions: {
scss: {
functions: {
"theme($keys)": getConfigItem,
},
},
},
},
});
- Later versions of
node-sass(I'm on 9.0.0) havesass.types.Colordeprecated and it doesn't seem to work. To fix that, replace thehexToRGBAfunction with this:
const hexToRGBA = (hex) => {
const red = parseInt(hex.slice(1, 3), 16),
green = parseInt(hex.slice(3, 5), 16),
blue = parseInt(hex.slice(5, 7), 16);
return {
red,
green,
blue,
};
};
https://stackoverflow.com/a/28056903/4633197
and then change the part of convertStringToSassDimension that handles the hex values to this:
if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(result)) {
const rgba = hexToRGBA(result);
return new SassColor(rgba);
}
The SassColor constructor only takes an object of red, blue, and green, and optional alpha: https://sass-lang.com/documentation/js-api/classes/sasscolor/
Thanks for sharing 🙏

Original issue on Tailwind repo
Here's I'm using Vue-CLI to configure Webpack, but only this line is important.
The SASS loader is based on the work of @jlpospisil in this file.