Vue CLI + Tailwind: Theming with CSS Variables - tailwind-css

The setup below works as expected on:
yarn serve
However it does not add the custom theme varaiables to the generated CSS file on:
yarn build
Setup:
project\src\assets\tailwind.css
#tailwind base;
#tailwind components;
#tailwind utilities;
#layer components { [...] }
#layer base {
:root{
--color-text-title: 0, 0, 0;
[...]
}
.theme-customOne{
--color-text-title: 0, 255, 0;
[...]
}
.theme-customTwo{
--color-text-title: 0, 0, 255;
[...]
}
}
project\tailwind.config.js
function withOpacity(variableName) {
[...]
}
module.exports = {
purge: { content: ["./public/**/*.html", "./src/**/*.vue"] },
darkMode: false,
theme: {
extend: {
textColor: {
skin: {
title: withOpacity("--color-text-title"),
[...]
}
}
}
}
}
Output:
project\dist\css\index.cae56bc4.css
:root{
--color-text-title: 0, 0, 0;
[...]
}
Is there a way to get the theme specific CSS Variables in the generated CSS file as part of the build process?

I figurd it out by myself.
The solution is to add the custom classes you would like to preserve to your tailwind.config.js like so:
module.exports = {
purge: {
content: ["./public/**/*.html", "./src/**/*.vue"],
safelist: ["theme-customeOne", "theme-customTwo"]
},
[...]
}
After that you can run:
yarn build
If you now check the generated CSS e.g. project\dist\css\index.cae56bc4.css
you will find the custom class + custom CSS variables inside that file.
I share my solution in case it might be helpful to anyone else who will come across
this issue.

Related

postcss-conditionals with mixins (vite + postcss.config.js)

I'm having an issue converting my postcss conditionals to css. I'm using vite to process the files and output a css file. Everything seems to be working up until the point that I try to convert the conditionals (see below).
Here is my vite file:
import { defineConfig } from 'vite';
import postcss from './postcss.config.js';
import dns from 'dns';
dns.setDefaultResultOrder('verbatim');
export default defineConfig({
root: 'src',
build: {
manifest: 'vite-manifest.json',
rollupOptions: {
input: {
main: './src/scripts/main.js',
},
},
outDir: '../dist',
emptyOutDir: true,
},
css: {
postcss,
devSourcemap: true,
},
server: {
hmr: {
protocol: 'ws',
},
},
});
Here is a simplified version of my postcss file:
import atImport from 'postcss-import';
import atMixins from 'postcss-mixins';
import atIf from 'postcss-conditionals';
import nested from 'postcss-nested';
export default {
plugins: [
atImport,
atMixins,
atIf,
nested,
],
};
The mixin I'm trying to parse:
#define-mixin center-x $position, $distance {
position: absolute;
left: 50%;
transform: translateX(-50%);
#if $position == top {
top: $distance;
bottom: auto;
} #else {
top: auto;
bottom: $distance;
}
}
This gives me this error: [vite:css] postcss-conditionals: src\styles\base\mixins.css:6:5: Failed to parse expression file: src/styles/main.css error during build: CssSyntaxError: postcss-conditionals: src\styles\base\mixins.css:10:5: Failed to parse expression
Furthermore replacing the if else inside the mixin with:
#if 3 < 5 {
background: green;
}
doesn't give me that error.
Maybe the mixin variables aren't resolved yet before the conditionals can use them but I don't know how to get those resolved first. Really hope someone knows how to fix this.
Gave this another try today, still can't fix it so I replaced the following plugins:
postcss-for
postcss-each
postcss-each-variables
postcss-mixins
postcss-conditionals
for postcss-advanced-variables where combining conditionals and mixins works out of the box, the downside is that I have to use SASS syntax instead of postcss syntax but that's ok I guess.

Create custom utility referencing additional custom colors

