├── README.md ├── package.json └── src └── index.js /README.md: -------------------------------------------------------------------------------- 1 | # tailwindcss-question-mark 2 | 3 | A plugin that provides a helpful `?` dev time utility. 4 | 5 | **Demo**: [https://play.tailwindcss.com/fXhD65EpG4?layout=horizontal](https://play.tailwindcss.com/l31KWvYYJP?layout=horizontal) 6 | 7 | ![example](https://user-images.githubusercontent.com/2526/248293688-da86d4e7-0955-40fb-8fb2-f892b270a9a8.gif) 8 | 9 | 10 | ## [Installation](#installation "Goto Installation") 11 | 12 | Install the plugin from npm: 13 | 14 | ```sh 15 | # Using npm 16 | npm install tailwindcss-question-mark 17 | 18 | # Using Yarn 19 | yarn add tailwindcss-question-mark 20 | ``` 21 | 22 | Then add the plugin to your `tailwind.config.js` file: 23 | 24 | ```js 25 | // tailwind.config.js 26 | module.exports = { 27 | theme: { 28 | // ... 29 | }, 30 | plugins: [ 31 | require("tailwindcss-question-mark"), 32 | // ... 33 | ], 34 | }; 35 | ``` 36 | 37 | ## [Usage](#usage "Goto Usage") 38 | 39 | Simply add the `?` utility class to any element that you'd like to highlight. 40 | By default, the utility will animate the element with a pink highlight. 41 | 42 | Optionally, you can specify a color by using the `?-{color}` utility class with `{color}` being the semantic name. For 43 | example, `?-blue` will highlight the element with a blue color. 44 | 45 | ![example](https://i.ibb.co/LvXtxLG/twcssqm-colors.gif) 46 | 47 | **Demo**: https://play.tailwindcss.com/fXhD65EpG4?layout=horizontal 48 | 49 | ## [Customizing](#customizing "Goto Customizing") 50 | 51 | Here's an example of how you can customize the plugin with the available configuration options and their defaults. 52 | 53 | ```js 54 | // tailwind.config.js 55 | module.exports = { 56 | theme: { 57 | // ... 58 | }, 59 | plugins: [ 60 | require("tailwindcss-question-mark")({ 61 | animationDuration: "0.6s", 62 | enableAnimation: true, 63 | highlightColorStart: "#f16bc9", 64 | highlightColorEnd: "#f71fb6", 65 | widthStart: "8px", 66 | widthEnd: "12px", 67 | }), 68 | // ... 69 | ], 70 | }; 71 | ``` 72 | 73 | **Demo with customization**: https://play.tailwindcss.com/4Y4TsxcrNU?file=config 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwindcss-question-mark", 3 | "version": "0.5.0", 4 | "description": "A plugin that provides a helpful `?` dev time utilit", 5 | "main": "src/index.js", 6 | "license": "MIT", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/GavinJoyce/tailwindcss-question-mark.git" 13 | }, 14 | "author": "Gavin Joyce", 15 | "bugs": { 16 | "url": "https://github.com/GavinJoyce/tailwindcss-question-mark/issues" 17 | }, 18 | "homepage": "https://github.com/GavinJoyce/tailwindcss-question-mark#readme", 19 | "peerDependencies": { 20 | "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const plugin = require("tailwindcss/plugin"); 2 | 3 | function parsePx(input, defaultValue) { 4 | let value = input.match(/\d+px/); 5 | if (value) { 6 | return parseInt(value[0], 10); 7 | } 8 | return defaultValue; 9 | } 10 | 11 | module.exports = plugin.withOptions( 12 | ({ 13 | animationDuration = "0.6s", 14 | enableAnimation = true, 15 | highlightColorStart = "#f16bc9", 16 | highlightColorEnd = "#f71fb6", 17 | widthStart = "8px", 18 | widthEnd = "12px", 19 | } = {}) => { 20 | return function ({ addUtilities, e, theme }) { 21 | const ANIMATION_NAME = "wobble"; 22 | const OUTLINE_STYLE = "solid"; 23 | 24 | const createUtilitiesForColor = (colorStart, colorEnd, colorName) => { 25 | const className = colorName ? `?-${colorName}` : "?"; 26 | const widthStartPx = `${parsePx(widthStart, 8) / 2}px`; 27 | const widthEndPx = `${parsePx(widthEnd, 12) / 2}px`; 28 | 29 | const boxShadowStart = `inset ${widthStartPx} ${widthStartPx} ${colorStart}, inset -${widthStartPx} -${widthStartPx} ${colorStart}`; 30 | const boxShadowEnd = `inset ${widthEndPx} ${widthEndPx} ${colorEnd}, inset -${widthEndPx} -${widthEndPx} ${colorEnd}`; 31 | 32 | const animation = enableAnimation 33 | ? `${e(className)}${ANIMATION_NAME} ${animationDuration} ease-in-out alternate infinite` 34 | : "none"; 35 | 36 | return { 37 | [`.${e(className)}`]: { 38 | "outline-style": OUTLINE_STYLE, 39 | "outline-width": widthStartPx, 40 | "outline-color": colorStart, 41 | "box-shadow": boxShadowStart, 42 | animation: animation, 43 | }, 44 | [`@keyframes ${e(className)}${ANIMATION_NAME}`]: { 45 | "0%": { 46 | "outline-width": widthStartPx, 47 | "outline-color": colorStart, 48 | "box-shadow": boxShadowStart, 49 | }, 50 | "100%": { 51 | "outline-width": widthEndPx, 52 | "outline-color": colorEnd, 53 | "box-shadow": boxShadowEnd, 54 | }, 55 | }, 56 | }; 57 | }; 58 | 59 | const defaultUtilities = createUtilitiesForColor( 60 | highlightColorStart, 61 | highlightColorEnd, 62 | ); 63 | 64 | const customColors = theme("colors"); 65 | const customUtilities = Object.keys(customColors).reduce( 66 | (acc, colorName) => { 67 | const colorValueStart = 68 | customColors[colorName][400] || customColors[colorName]; 69 | const colorValueEnd = 70 | customColors[colorName][600] || customColors[colorName]; 71 | const utilities = createUtilitiesForColor( 72 | colorValueStart, 73 | colorValueEnd, 74 | colorName, 75 | ); 76 | return { ...acc, ...utilities }; 77 | }, 78 | {}, 79 | ); 80 | 81 | addUtilities({ ...defaultUtilities, ...customUtilities }); 82 | }; 83 | }, 84 | ); 85 | --------------------------------------------------------------------------------