|
| 1 | +/* |
| 2 | +export default function({addBase, theme}) { |
| 3 | + if (process.env.NODE_ENV === "production") return |
| 4 | +
|
| 5 | + const screens = theme('screens', {}) |
| 6 | + const breakpoints = Object.keys(screens) |
| 7 | +
|
| 8 | + addBase({ |
| 9 | + 'body::after': { |
| 10 | + content: `"Current breakpoint default (< ${screens[breakpoints[0]]})"`, |
| 11 | + position: 'fixed', |
| 12 | + right: '.5rem', // could replace with theme('spacing.2', '.5rem'), same for most of the other values |
| 13 | + bottom: '.5rem', |
| 14 | + padding: '.5rem .5rem .5rem 2rem', |
| 15 | + background: 'no-repeat .5rem center / 1.25rem url(https://tailwindcss.com/favicon-32x32.png), #edf2f7', |
| 16 | + border: '1px solid #cbd5e0', |
| 17 | + color: '#d53f8c', |
| 18 | + fontSize: '.875rem', |
| 19 | + fontWeight: '600', |
| 20 | + zIndex: '99999', |
| 21 | + }, |
| 22 | + ...breakpoints.reduce((acc, current) => { |
| 23 | + acc[`@media (min-width: ${screens[current]})`] = { |
| 24 | + 'body::after': { |
| 25 | + content: `"Current breakpoint ${current}"` |
| 26 | + } |
| 27 | + } |
| 28 | + return acc |
| 29 | + }, {}) |
| 30 | + }) |
| 31 | +} |
| 32 | +*/ |
| 33 | + |
| 34 | +module.exports = function ({ |
| 35 | + addComponents, |
| 36 | + theme |
| 37 | +}) { |
| 38 | + if (process.env.NODE_ENV === "production") return |
| 39 | + |
| 40 | + const defaultPosition = ['bottom', 'right']; |
| 41 | + const screens = theme('screens'); |
| 42 | + const userStyles = theme('breakpointsInspector.style', {}); |
| 43 | + const ignoredScreens = theme('breakpointsInspector.ignore', ['dark']); |
| 44 | + const minWidth = theme('breakpointsInspector.width', 120); |
| 45 | + const prefix = theme('breakpointsInspector.prefix', 'Current breakpoint '); |
| 46 | + const position = theme('breakpointsInspector.position', defaultPosition); |
| 47 | + const positionY = position[0] || defaultPosition[0]; |
| 48 | + const positionX = position[1] || defaultPosition[1]; |
| 49 | + const symbols = /[\r\n%#()<>?[\\\]^`{|}]/g; |
| 50 | + const minScreen = Object.entries(screens).filter(([screen]) => !ignoredScreens.includes(screen))[0][1]; |
| 51 | + |
| 52 | + const gridStyle = Object.assign({ |
| 53 | + color: '#d53f8c', |
| 54 | + fontSize: '12px', |
| 55 | + fontFamily: 'sans-serif', |
| 56 | + }, userStyles, { |
| 57 | + display: 'grid', |
| 58 | + gridTemplateColumns: '1fr min-content', |
| 59 | + gridTemplateRows: 'repeat(2, minmax(15px, 1fr))', |
| 60 | + columnGap: '6px', |
| 61 | + padding: '0', |
| 62 | + }); |
| 63 | + |
| 64 | + const styleToString = (style) => { |
| 65 | + return Object.keys(style).reduce((acc, key) => ( |
| 66 | + acc + key.split(/(?=[A-Z])/).join('-').toLowerCase() + ':' + style[key] + ';' |
| 67 | + ), ''); |
| 68 | + }; |
| 69 | + |
| 70 | + const makeContent = (prefix, screen = null) => { |
| 71 | + |
| 72 | + let template = `<svg width='` + (screen ? minWidth + 40 : minWidth) + `' height='30' xmlns='http://www.w3.org/2000/svg'> |
| 73 | + <style> |
| 74 | + .inspect--grid {` + styleToString(gridStyle) + `} |
| 75 | + .inspect--text { |
| 76 | + text-align: right; |
| 77 | + overflow: hidden; |
| 78 | + white-space: nowrap; |
| 79 | + } |
| 80 | + .inspect--indicator { |
| 81 | + font-size: 200%; |
| 82 | + text-align: center; |
| 83 | + grid-row: span 2 / span 2; |
| 84 | + } |
| 85 | + </style> |
| 86 | + <foreignObject width='100%' height='100%' x='0' y='0'> |
| 87 | + <div xmlns='http://www.w3.org/1999/xhtml' class='inspect--grid'> |
| 88 | + <div class='inspect--text'>${prefix}</div> |
| 89 | + <div class='inspect--indicator'><b>${screen ? screen : ''}</b></div> |
| 90 | + <div class='inspect--text'><b>${(screen ? '>' + screens[screen] : '<' + minScreen)}</b></div> |
| 91 | + </div> |
| 92 | + </foreignObject> |
| 93 | + </svg>`; |
| 94 | + |
| 95 | + template = template.replace(/>\s{1,}</g, `><`); |
| 96 | + template = template.replace(/\s{2,}/g, ` `); |
| 97 | + |
| 98 | + return `url("data:image/svg+xml,` + template.replace(symbols, encodeURIComponent) + `");`; |
| 99 | + }; |
| 100 | + |
| 101 | + const components = { |
| 102 | + 'body::after': Object.assign({ |
| 103 | + position: 'fixed', |
| 104 | + zIndex: '2147483647', |
| 105 | + [positionY]: '.5rem', |
| 106 | + [positionX]: '.5rem', |
| 107 | + padding: '.25rem .5rem .25rem 1.75rem', |
| 108 | + lineHeight: '1', |
| 109 | + background: '#edf2f7', |
| 110 | + backgroundImage: 'url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' fill=\'none\' viewBox=\'0 0 54 33\'%3E%3Cg clip-path=\'url(%23prefix__clip0)\'%3E%3Cpath fill=\'%2306B6D4\' fill-rule=\'evenodd\' d=\'M27 0c-7.2 0-11.7 3.6-13.5 10.8 2.7-3.6 5.85-4.95 9.45-4.05 2.054.513 3.522 2.004 5.147 3.653C30.744 13.09 33.808 16.2 40.5 16.2c7.2 0 11.7-3.6 13.5-10.8-2.7 3.6-5.85 4.95-9.45 4.05-2.054-.513-3.522-2.004-5.147-3.653C36.756 3.11 33.692 0 27 0zM13.5 16.2C6.3 16.2 1.8 19.8 0 27c2.7-3.6 5.85-4.95 9.45-4.05 2.054.514 3.522 2.004 5.147 3.653C17.244 29.29 20.308 32.4 27 32.4c7.2 0 11.7-3.6 13.5-10.8-2.7 3.6-5.85 4.95-9.45 4.05-2.054-.513-3.522-2.004-5.147-3.653C23.256 19.31 20.192 16.2 13.5 16.2z\' clip-rule=\'evenodd\'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id=\'prefix__clip0\'%3E%3Cpath fill=\'%23fff\' d=\'M0 0h54v32.4H0z\'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E")', |
| 111 | + backgroundRepeat: 'no-repeat', |
| 112 | + backgroundSize: '22px auto', |
| 113 | + backgroundPosition: '.5rem center', |
| 114 | + border: '1px solid #cbd5e0', |
| 115 | + content: makeContent(prefix), |
| 116 | + }, userStyles), |
| 117 | + }; |
| 118 | + |
| 119 | + Object.entries(screens) |
| 120 | + .filter(([screen]) => !ignoredScreens.includes(screen)) |
| 121 | + .forEach(([screen]) => { |
| 122 | + components[`@screen ${screen}`] = { |
| 123 | + 'body::after': { |
| 124 | + content: makeContent(prefix, screen), |
| 125 | + }, |
| 126 | + }; |
| 127 | + }); |
| 128 | + |
| 129 | + addComponents(components); |
| 130 | +} |
0 commit comments