I have several custom utilities configured in my tailwind.config.cjs file this:
plugins: [
plugin(({ addUtilities }) => {
const utilities = {
'.border-invalid': {
border: '1px solid #ef4444',
},
[...]
};
addUtilities(utilities);
}),
],
I also have defined custom colors, like this
extend: {
colors: {
'red-50': '#FEF2F2',
[...]
'red-500': '#EF4444',
[...]
}
}
Instead of having the hard-coded value in my custom utility, I'd like to reference my custom color, so that if I ever change my color palette my custom utilities would be updated accordingly. So, ideally, it would be something like this:
const utilities = {
'.border-invalid': {
apply: 'border border-solid border-red-500',
},
Or some way to reference red-500 in my custom utility instead of the hard-coded #EF4444.
Is there a way to achieve it?
#ihar-aliakseyenka answer workes great, I added this just to tell that the second alternative, border: "1px solid theme('colors.red-500')" even show a nice and clear css definition when flying with the mouse over:
While the first option, border: 1px solid ${theme('colors.red-500')}` just show the literarl value (as expected, btw):
You may use theme() directive
plugins: [
plugin(({ addUtilities, theme }) => { // extract theme
const utilities = {
'.border-invalid': {
border: `1px solid ${theme('colors.red-500')}`, // concatenate
}
};
addUtilities(utilities);
}),
],
// or pass it as a string
plugins: [
plugin(({ addUtilities }) => {
const utilities = {
'.border-invalid': {
border: "1px solid theme('colors.red-500')",
}
};
addUtilities(utilities);
}),
],
Note: you set your color as red-500, so no dot notation will be available like theme('colors.red.500') (it will cause error. Well maybe not because Tailwind has red-500 color but in any other cases it will)
DEMO

Unable to extend: TailwindCSS variants:

I am looking to extend the margin style and add the variant ['even'] to it.
I can add the variant like so:
module.exports = {
variants: {
margin: ['even'],
},
theme: {
...
}
}
It is my understanding that the above will override the margin styles default variants.
The documentation here shows the ability to extend a variant as to not remove all the defaults when adding the new variant (discussed more here).
I have tried this and not been successful:
module.exports = {
variants: {
extend: {
margin: ['even'],
},
},
theme: {
...
}
}
I must be doing something wrong or have a typo?
The reason I was unable to do this was because of my tailwindcss version being below 2.0. As #Jon suggested. Thanks! 2.0 release notes.

Theming with SCSS & nuxt

I'm trying to allow my users to have different themes to choose from however I can't seem to get it working. I've tried multiple different ways, one way is having two different files and i import them based on if the theme is light/dark however once it's imported it stays on the page. Another is within SCSS like this:
$enable-rounded: true;
[theme="dark"] {
$blue: #232c3b;
$body-bg: #262626;
$body-color: white;
}
[theme="light"] {
$body-bg: #ffffff;
$body-color: #000000;
}
#import 'bootstrap/scss/bootstrap.scss';
#import 'bootstrap-vue/src/index.scss';
then in my layouts/default.vue:
import(`~/assets/scss/main.scss`)
export default {
data() {
return {
darkMode: false,
}
},
mounted() {
let bodyElement = document.body;
bodyElement.classList.add("app-background");
let htmlElement = document.documentElement;
let theme = localStorage.getItem("theme");
if (theme === 'dark') {
bodyElement.setAttribute('theme', 'dark')
this.darkMode = true
} else {
bodyElement.setAttribute('theme', 'light');
this.darkMode = false
}
},
watch: {
darkMode: function () {
let htmlElement = document.documentElement;
if (this.darkMode) {
localStorage.setItem("theme", 'dark');
htmlElement.setAttribute('theme', 'dark');
} else {
localStorage.setItem("theme", 'light');
htmlElement.setAttribute('theme', 'light');
}
}
}
}
however nothing happens when I do it this way. I've been trying to figure it out for days and can't seem to get it. It makes me want to just use CSS and avoid SCSS even though I really want to use scss
I think you are importing your scss file in a wrong way. Please try importing it like below out of the script part:
<style lang="scss">
#import '~/assets/scss/main.scss';
</style>
I think you can use this for your project, you can switch into themes or custom on your own
https://color-mode.nuxtjs.org/

How to #import using chrome.tabs.insertCSS()?

chrome.tabs.insertCSS(tabId, { code : '#import url("custom.css");' });
OR
chrome.tabs.insertCSS(tabId, { file : 'importer.css' });
importer.css:
#import url("custom.css");
a { color:red!important; } /* this rule applied successfully though. */
Doesn't seem to work as expected.
Why doesn't it work and how to make it work?
Edit:
Maybe I am looking at the wrong source code location, but the source code indicates that it uses the regular style sheet parser to parse the injected CSS. In other words, if the #import directive works in regular CSS documents, it should also work in injected CSS.
https://code.google.com/p/chromium/codesearch#chromium/src/extensions/renderer/script_injection.cc&q=script_injection.cc&sq=package:chromium&type=cs&l=312-320
void ScriptInjection::InjectCss(blink::WebLocalFrame* frame) {
std::vector<std::string> css_sources =
injector_->GetCssSources(run_location_);
for (std::vector<std::string>::const_iterator iter = css_sources.begin();
iter != css_sources.end();
++iter) {
frame->document().insertStyleSheet(blink::WebString::fromUTF8(*iter));
}
}
Edit:
Sample code that's not working:
Directory structure:
ext.root
|-- custom.css
|-- custom.css.js
|-- importer.css
|-- manifest.json
manifest.json:
{
"background": {
"scripts": [ "custom.css.js" ],
"persistent": true
},
"manifest_version": 2,
"name": "custom.css",
"version": "1.0",
"web_accessible_resources" : [ "*" ],
"permissions" : [ "webNavigation", "http://*/", "https://*/" ]
}
custom.css.js:
chrome.webNavigation.onCommitted.addListener(function(details) {
console.log('inserting css');
console.log(chrome.runtime.getURL("custom.css"));
chrome.tabs.insertCSS(details.tabId, { file : 'importer.css' });
chrome.tabs.insertCSS(details.tabId, { code : '#import url("custom.css");' });
chrome.tabs.insertCSS(details.tabId, { code : '#import url(custom.css);' });
chrome.tabs.insertCSS(details.tabId, { code : '#import url("' + chrome.runtime.getURL("custom.css") + '");' });
chrome.tabs.insertCSS(details.tabId, { code : '#import url(' + chrome.runtime.getURL("custom.css") + ');' });
chrome.tabs.insertCSS(details.tabId, { code : '#import "custom.css";' });
chrome.tabs.insertCSS(details.tabId, { code : '#import custom.css;' });
chrome.tabs.insertCSS(details.tabId, { code : '#import "' + chrome.runtime.getURL("custom.css") + '";' });
chrome.tabs.insertCSS(details.tabId, { code : '#import ' + chrome.runtime.getURL("custom.css") + ';' });
});
importer.css:
#import "custom.css";
#import "chrome-extension://__MSG_##extension_id__/custom.css";
#import custom.css;
#import chrome-extension://__MSG_##extension_id__/custom.css;
#import url("custom.css");
#import url("chrome-extension://__MSG_##extension_id__/custom.css");
#import url(custom.css);
#import url(chrome-extension://__MSG_##extension_id__/custom.css);
body { background-color: red!important; } /* change page background color to red */
custom.css (Rules in this file are supposed to be applied but not):
body { border: 20px solid red!important; } /* add a 20px border around the body. */
a { background-color: blue!important; } /* change all link's background color to blue. */
If you try to inject such a file into a tab, relative URLs take its origin.
I.e. if you try to inject this into http://example.com/test/index.html, then the above CSS will try to load http://example.com/test/custom.css.
If custom.css is packed in the extension, you should use absolute path obtained from chrome.runtime.getURL():
chrome.tabs.insertCSS(
tabId,
{ code : '#import url("' + chrome.runtime.getURL(custom.css) + '");' }
);
You may try to use the special constant ##extension_id:
#import url("chrome-extension://__MSG_##extension_id__/custom.css");
but I'm not 100% sure it'll work.
Lastly, make sure the imported CSS file is in web_accessible_resources.
#important doesn't work with tabs.insertCSS(). insertCSS seem to be interpreted before injection in the page. How they are interpreted is not documented. For example !important do not works neither.

Resources