├── .npmignore ├── renovate.json ├── example ├── src │ ├── tailwind.css │ ├── App.css │ ├── david-pisnoy-46juD4zY1XA-unsplash-1.jpg │ ├── reportWebVitals.js │ ├── index.js │ └── App.js ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── manifest.json │ └── index.html ├── craco.config.js ├── tailwind.config.js ├── .gitignore ├── package.json └── README.md ├── scripts └── prepare-gpr.js ├── package.json ├── LICENSE ├── .github └── workflows │ └── npmpublish.yml ├── .gitignore ├── index.js └── readme.md /.npmignore: -------------------------------------------------------------------------------- 1 | /scripts 2 | .github 3 | example -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /example/src/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /example/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umstek/tailwindcss-glow/HEAD/example/public/favicon.ico -------------------------------------------------------------------------------- /example/src/App.css: -------------------------------------------------------------------------------- 1 | .bkg-img { 2 | background-image: url("david-pisnoy-46juD4zY1XA-unsplash-1.jpg"); 3 | background-color: #cccccc; 4 | } 5 | -------------------------------------------------------------------------------- /example/src/david-pisnoy-46juD4zY1XA-unsplash-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umstek/tailwindcss-glow/HEAD/example/src/david-pisnoy-46juD4zY1XA-unsplash-1.jpg -------------------------------------------------------------------------------- /example/craco.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | style: { 3 | postcss: { 4 | plugins: [require("tailwindcss"), require("autoprefixer")], 5 | }, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /example/tailwind.config.js: -------------------------------------------------------------------------------- 1 | const plugin = require("tailwindcss/plugin"); 2 | 3 | module.exports = { 4 | purge: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"], 5 | darkMode: false, // or 'media' or 'class' 6 | theme: { 7 | extend: {}, 8 | }, 9 | variants: { 10 | extend: {}, 11 | }, 12 | plugins: [require("tailwindcss-glow")()], 13 | }; 14 | -------------------------------------------------------------------------------- /scripts/prepare-gpr.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs").promises; 2 | 3 | const GH_USERNAME = "umstek"; 4 | 5 | (async function Prepare() { 6 | const buffer = await fs.readFile("package.json"); 7 | const object = JSON.parse(buffer.toString()); 8 | object.name = `@${GH_USERNAME}/${object.name}`; 9 | await fs.writeFile("package.json", JSON.stringify(object, null, 2)); 10 | })(); 11 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /example/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = (onPerfEntry) => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./tailwind.css"; 4 | import App from "./App"; 5 | import reportWebVitals from "./reportWebVitals"; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById("root") 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /example/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwindcss-glow", 3 | "version": "2.0.0-beta.1", 4 | "description": "TailwindCSS glow plugin", 5 | "keywords": [ 6 | "tailwindcss-plugin", 7 | "tailwindcss", 8 | "glow", 9 | "shadow" 10 | ], 11 | "homepage": "https://github.com/umstek/tailwindcss-glow", 12 | "bugs": { 13 | "url": "https://github.com/umstek/tailwindcss-glow/issues", 14 | "email": "w@umstek.tk" 15 | }, 16 | "repository": "https://github.com/umstek/tailwindcss-glow.git", 17 | "license": "MIT", 18 | "author": "Wickramaranga Abeygunawardhana ", 19 | "main": "index.js", 20 | "scripts": { 21 | "ci-gpr": "node scripts/prepare-gpr.js", 22 | "test": "echo \"Error: No tests rn :(. \" && exit 1" 23 | }, 24 | "dependencies": { 25 | "color-convert": "^2.0.1", 26 | "color-string": "^1.6.0", 27 | "lodash": "^4.17.21", 28 | "tailwindcss": "^2.2.17" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Wickramaranga Abeygunawardhana 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/npmpublish.yml: -------------------------------------------------------------------------------- 1 | name: Node.js Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v2 13 | with: 14 | node-version: 14 15 | # - run: npm ci 16 | # - run: npm test 17 | 18 | publish-npm: 19 | needs: build 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: actions/setup-node@v2 24 | with: 25 | node-version: 14 26 | registry-url: https://registry.npmjs.org/ 27 | # - run: npm ci 28 | - run: npm publish 29 | env: 30 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 31 | 32 | publish-gpr: 33 | needs: build 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v2 37 | - uses: actions/setup-node@v2 38 | with: 39 | node-version: 14 40 | registry-url: https://npm.pkg.github.com/ 41 | scope: "@umstek" 42 | - run: npm run ci-gpr 43 | - run: npm publish 44 | env: 45 | NODE_AUTH_TOKEN: ${{secrets.gpr_token}} 46 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "version": "2.0.0-beta.1", 4 | "private": true, 5 | "dependencies": { 6 | "@craco/craco": "^6.1.1", 7 | "@testing-library/jest-dom": "5.15.0", 8 | "@testing-library/react": "^11.1.0", 9 | "@testing-library/user-event": "13.5.0", 10 | "react": "^17.0.2", 11 | "react-dom": "^17.0.2", 12 | "react-scripts": "4.0.3", 13 | "web-vitals": "2.1.2" 14 | }, 15 | "scripts": { 16 | "start": "craco start", 17 | "build": "craco build", 18 | "test": "craco test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": [ 23 | "react-app", 24 | "react-app/jest" 25 | ] 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | }, 39 | "devDependencies": { 40 | "@tailwindcss/postcss7-compat": "npm:@tailwindcss/postcss7-compat", 41 | "autoprefixer": "^9", 42 | "postcss": "^7", 43 | "tailwindcss": "npm:@tailwindcss/postcss7-compat", 44 | "tailwindcss-glow": "file:.." 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | 3 | function App() { 4 | return ( 5 |
6 |
This example is not production ready.
7 |
8 |
glow-blue-500
9 |
glow-blue-500-md
10 |
glow-blue-500-lg
11 |
glow-blue-500-xl
12 |
13 | glow-blue-500-outline 14 |
15 |
16 | glow-dynamic 17 |
18 |
19 | glow-dynamic-md 20 |
21 |
22 |
23 |

glow-dynamic-md with gradient

24 |
25 |
26 |

using glow-dynamic-lg with background image

27 |
28 |
29 | ); 30 | } 31 | 32 | export default App; 33 | -------------------------------------------------------------------------------- /example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Installing tailwindCSS 6 | 7 | https://tailwindcss.com/docs/guides/create-react-app 8 | 9 | ## Available Scripts 10 | 11 | In the project directory, you can run: 12 | 13 | ### `yarn start` 14 | 15 | Runs the app in the development mode.\ 16 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 17 | 18 | The page will reload if you make edits.\ 19 | You will also see any lint errors in the console. 20 | 21 | ### `yarn test` 22 | 23 | Launches the test runner in the interactive watch mode.\ 24 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 25 | 26 | ### `yarn build` 27 | 28 | Builds the app for production to the `build` folder.\ 29 | It correctly bundles React in production mode and optimizes the build for the best performance. 30 | 31 | The build is minified and the filenames include the hashes.\ 32 | Your app is ready to be deployed! 33 | 34 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 35 | 36 | ### `yarn eject` 37 | 38 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 39 | 40 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 41 | 42 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 43 | 44 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 45 | 46 | ## Learn More 47 | 48 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 49 | 50 | To learn React, check out the [React documentation](https://reactjs.org/). 51 | 52 | ### Code Splitting 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 55 | 56 | ### Analyzing the Bundle Size 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 59 | 60 | ### Making a Progressive Web App 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 63 | 64 | ### Advanced Configuration 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 67 | 68 | ### Deployment 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 71 | 72 | ### `yarn build` fails to minify 73 | 74 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,webstorm+all,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=node,webstorm+all,visualstudiocode 4 | 5 | ### Node ### 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # TypeScript v1 declaration files 50 | typings/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Optional REPL history 62 | .node_repl_history 63 | 64 | # Output of 'npm pack' 65 | *.tgz 66 | 67 | # Yarn Integrity file 68 | .yarn-integrity 69 | 70 | # dotenv environment variables file 71 | .env 72 | .env.test 73 | 74 | # parcel-bundler cache (https://parceljs.org/) 75 | .cache 76 | 77 | # next.js build output 78 | .next 79 | 80 | # nuxt.js build output 81 | .nuxt 82 | 83 | # react / gatsby 84 | ./public/ 85 | 86 | # vuepress build output 87 | .vuepress/dist 88 | 89 | # Serverless directories 90 | .serverless/ 91 | 92 | # FuseBox cache 93 | .fusebox/ 94 | 95 | # DynamoDB Local files 96 | .dynamodb/ 97 | 98 | ### VisualStudioCode ### 99 | .vscode/* 100 | !.vscode/settings.json 101 | !.vscode/tasks.json 102 | !.vscode/launch.json 103 | !.vscode/extensions.json 104 | 105 | ### VisualStudioCode Patch ### 106 | # Ignore all local history of files 107 | .history 108 | 109 | ### WebStorm+all ### 110 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 111 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 112 | 113 | # User-specific stuff 114 | .idea/**/workspace.xml 115 | .idea/**/tasks.xml 116 | .idea/**/usage.statistics.xml 117 | .idea/**/dictionaries 118 | .idea/**/shelf 119 | 120 | # Generated files 121 | .idea/**/contentModel.xml 122 | 123 | # Sensitive or high-churn files 124 | .idea/**/dataSources/ 125 | .idea/**/dataSources.ids 126 | .idea/**/dataSources.local.xml 127 | .idea/**/sqlDataSources.xml 128 | .idea/**/dynamic.xml 129 | .idea/**/uiDesigner.xml 130 | .idea/**/dbnavigator.xml 131 | 132 | # Gradle 133 | .idea/**/gradle.xml 134 | .idea/**/libraries 135 | 136 | # Gradle and Maven with auto-import 137 | # When using Gradle or Maven with auto-import, you should exclude module files, 138 | # since they will be recreated, and may cause churn. Uncomment if using 139 | # auto-import. 140 | # .idea/modules.xml 141 | # .idea/*.iml 142 | # .idea/modules 143 | # *.iml 144 | # *.ipr 145 | 146 | # CMake 147 | cmake-build-*/ 148 | 149 | # Mongo Explorer plugin 150 | .idea/**/mongoSettings.xml 151 | 152 | # File-based project format 153 | *.iws 154 | 155 | # IntelliJ 156 | out/ 157 | 158 | # mpeltonen/sbt-idea plugin 159 | .idea_modules/ 160 | 161 | # JIRA plugin 162 | atlassian-ide-plugin.xml 163 | 164 | # Cursive Clojure plugin 165 | .idea/replstate.xml 166 | 167 | # Crashlytics plugin (for Android Studio and IntelliJ) 168 | com_crashlytics_export_strings.xml 169 | crashlytics.properties 170 | crashlytics-build.properties 171 | fabric.properties 172 | 173 | # Editor-based Rest Client 174 | .idea/httpRequests 175 | 176 | # Android studio 3.1+ serialized cache file 177 | .idea/caches/build_file_checksums.ser 178 | 179 | ### WebStorm+all Patch ### 180 | # Ignores the whole .idea folder and all .iml files 181 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 182 | 183 | .idea/ 184 | 185 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 186 | 187 | *.iml 188 | modules.xml 189 | .idea/misc.xml 190 | *.ipr 191 | 192 | # Sonarlint plugin 193 | .idea/sonarlint 194 | 195 | # End of https://www.gitignore.io/api/node,webstorm+all,visualstudiocode -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const _ = require("lodash"); 2 | const colorString = require("color-string"); 3 | const convert = require("color-convert"); 4 | 5 | const prefixNegativeModifiers = require("tailwindcss/lib/util/prefixNegativeModifiers") 6 | .default; 7 | const flattenColorPalette = require("tailwindcss/lib/util/flattenColorPalette") 8 | .default; 9 | 10 | const defaultStyles = { 11 | default: (baseColor) => 12 | `0 1px 3px 0 rgba(${baseColor}, 0.4), 0 1px 2px 0 rgba(${baseColor}, 0.24)`, 13 | md: (baseColor) => 14 | `0 4px 6px -1px rgba(${baseColor}, 0.4), 0 2px 4px -1px rgba(${baseColor}, 0.24)`, 15 | lg: (baseColor) => 16 | `0 10px 15px -3px rgba(${baseColor}, 0.4), 0 4px 6px -2px rgba(${baseColor}, 0.20)`, 17 | xl: (baseColor) => 18 | `0 20px 25px -5px rgba(${baseColor}, 0.4), 0 10px 10px -5px rgba(${baseColor}, 0.16)`, 19 | "2xl": (baseColor) => `0 25px 50px -12px rgba(${baseColor}, 1)`, 20 | outline: (baseColor) => `0 0 0 3px rgba(${baseColor}, 0.5)`, 21 | none: "none", 22 | }; 23 | 24 | const dynamicGlowBase = { 25 | position: "relative", 26 | zIndex: 1, 27 | "&::after": { 28 | content: "''", 29 | position: "absolute", 30 | background: "inherit", 31 | zIndex: -1, 32 | }, 33 | }; 34 | 35 | const dynamicGlow = { 36 | ...dynamicGlowBase, 37 | "&::after": { 38 | ...dynamicGlowBase["&::after"], 39 | width: "99%", 40 | height: "98%", 41 | top: "2px", 42 | left: "0.4%", 43 | filter: "blur(2px)", 44 | opacity: 1, 45 | }, 46 | }; 47 | 48 | const dynamicGlowMd = { 49 | ...dynamicGlowBase, 50 | "&::after": { 51 | ...dynamicGlowBase["&::after"], 52 | width: "99%", 53 | height: "98%", 54 | top: "4px", 55 | left: "0.5%", 56 | filter: "blur(3px)", 57 | opacity: 0.7, 58 | }, 59 | }; 60 | 61 | const dynamicGlowLg = { 62 | ...dynamicGlowBase, 63 | "&::after": { 64 | ...dynamicGlowBase["&::after"], 65 | width: "98%", 66 | height: "98%", 67 | top: "calc(4px + 2%)", 68 | left: "1%", 69 | filter: "blur(8px)", 70 | opacity: 0.7, 71 | }, 72 | }; 73 | 74 | const dynamicGlowXl = { 75 | ...dynamicGlowBase, 76 | "&::after": { 77 | ...dynamicGlowBase["&::after"], 78 | width: "98%", 79 | height: "96%", 80 | top: "calc(12px + 4%)", 81 | left: "1%", 82 | filter: "blur(12px)", 83 | opacity: 0.53, 84 | }, 85 | }; 86 | 87 | const dynamicGlow2Xl = { 88 | ...dynamicGlowBase, 89 | "&::after": { 90 | ...dynamicGlowBase["&::after"], 91 | width: "94%", 92 | height: "94%", 93 | top: "calc(20px + 4%)", 94 | left: "3%", 95 | filter: "blur(22px)", 96 | opacity: 0.84, 97 | }, 98 | }; 99 | 100 | module.exports = function () { 101 | return function ({ addUtilities, e, theme, variants }) { 102 | const colors = flattenColorPalette(theme("glow.colors") || theme("colors")); 103 | const styles = theme("glow.styles") || defaultStyles; 104 | const styleFunctions = _.filter( 105 | _.toPairs(styles), 106 | ([_modifier, style]) => typeof style === "function" 107 | ); 108 | const staticStyles = _.filter( 109 | _.toPairs(styles), 110 | ([_modifier, style]) => typeof style !== "function" 111 | ); 112 | 113 | const processedGlows = _.flatMap(colors, (colorValue, colorModifier) => { 114 | if (colorValue === "currentColor") { 115 | return null; 116 | } 117 | 118 | const colorDescriptor = colorString.get(colorValue); 119 | const colorRGB = (colorDescriptor.model === "rgb" 120 | ? colorDescriptor.value 121 | : convert[colorDescriptor.model].rgb(colorDescriptor.value) 122 | ).slice(0, 3); 123 | const baseColor = colorRGB.join(", "); 124 | 125 | return _.map(styleFunctions, ([modifier, style]) => { 126 | const className = `${e( 127 | prefixNegativeModifiers( 128 | "glow", 129 | modifier === "default" 130 | ? colorModifier // default style will have only a color suffix 131 | : `${colorModifier}-${modifier}` 132 | ) 133 | )}`; 134 | 135 | return [ 136 | `.${className}`, 137 | { 138 | "box-shadow": style(baseColor), 139 | }, 140 | ]; 141 | }); 142 | }).filter((c) => !!c); 143 | 144 | const staticGlows = _.map(staticStyles, ([modifier, style]) => { 145 | const className = 146 | modifier === "default" 147 | ? "glow" 148 | : `${e(prefixNegativeModifiers("glow", modifier))}`; 149 | 150 | return [ 151 | `.${className}`, 152 | { 153 | "box-shadow": style, 154 | }, 155 | ]; 156 | }); 157 | 158 | const utilities = _.fromPairs([...processedGlows, ...staticGlows]); 159 | 160 | addUtilities(utilities, variants("shadow")); 161 | addUtilities([ 162 | { ".glow-dynamic": dynamicGlow }, 163 | { ".glow-dynamic-md": dynamicGlowMd }, 164 | { ".glow-dynamic-lg": dynamicGlowLg }, 165 | { ".glow-dynamic-xl": dynamicGlowXl }, 166 | { ".glow-dynamic-2xl": dynamicGlow2Xl }, 167 | ]); 168 | }; 169 | }; 170 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Colored/Dynamic Shadow/Glow Plugin for TailwindCSS 2 | 3 | _NOTE_: This plugin is for Tailwind 2.x and unstable; 1.x plugin is at v0.3.10. 4 | https://github.com/umstek/tailwindcss-glow/releases/tag/v0.3.10 5 | 6 | The default shadow plugin for TailwindCSS doesn't support colored shadows, which is a trend now. 7 | This can be customized, of course, but it is still overwhelming to get colored shadows for, e.g.: 10 colors. 8 | WARNING: **This generates a lot of styles, so it is recommended that you choose only the colors that are necessary, 9 | and/or enable purging.** 10 | 11 | ## Installation 12 | 13 | CAREFUL: We DON'T use semantic versioning. 0.x versions are for tailwindcss 1.x and the new versions will maintain major version number as same as the tailwind major version. 14 | 15 | ### With `npm` 16 | 17 | ```bash 18 | npm i tailwindcss-glow 19 | ``` 20 | 21 | ### With `yarn` 22 | 23 | ```bash 24 | yarn add tailwindcss-glow 25 | ``` 26 | 27 | ## Usage 28 | 29 | ```js 30 | // tailwind.config.js 31 | module.exports = { 32 | theme: { 33 | glow: { 34 | colors: { // Defaults to all theme colors 35 | // ... 36 | }, 37 | styles: { // Defaults to these values 38 | default: baseColor => 39 | `0 1px 3px 0 rgba(${baseColor}, 0.4), 0 1px 2px 0 rgba(${baseColor}, 0.24)`, 40 | md: baseColor => 41 | `0 4px 6px -1px rgba(${baseColor}, 0.4), 0 2px 4px -1px rgba(${baseColor}, 0.24)`, 42 | lg: baseColor => 43 | `0 10px 15px -3px rgba(${baseColor}, 0.4), 0 4px 6px -2px rgba(${baseColor}, 0.20)`, 44 | xl: baseColor => 45 | `0 20px 25px -5px rgba(${baseColor}, 0.4), 0 10px 10px -5px rgba(${baseColor}, 0.16)`, 46 | "2xl": baseColor => `0 25px 50px -12px rgba(${baseColor}, 1)`, 47 | outline: baseColor => `0 0 0 3px rgba(${baseColor}, 0.5)`, 48 | none: "none" 49 | } 50 | } 51 | // ... 52 | }, 53 | plugins: [ 54 | // ... 55 | require("tailwindcss-glow")(), 56 | // ... 57 | }; 58 | ``` 59 | 60 | This plugin generates the following utilities: 61 | 62 | ```css 63 | .glow-blue-100 { 64 | /* For each color (blue-100 here), for the `default` style */ 65 | box-shadow: 0 1px 3px 0 rgba(235, 248, 255, 0.4), 0 1px 2px 0 rgba(235, 248, 255, 0.24); 66 | } 67 | 68 | .glow-blue-100-md { 69 | /* For each color (blue-100 here), for each sizes (styles) from `md`, `lg`, `xl` and `2xl`. */ 70 | box-shadow: 0 4px 6px -1px rgba(235, 248, 255, 0.4), 0 2px 4px -1px rgba(235, 248, 255, 0.24); 71 | } 72 | 73 | /* ... */ 74 | 75 | .glow-dynamic { 76 | position: relative; 77 | z-index: 1; 78 | } 79 | 80 | .glow-dynamic::after { 81 | content: ""; 82 | position: absolute; 83 | background: inherit; 84 | z-index: -1; 85 | width: 99%; 86 | height: 98%; 87 | top: 2px; 88 | left: 0.4%; 89 | filter: blur(2px); 90 | opacity: 1; 91 | } 92 | 93 | .glow-dynamic-md { 94 | position: relative; 95 | z-index: 1; 96 | } 97 | 98 | .glow-dynamic-md::after { 99 | content: ""; 100 | position: absolute; 101 | background: inherit; 102 | z-index: -1; 103 | width: 99%; 104 | height: 98%; 105 | top: 4px; 106 | left: 0.5%; 107 | filter: blur(3px); 108 | opacity: 0.7; 109 | } 110 | 111 | /* ...*/ 112 | 113 | /* 114 | * Dynamic glow styles cannot be extended, as of now. The built-in styles are, `default`, `md`, `lg`, `xl` and `2xl`. 115 | * These have been designed to be visually similar as much as possible to their box-shadow counterparts, 116 | * when used with a single color background. 117 | */ 118 | ``` 119 | 120 | ## Customization 121 | 122 | Since the theme colors might include a lot of unnecessary colors, it is recommended to limit the color palette to 123 | your selected accent color(s). 124 | Since the configuration file is JavaScript, you can filter out some of the theme colors. 125 | 126 | ```js 127 | glow: (theme) => ({ 128 | colors: { 129 | blue: theme("colors.blue"), 130 | pink: theme("colors.pink.100"), 131 | }, 132 | styles: { 133 | // ... 134 | }, 135 | }); 136 | ``` 137 | 138 | The default glow styles are the same as TailwindCSS's default shadows, but with an increase in alpha channel. 139 | You can customize them just like you can customize TailwindCSS shadows with one key difference: 140 | In this plugin, we have to support multiple colors, so the R, G, B part of the color is changing. 141 | So, instead of an style string, in this plugin you have to use a function in the format (e.g.): 142 | 143 | ```js 144 | md: baseColor => `0 4px 6px -1px rgba(${baseColor}, 0.4), 0 2px 4px -1px rgba(${baseColor}, 0.24)`, 145 | // ... 146 | ``` 147 | 148 | where the `baseColor` will be a comma-separated list of R, G and B values of that color, in that order, as a string. We have used string interpolation here. 149 | e.g.: For `baseColor` == `rgb(235, 248, 255)`, 150 | 151 | ```css 152 | 0 4px 6px -1px rgba(235, 248, 255, 0.4), 0 2px 4px -1px rgba(235, 248, 255, 0.24); 153 | ``` 154 | 155 | will be generated. Your theme colors can be in any format, `#000000` or `hsl` or otherwise; these will be converted. _This implementation is subject to change in a future version._ 156 | 157 | Dynamic glows cannot be customized currently, as they are _hand-picked_ to be visually similar to the default styles, and thus do not show a sane way to customize. 158 | --------------------------------------------------------------------------------