Skip to content

Commit 4c2019e

Browse files
committed
added support for tailwind config in esm format
1 parent 63b4258 commit 4c2019e

File tree

7 files changed

+218
-58
lines changed

7 files changed

+218
-58
lines changed

.changeset/forty-gorillas-kick.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'qwik-ui': minor
3+
---
4+
5+
added support for tailwind config in ESM format

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"story.headless": "nx storybook headless",
3232
"test.cli": "nx test cli",
3333
"test.headless": "nx component-test headless",
34-
"test.headless.ci": "nx component-test-ci headless"
34+
"test.headless.ci": "nx component-test-ci headless",
35+
"test.utils": "nx test utils"
3536
},
3637
"packageManager": "[email protected]",
3738
"devDependencies": {

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"dependencies": {
99
"@clack/prompts": "^0.7.0",
1010
"@nx/devkit": "17.1.3",
11-
"@qwik-ui/utils": "workspace:*",
11+
"@qwik-ui/utils": "0.2.0",
1212
"ansis": "2.3.0",
1313
"tslib": "^2.3.0",
1414
"yargs": "17.7.2"

packages/cli/project.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
"targets": {
77
"build-bin": {
88
"executor": "@nx/js:tsc",
9+
910
"outputs": ["{options.outputPath}"],
1011
"options": {
12+
"rootDir": ".",
1113
"main": "packages/cli/bin/index.ts",
1214
"outputPath": "dist/packages/cli",
1315
"tsConfig": "packages/cli/tsconfig.bin.json"

packages/cli/src/generators/setup-tailwind/setup-tailwind-generator.spec.ts

Lines changed: 152 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,48 @@ import { ThemeStyle } from '@qwik-ui/utils';
33
import { SetupTailwindGeneratorSchema } from './schema';
44
import { setupTailwindGenerator } from './setup-tailwind-generator';
55

6+
const tailwindConfigContent = `
7+
content: [
8+
join(__dirname, 'src/**/*.{js,ts,jsx,tsx,mdx}'),
9+
],
10+
darkMode: 'class',
11+
theme: {
12+
screens: {
13+
sm: '640px',
14+
md: '768px',
15+
lg: '1024px',
16+
xl: '1280px',
17+
'2xl': '1536px',
18+
},
19+
important: true,
20+
extend: {
21+
fontFamily: {
22+
sans: ['Inter Variable', 'sans-serif'],
23+
},
24+
},
25+
},
26+
`;
27+
28+
function wrapWithCommonJs(content: string) {
29+
return `
30+
const { join } = require('path');
31+
32+
/** @type {import('tailwindcss').Config} */
33+
module.exports = {
34+
${content}
35+
};
36+
`;
37+
}
38+
39+
function wrapWithEsm(content: string) {
40+
return `
41+
/** @type {import('tailwindcss').Config} */
42+
export default {
43+
${content}
44+
};
45+
`;
46+
}
47+
648
describe('Setup Tailwind generator', () => {
749
function setupWithProperFiles() {
850
const options: SetupTailwindGeneratorSchema = {};
@@ -23,36 +65,7 @@ html {
2365
}`,
2466
);
2567

26-
tree.write(
27-
'tailwind.config.cjs',
28-
`
29-
const { join } = require('path');
30-
31-
/** @type {import('tailwindcss').Config} */
32-
module.exports = {
33-
content: [
34-
join(__dirname, 'src/**/*.{js,ts,jsx,tsx,mdx}'),
35-
],
36-
darkMode: 'class',
37-
theme: {
38-
screens: {
39-
sm: '640px',
40-
md: '768px',
41-
lg: '1024px',
42-
xl: '1280px',
43-
'2xl': '1536px',
44-
},
45-
important: true,
46-
extend: {
47-
fontFamily: {
48-
sans: ['Inter Variable', 'sans-serif'],
49-
},
50-
},
51-
},
52-
};
53-
54-
`,
55-
);
68+
tree.write('tailwind.config.cjs', wrapWithCommonJs(tailwindConfigContent));
5669

5770
return {
5871
tree,
@@ -61,8 +74,7 @@ html {
6174
}
6275

6376
test(`
64-
GIVEN global.css and tailwind config exist
65-
WHEN running the generator
77+
GIVEN global.css and tailwind config exist in commonjs format
6678
THEN it should generate the proper tailwind config values`, async () => {
6779
const { tree, options } = setupWithProperFiles();
6880

@@ -86,6 +98,114 @@ html {
8698
});
8799
}),
88100
],
101+
102+
content: [join(__dirname, 'src/**/*.{js,ts,jsx,tsx,mdx}')],
103+
darkMode: 'class',
104+
theme: {
105+
screens: {
106+
sm: '640px',
107+
md: '768px',
108+
lg: '1024px',
109+
xl: '1280px',
110+
'2xl': '1536px',
111+
},
112+
important: true,
113+
extend: {
114+
colors: {
115+
border: 'hsl(var(--border))',
116+
input: 'hsl(var(--input))',
117+
ring: 'hsl(var(--ring))',
118+
background: 'hsl(var(--background))',
119+
foreground: 'hsl(var(--foreground))',
120+
primary: {
121+
DEFAULT: 'hsl(var(--primary))',
122+
foreground: 'hsl(var(--primary-foreground))',
123+
},
124+
secondary: {
125+
DEFAULT: 'hsl(var(--secondary))',
126+
foreground: 'hsl(var(--secondary-foreground))',
127+
},
128+
alert: {
129+
DEFAULT: 'hsl(var(--alert))',
130+
foreground: 'hsl(var(--alert-foreground))',
131+
},
132+
muted: {
133+
DEFAULT: 'hsl(var(--muted))',
134+
foreground: 'hsl(var(--muted-foreground))',
135+
},
136+
accent: {
137+
DEFAULT: 'hsl(var(--accent))',
138+
foreground: 'hsl(var(--accent-foreground))',
139+
},
140+
card: {
141+
DEFAULT: 'hsl(var(--card))',
142+
foreground: 'hsl(var(--card-foreground))',
143+
},
144+
},
145+
borderRadius: {
146+
base: 'var(--border-radius)',
147+
sm: 'calc(var(--border-radius) + 0.125rem)',
148+
DEFAULT: 'calc(var(--border-radius) + 0.25rem)',
149+
md: 'calc(var(--border-radius) + 0.375rem)',
150+
lg: 'calc(var(--border-radius) + 0.5rem)',
151+
xl: 'calc(var(--border-radius) + 0.75rem)',
152+
'2xl': 'calc(var(--border-radius) + 1rem)',
153+
'3xl': 'calc(var(--border-radius) + 1.5rem)',
154+
preset: 'var(--border-radius)',
155+
},
156+
borderWidth: {
157+
base: 'var(--border-width)',
158+
DEFAULT: 'calc(var(--border-width) + 1px)',
159+
2: 'calc(var(--border-width) + 2px)',
160+
4: 'calc(var(--border-width) + 4px)',
161+
8: 'calc(var(--border-width) + 8px)',
162+
},
163+
boxShadow: {
164+
base: 'var(--shadow-base)',
165+
sm: 'var(--shadow-sm)',
166+
DEFAULT: 'var(--shadow)',
167+
md: 'var(--shadow-md)',
168+
lg: 'var(--shadow-lg)',
169+
xl: 'var(--shadow-xl)',
170+
'2xl': 'var(--shadow-2xl)',
171+
inner: 'var(--shadow-inner)',
172+
},
173+
fontFamily: {
174+
sans: ['Inter Variable', 'sans-serif'],
175+
},
176+
},
177+
},
178+
};
179+
"
180+
`);
181+
});
182+
183+
test(`
184+
GIVEN tailwind config exist in esm format
185+
WHEN running the generator
186+
THEN it should generate the proper tailwind config values`, async () => {
187+
const { tree, options } = setupWithProperFiles();
188+
tree.write('tailwind.config.js', wrapWithEsm(tailwindConfigContent));
189+
190+
options.rootCssPath = 'src/global.css';
191+
192+
await setupTailwindGenerator(tree, options);
193+
194+
const updatedTailwindConfigContent = tree.read('tailwind.config.js', 'utf-8');
195+
196+
expect(updatedTailwindConfigContent).toMatchInlineSnapshot(`
197+
"/** @type {import('tailwindcss').Config} */
198+
export default {
199+
plugins: [
200+
plugin(function ({ addUtilities }) {
201+
addUtilities({
202+
'.press': {
203+
transform: 'var(--transform-press)',
204+
},
205+
});
206+
}),
207+
],
208+
89209
content: [join(__dirname, 'src/**/*.{js,ts,jsx,tsx,mdx}')],
90210
darkMode: 'class',
91211
theme: {

packages/cli/src/generators/setup-tailwind/setup-tailwind-generator.ts

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -71,45 +71,70 @@ function updateTailwindConfig(tree: Tree, projectRoot: string, kitRoot: string)
7171
'// EXTEND-END',
7272
);
7373

74-
const moduleExportsRegex = /\bmodule\.exports\s*=\s*\{/;
74+
const commonJsModuleExportsRegex = /\bmodule\.exports\s*=\s*\{/;
75+
const esmModuleExportsRegex = /\bexport\s*default\s*\{/;
76+
let modifiedTailwindConfigContent;
77+
78+
modifiedTailwindConfigContent = insertAfter({
79+
whatToFind: commonJsModuleExportsRegex,
80+
content: tailwindConfigContent,
81+
whatToInsert: rootTemplate,
82+
shouldThrow: false,
83+
});
7584

76-
let modifiedTailwindConfigContent = insertAfter(
77-
moduleExportsRegex,
78-
tailwindConfigContent,
79-
rootTemplate,
80-
'module.exports',
81-
);
85+
// if the result is undefined that means that
86+
// it didn't find the `module.exports` string
87+
if (!modifiedTailwindConfigContent) {
88+
modifiedTailwindConfigContent = insertAfter({
89+
whatToFind: esmModuleExportsRegex,
90+
content: tailwindConfigContent,
91+
whatToInsert: rootTemplate,
92+
shouldThrow: true,
93+
errorTitle: '"module.exports" or "export default"',
94+
});
95+
}
8296

8397
const extendKeyword = /\bextend:\s*\{/;
8498

85-
modifiedTailwindConfigContent = insertAfter(
86-
extendKeyword,
87-
modifiedTailwindConfigContent,
88-
extendTemplate,
89-
'extend',
90-
);
99+
modifiedTailwindConfigContent = insertAfter({
100+
whatToFind: extendKeyword,
101+
content: modifiedTailwindConfigContent,
102+
whatToInsert: extendTemplate,
103+
shouldThrow: true,
104+
errorTitle: 'extend',
105+
});
91106

92107
tree.write(tailwindConfigPath, modifiedTailwindConfigContent);
93108
}
94109

95-
function insertAfter(
96-
regex: RegExp,
97-
content: string,
98-
toInsert: string,
99-
errorTitle: string,
100-
) {
101-
const match = content.match(regex);
110+
type InsertAfterConfig = {
111+
whatToFind: RegExp;
112+
content: string;
113+
whatToInsert: string;
114+
shouldThrow?: boolean;
115+
errorTitle?: string;
116+
};
117+
118+
function insertAfter({
119+
whatToFind,
120+
content,
121+
whatToInsert,
122+
shouldThrow,
123+
errorTitle,
124+
}: InsertAfterConfig) {
125+
const match = content.match(whatToFind);
102126

103127
if (!match || !match.index) {
104-
throw new Error(
105-
`Could not find the "${errorTitle}" property in your tailwind config file`,
106-
);
128+
if (shouldThrow) {
129+
throw new Error(`Could not find the "${errorTitle}" in your tailwind config file`);
130+
}
131+
return;
107132
}
108133

109134
if (match && match.index) {
110135
const startIndex = match.index + match[0].length;
111136
const modifiedTailwindConfigContent =
112-
content.slice(0, startIndex) + toInsert + content.slice(startIndex);
137+
content.slice(0, startIndex) + whatToInsert + content.slice(startIndex);
113138

114139
return modifiedTailwindConfigContent;
115140
}

packages/kit-styled/src/templates/global.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,3 +1332,10 @@ body {
13321332
animation: 500ms cubic-bezier(0.87, 0, 0.13, 1) 0s 1 normal forwards accordion-close;
13331333
}
13341334
}
1335+
1336+
/* Not used yet - could be used for the colored text on the landing page when the make-it-yours color is too bright in light mode or too dim in dark mode */
1337+
@layer components {
1338+
.text-outlined {
1339+
@apply [text-shadow:-1px_0_black,_0_1px_black,_1px_0_black,_0_-1px_black] dark:[text-shadow:-1px_0_white,_0_1px_white,_1px_0_white,_0_-1px_white];
1340+
}
1341+
}

0 commit comments

Comments
 (0)