Skip to content

Commit abd19dc

Browse files
committed
First commit
0 parents  commit abd19dc

File tree

5 files changed

+273
-0
lines changed

5 files changed

+273
-0
lines changed

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
insert_final_newline = true
6+
trim_trailing_whitespace = true
7+
end_of_line = lf
8+
indent_style = space
9+
indent_size = 2

README.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Tailwind CSS Breakpoints Inspector
2+
A Tailwind CSS component that shows the currently active responsive breakpoint.
3+
4+
<img src="screenshot.gif" width="534">
5+
6+
## Install
7+
8+
Requires **Tailwind v2.0** or higher but it should work for **Tailwind v1.0** too (not tested).
9+
10+
1. Install the plugin:
11+
12+
```bash
13+
npm install tailwindcss-breakpoints-inscpector --save-dev
14+
```
15+
16+
2. Add it to your `tailwind.config.js` file:
17+
18+
```js
19+
// tailwind.config.js
20+
module.exports = {
21+
//...
22+
plugins: [
23+
require('tailwindcss-breakpoints-inscpector'),
24+
]
25+
}
26+
```
27+
28+
## Usage
29+
30+
Just run build tools and voila!
31+
No extra markup, no external ressources.
32+
33+
The indicator is only present during development.
34+
35+
Uner the hood we use svg for Tailwind logo and inspector render.
36+
37+
## Customization
38+
39+
You can customize this plugin in the `theme.breakpointsInspector` section of your `tailwind.config.js` file.
40+
41+
42+
#### Position
43+
44+
The first item of the position configuration array can be `top` or `bottom`, the second item can be `left` or `right`.
45+
46+
```js
47+
// tailwind.config.js
48+
module.exports = {
49+
theme: {
50+
breakpointsInspector: {
51+
position: ['bottom', 'left'],
52+
},
53+
},
54+
plugins: [
55+
require('tailwindcss-breakpoints-inscpector'),
56+
],
57+
}
58+
```
59+
60+
#### Styles
61+
62+
Take a look at the [index.js](index.js) file to see all the default styles.
63+
64+
```js
65+
// tailwind.config.js
66+
module.exports = {
67+
theme: {
68+
breakpointsInspector: {
69+
style: {
70+
backgroundColor: '#323232;',
71+
color: '#9e9e9e',
72+
// ...
73+
},
74+
},
75+
},
76+
plugins: [
77+
require('tailwindcss-breakpoints-inscpector'),
78+
],
79+
}
80+
```
81+
82+
#### Prefix
83+
84+
Modify the debug label prefix with the `prefix` configuration option.
85+
86+
```js
87+
// tailwind.config.js
88+
module.exports = {
89+
theme: {
90+
breakpointsInspector: {
91+
prefix: 'My breakpoint is ',
92+
},
93+
},
94+
plugins: [
95+
require('tailwindcss-breakpoints-inscpector'),
96+
],
97+
}
98+
```
99+
100+
#### Ignore screens
101+
102+
To ignore a specific screen (for instance [dark mode](https://v1.tailwindcss.com/docs/breakpoints#dark-mode) in v1), add the screen name to the `ignore` configuration array.
103+
The Tailwind v1 `dark` screen is ignored by default.
104+
105+
```js
106+
// tailwind.config.js
107+
module.exports = {
108+
theme: {
109+
breakpointsInspector: {
110+
ignore: ['dark'],
111+
},
112+
},
113+
plugins: [
114+
require('tailwindcss-breakpoints-inscpector'),
115+
],
116+
}
117+
```

index.js

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
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 ? '&gt;' + screens[screen] : '&lt;' + 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+
}

package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "tailwindcss-breakpoints-inscpector",
3+
"version": "1.0.0",
4+
"description": "A Tailwind CSS component that shows the currently active breakpoint.",
5+
"main": "index.js",
6+
"author": "Damien MATHIEU",
7+
"license": "MIT",
8+
"repository": {
9+
"type": "git",
10+
"url": "https://github.com/hounddd/tailwindcss-breakpoint-inscpector.git"
11+
},
12+
"homepage": "https://github.com/hounddd/tailwindcss-breakpoint-inscpector",
13+
"bugs": "https://github.com/hounddd/tailwindcss-breakpoint-inscpector/issues",
14+
"peerDependencies": {
15+
"tailwindcss": "^1.0 || ^2.0"
16+
}
17+
}

screenshot.gif

1.67 MB
Loading

0 commit comments

Comments
 (0)