Dynamic TailwindCSS class is not working properly - vue.js

Considering my code:
<template>
<section
class="bg-gradient-to-br h-40"
:class="
'from-palettes-' +
palette +
'-primary to-palettes-' +
palette +
'-secondary'
"
>
Topbar
</section>
</template>
<script>
export default {
data: function () {
return {
menuOpen: false,
palette: "green-dark",
};
},
methods: {},
};
</script>
<style>
</style>
And my tailwind file:
extend: {
colors: {
palettes: {
"green-dark": {
primary: "#57876E", //dark color
secondary: "#92BFA8", //light color
gray: "#333453",
accent: "#f8f2f2", //slight offset from white
white: "#FAF9FA",
},
},
},
},
Color is not loaded. When I check the console there are no errors, when I check source code, the class name is applied as it should. The corresponding class is however not found/applied. What am I doing wrong?

The most important implication of how Tailwind extracts class names is
that it will only find classes that exist as complete unbroken strings
in your source files.
If you use string interpolation or concatenate partial class names
together, Tailwind will not find them and therefore will not generate
the corresponding CSS.
https://tailwindcss.com/docs/content-configuration#dynamic-class-names

Related

customize a color in tailwind.config.js file

I am currently building an VUE application. There I need to customize the primary color in litepie-datepicker to #A7F3D0(emerald series) in my tailwind.config.js file.
I tried theses codes. But nothing is working
'litepie-primary':'#A7F3D0', // color system for light mode
'litepie-secondary': colors.coolGray // color system for dark mode
'litepie-primary': colors.emerald[200], // color system for light mode
'litepie-secondary': colors.coolGray // color system for dark mode
This is my tailwind.config.js file
const path = require('path');
const colors = require('tailwindcss/colors');
module.exports = {
purge: [
"./src/**/*.php",
"./src/**/*.html",
"./src/**/*.vue",
"./resources/**/*.php",
"./resources/**/*.html",
"./node_modules/#left4code/tw-starter/**/*.js",
path.resolve(__dirname, './node_modules/litepie-datepicker/**/*.js')
],
darkMode: 'class', // or 'media' or 'class'
theme: {
extend: {
width: {
'1/7': '14.2857143%',
},
colors: {
'primary': '#00a69c',
'secondary': '#343a40',
'litepie-primary': colors.emerald, // color system for light mode
'litepie-secondary': colors.coolGray // color system for dark mode
}
},
},
variants: {
extend: {
cursor: ['disabled'],
textOpacity: ['disabled'],
textColor: ['disabled']
},
},
plugins: [],
}
I search questions already on StackOverflow but didn't find a satisfying answer. I hope someone answers this.
Thank you in advance.
Litepie Datepicker already set litepie-primary as emerald. You can check it on their Github repository
// lines 20, 21
'litepie-primary': colors.emerald,
'litepie-secondary': colors.coolGray
As a primary color (color of selected date) they are using litepie.primary[500] which is rgb(16, 185, 129). My guess you need to change this color. I will show only relevant to colors part of your config
const colors = require('tailwindcss/colors');
// Change '500' key. To make it noticeable I'll change it to red
colors.emerald[500] = 'red';
module.exports = {
...
theme: {
extend: {
colors: {
'litepie-primary': colors.emerald
}
}
}
...
}
Let's check
<div class="text-litepie-primary-50">50</div>
<div class="text-litepie-primary-100">100</div>
<div class="text-litepie-primary-200">200</div>
<div class="text-litepie-primary-300">300</div>
<div class="text-litepie-primary-400">400</div>
<div class="text-litepie-primary-500">500 This should be red</div>
<div class="text-litepie-primary-600">600</div>
<div class="text-litepie-primary-700">700</div>
<div class="text-litepie-primary-800">800</div>
<div class="text-litepie-primary-900">900</div>
To make it #A7F3D0 you can pass it directly as a string or by default color
// colors.emerald[500] = '#A7F3D0';
colors.emerald[500] = colors.emerald[200];
Alternatively if you wish to change whole pallete to your customs provide object with Tailwind's keys
module.exports = {
theme: {
extend: {
colors: {
'litepie-primary': {
50: '#color50',
100: '#color100',
...
900: '#color900'
}
}
}
}
}

Vue JS props is underfined

Im using Gridsome frame work for VUE JS
I am navigating to a new page by using this.$router.push(PATH, PARAMS)
this.$router.push({path: `/${value.sectionLink}/`, params: {pageOBJ: value}})
The page route works fine - however the PROP, pageOBJ is undefined in the page as seen in the VUE inspector:
it should be an object (which is what VALUE is set to) i.e.
I've tried a number of different techniques to resolve this but have not managed to figure this out so I assume I have missed something here?
gridsome auto generates the page routes when you add a new PAGE.VUE file to the /pages folder -
Is this the issue?
Gridsome also references graphQI, are you supposed to grab the data using graph and not by pushing Props?
Any help would be amazing here - please let me know if you need any further information.
Thanks -
W
UPDATE BASED ON CURRENT ANSWERS:
I have already added props:true to the component as shown below, but the issue is still present.
CODE SNIPPET - SUMMARY:
User clicks on the SectionTitle component, this then emits the page link
(each of the SectionTitle is a object from : sections array of Object)
To see the current online version of this please look at
wtwd.ninjashotgunbear.com
<template>
<Layout>
<div class="navs" v-for="section in sections" :key="section.sectionTitle">
<!-- On click delay for screen to come ove top -->
<!-- router to be put here -->
<SectionTitle :data="section" #routeChange="reRoute($event)"/>
</div>
<PageTransition :dataObj="transitionObj"/>
</Layout>
</template>
<script>
import SectionTitle from '#/components/SectionTitle.vue';
import PageTransition from '#/components/PageTransition.vue'
export default {
metaInfo: {
title: 'Hello, world!'
},
components: {
SectionTitle,
PageTransition
},
data(){
return {
// data to be passed to the components
sections: [
{
sectionTitle: 'Clients',
sectionLink: 'clients',
sectionSubTitle: '"Some of the amazing humans I have had the pleasure of working with"',
backgroundColor: '#F08080',
titleColor: '#E65454'
},
{
sectionTitle: 'Projects',
sectionLink: 'projects',
sectionSubTitle: '"I LIKE TO MAKE PROJECTS THAT WILL TEST MY KNOWEDGE AND EXPOSE MY WEAKNESSES"',
backgroundColor: '#20B2AA',
titleColor: '#11DACF'
},
{
sectionTitle: 'Skills',
sectionLink: 'skills',
sectionSubTitle: `"LEARNING WILL NEVER END, SO LONG AS YOUR AMBITIONS ARE STOKED, AND I've got plenty of ambition"`,
backgroundColor: '#A921B2',
titleColor: '#CA14D6'
},
{
sectionTitle: 'About Me',
sectionLink: 'aboutme',
sectionSubTitle: `"My joruney becoming a developer so far"`,
backgroundColor: '#FFFFFF',
titleColor: '#D1D1D1'
},
{
sectionTitle: 'Contact Me',
sectionLink: 'contactme',
sectionSubTitle: `"If you have any questions or want to reach out about a project then i'd love to speak with you"`,
backgroundColor: '#2185B2',
titleColor: '#0076AB'
}
],
divText: null,
transitionObj: null
}
},
methods:{
reRoute(value){
// 1)A) - change the text of the div to say the section it is being moved to
this.divText = value.sectionTitle
this.transitionObj = value
// FIND center pixcle value to place text - scrolled height + windowHeight / 2 = centerPos
let centerPos = window.scrollY+(window.innerHeight/2)
// Apply secific Title color - and center possitioning
document.querySelector('.leaveScreen p').style.cssText=`color: ${value.titleColor}; top: ${centerPos}px`
// 1) animate the loading screen
let screen = document.querySelector('.leaveScreen');
screen.style.cssText=`background: ${value.backgroundColor}; left: 0%`;
// 2) re-route the page
setTimeout(()=>{
this.$router.push({path: `/${value.sectionLink}/`, params: {pageOBJ: value}}) // << says that the route name is not found
// this.$router.push(value.sectionLink)
}, 700)
}
}
}
</script>
<style lang="scss">
// **** ERROR CAUSED BY NOT INSTALLING SCSS package ****
// https://gridsome.org/docs/assets-css/ &&&& npm install -D sass-loader node-sass
// Universal Font being used - LEMON MILK
#font-face {
font-family: LemonMilk;
src: url('../assets/fonts/LemonMilk.otf');
}
* {
box-sizing: border-box;
}
.navs {
font-family: LemonMilk;
}
.SectionTitle{
cursor: pointer;
}
</style>
Pass name rather than path in this.$router.push()
this.$router.push({name: ${value.sectionLink}, params: {pageOBJ: value}})
You should add props:true to the route definition :
{
path:'/thepath/:theParam',
component:SomeComponent,
props:true
}

Vue: Using material-design-icons offline / size

I am using materialdesignicons in my vue project.
require ('../node_modules/#mdi/font/css/materialdesignicons.min.css);
Vue.use(Vuetify, {iconfont:'mdi'});
I have a handful of icons which I dynamically create:
<v-icon>{{ some-mdi-file }}</v-icon>
When I build for production via (npm run build) I get the following error:
asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
img/materialdesignicons-webfont.someHash.svg (3.77 MiB)
That file size is huge because it includes every icon, regardless of whether it's being used. Is there a way to trim that file size down by only packaging the specific icons used. Is there a different package I should be using? Caveat: The project is hosted offline, so I need to include the fonts directly in my project.
I looked at vue-material-design-icons but it looks like it may not work for dynamic icon names and it says nothing about the overall file size/performance.
I have also looked here but clicking on the 'size warning' link brings me to a page where the Vue portion is not filled out
https://dev.materialdesignicons.com/getting-started/webfont
I would recommend using the #mdi/js package for this which provides SVG paths for each icon and supports tree shaking. Currently Vuetify doesn't support SVG icons but it should in the future.
For now, it's easy enough to create a custom icon component:
<template>
<svg :class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path :d="path" />
</svg>
</template>
<script>
export default {
name: 'my-icon',
data: () => ({
path: '',
}),
methods: {
updatePath() {
if (!this.$scopedSlots) return
if (typeof this.$scopedSlots.default !== 'function') return
this.path = this.$scopedSlots
.default()
.map((n) => n.text)
.join('')
},
},
mounted() {
this.updatePath()
},
updated() {
this.updatePath()
},
}
</script>
<style scoped>
.icon {
display: block;
color: inherit;
fill: currentColor;
width: 24px;
height: 24px;
}
<style>
Then to use it you just need to import your component and the icon you want to use:
<template>
<div class="app">
<my-icon>{{mdiCheck}}</my-icon>
</div>
</template>
<script>
import MyIcon from 'path/to/my/icon.vue'
import { mdiCheck } from '#mdi/js'
export default {
name: 'my-app',
components: {
MyIcon,
}
data: () => ({
mdiCheck,
}),
}
</script>

Is it possible to print a chart with vue-chartjs?

I am using vue-chartjs to render graphs on a webapp. I know you can print charts if you are using the original library. However I have no idea on how to do it with the vue version of the library.
I have my charts variable on an external charts.js file
import {Bar, mixins } from 'vue-chartjs'
Chart.defaults.global
let chartOptions = Chart.defaults.global;
const { reactiveProp } = mixins
export default {
extends: Bar,
mixins: [reactiveProp],
props: ['options'],
mounted () {
let that = this;
that.chartOptions = {
scales: {
yAxes: [{
ticks: {
suggestedMin: 0,
fontFamily: "'Overpass_Mono', 'Monaco', monospace",
fontColor: "rgba(254, 255, 248, 0.5)"
},
gridLines: {
color: 'rgba(255, 80, 248, 0.08)',
zeroLineColor: 'rgb(168, 119, 181)',
zeroLineWidth: 2
},
}],
xAxes: [{
ticks: {
suggestedMin: 0,
fontColor: "rgb(168, 119, 181)"
},
gridLines: {
color: 'rgba(255, 80, 248, 0.08)',
zeroLineColor: 'transparent',
}
}],
},
legend: {
labels: {
fontColor: 'rgb(168, 119, 181)',
}
}
},
this.renderChart(this.chartData, that.chartOptions)
}
}
Then on my component template I have:
<template>
<div class="report">
<charts v-if="todaySelected"
:chart-id="'total_visits_chart_bar'"
:height="chartsHeight"
:options="chartOptions"
:chart-data="datacollection"
></charts>
<div v-if="todaySelected">
<button #click="printChart(charts)">Print chart</button>
</div>
</template>
<script>
import charts from './chart_0.js'
components: {
charts,
},
data() {
return{
datacollection: {"datasets":[{"label":"Entries Today","data":[15,15,15,0]},{"label":"Currently Inside","data":[2,2,2,0]}],"labels":[]}
}
}.
methods: {
printChart(charts) {
charts.print();
},
}
</script>
Any help would be appreciated.
The answer is: Yes, it is. Your print method in the components' script could be:
methods:{
printChart() {
var canvasEle = document.getElementById('total_visits_chart_bar');
var win = window.open('', 'Print', 'height=600,width=800');
win.document.write("<br><img src='" + canvasEle.toDataURL() + "' />");
setTimeout(function(){ //giving it 200 milliseconds time to load
win.document.close();
win.focus()
win.print();
win.location.reload()
}, 200);
},
}
You can also add this to your component's style:
#media print{
#page {
size: landscape
}
}
vue-chartjs is based on chart.js and not canvas.js, thus it does not have a "build-in" way of printing.
You have to do it with some custom logic and the native javascript printing functions.
You can however grab the canvas element inside your chart component and generate for example an image and then print that image.
It will get a bit tricky, because you only have access to the canvas inside your chart component. So you will need to maybe wait for an event or prop to trigger the toDataURL call and then emit the image to your parent component where you can print it. If you want to trigger the print in your parent component.
methods: {
print () {
// grab the canvas and generate an image
let image = this.$refs.canvas.toDataURL('image/png')
// Emits an event with the image
this.$emit('chart:print', image)
}
}
In your parent component:
<template>
<your-chart #chart:print="handlePrint"
<template/>
....
...
methods: {
handlePrint(image) {
const win = window.open('', 'Print', 'height=600, width=800')
win.document.write(`<br><img src='${image}' />`)
win.print()
win.close()
}
}
It seems like the library is based on chartjs not canvasjs https://www.chartjs.org/docs/latest/ you might want to look into how to print a window Quick Print HTML5 Canvas, and remember you have access to the canvas element where your graph is drawn:
methods: {
printChart() {
const canvasEle = this.$el.querySelector('canvas');
//now your chart image is on canvasEle
},
}
If you are not against using export to pdf format, you can implement this task using jsPDF library, for example:
<template>
<div class="report">
<charts v-if="todaySelected"
:chart-id="'total_visits_chart_bar'"
:height="chartsHeight"
:options="chartOptions"
:chart-data="datacollection"
></charts>
</div>
</template>
<script>
import jsPDF from 'jspdf'; //for PDF printing
methods: {
pdfThatThing : function(){
//Default export is a4 paper, portrait, using milimeters for units
let pdfName = 'test';
var doc = new jsPDF();
doc.text("Header", 20, 20); //at x,y at def.units 2cm
//chart element
let canvasEle = document.getElementById('total_visits_chart_bar');
let chartURL = canvasEle.toDataURL(); //transform path
//a4 page is 209mm, adds at 4cm top, 2cm left, for 15cm in size
doc.addImage(chartURL, 'PNG', 20, 40, 150, 150 )
doc.save(pdfName + '.pdf');
},
}
</script>
There is also option to auto show print dialog in pdf viewer:
doc.autoPrint({variant: 'non-conform'})

Using custom theming in Vuetify and pass color variables to components

In my index.js file I have manually override the Vuetify theme object with my company's color:
Vue.use(Vuetify, {
theme: {
primary: '#377ef9',
secondary: '#1b3e70',
accent: '#ff643d',
error: '#ff643d'
...
}
Now, I can use these colors from my templates like so:
<my-text-field name="input text"
label="text"
value="text text text text..."
type="text"
color="primary">
</my-text-field>
What I'm after is using the primary or any other variable in the theme object defined above, inside my template style:
<script>
import { VTextField } from 'vuetify'
export default {
extends: VTextField
}
</script>
<style scoped lang="stylus">
label
color: <seconday color> <-- this is what I'm after
color: #1b3e70 <-- this works, but not quite good enough for me
</style>
I can easily just write the hex value of my colors in the style section, but I don't want to repeat myself, and would rather use my theme object so it will also be easier for my to easily change the colors everywhere, and avoid typos which will lead to mistakes in the colors definitions.
Edit (2018/10/11)
Since version 1.2. we can enable CSS variables
NOTE: allegedly it won't work in IE (Edge should work), and possibly some Safari versions?
From docs (see Custom Properties)
Enabling customProperties will also generate a css variable for each
theme color, which you can then use in your components'
blocks.
Vue.use(Vuetify, {
options: {
customProperties: true
}
})
<style scoped>
.something {
color: var(--v-primary-base)
background-color: var(--v-accent-lighten2)
}
</style>
For custom values e.g.
yourcustomvariablename: '#607D8B'
use --v-yourcustomvariablename-base (so base is default).
Original answer:
There is a Feature Request on github: Access theme colors in stylus files
#KaelWD (one of devs) wrote:
This is something you'll have to implement yourself. I've tried doing
something similar before but it doesn't really work on a framework
level.
Issue is labeled wontfix
Edit (2018/10/11)
Also see this updated thread:
https://github.com/vuetifyjs/vuetify/issues/827 (Feature request: Native css variables)
There is a way to go around this by utilizing :style attributes. It can be used to set custom CSS properties reactively.
Add a computed property:
computed: {
cssProps () {
return {
'--secondary-color': this.$vuetify.theme.secondary
}
}
Bind style to cssProps:
<div id="app" :style="cssProps">
Then, in your style:
<style scoped>
label
color: var(--secondary-color);
</style>
Adapted from this discussion: https://github.com/vuejs/vue/issues/7346
For anyone stumbling over this from Vuetify V2 onwards, you can do the following to get access to the SCSS colour variables.
// Import the Vuetify styles somewhere global
#import '~vuetify/src/styles/styles.sass';
// Now in your components you can access the colour variables using map-get
div {
background: map-get($grey, lighten-4);
}
All the colours can be found in /node_modules/vuetify/styles/settings/_colors.scss.
From above answers, if you want to include all vuetify colors, put this code in App.vue template
<v-app :style="cssProps">
App.vue script
computed: {
cssProps () {
var themeColors = {}
Object.keys(this.$vuetify.theme.themes.light).forEach((color) => {
themeColors[`--v-${color}`] = this.$vuetify.theme.themes.light[color]
})
return themeColors
}
}
Let say if you have this color in vuetify.js
export default new Vuetify({
treeShake: true,
theme: {
themes: {
light: {
darkRed: "#CD3300",
}
}
}
})
Then, in any component:
<style scoped>
.label {
color: var(--v-darkRed);
}
</style>
Maybe I am late the most efficient way to do is as mentioned in the docs https://vuetifyjs.com/en/features/theme/#custom-properties
I will provide a working example for the same.
you need only three changes to be done for this to get working.
Mention the option which does the magic and your theme color
export default new Vuetify({
theme: {
options: {
customProperties: true
},
themes: {
light: {
primary: "#3DCFD3",
secondary: "#171b34",
accent: "3D87E4"
}
}
}
});
Mention the class name in the tag where you want your theme to get applied
<h4 class="blue-header">Yash Oswal</h4>
CSS to apply your theme.
<style lang="scss">
.blue-header {
color: var(--v-primary-base);
}
</style>
For vutify 3+:
inside vuetify.js file declare theme color variable colors:{green:'#00ff00'}
// src/plugins/vuetify.js
import { createApp } from 'vue'
import { createVuetify } from 'vuetify'
export default createVuetify({
theme: {
defaultTheme: 'myCustomTheme',
themes: {
myCustomTheme: {
dark: false,
colors: {
..., // We have omitted the standard color properties here to emphasize the custom one that we've added
green: '#00ff00'
}
}
}
}
})
inside .vue component file use rgb(var(--v-theme-green)):
<template>
<div class="custom-class">background color with appropriate text color contrast</div>
</template>
<style>
.custom-class {
background: rgb(var(--v-theme-green))
}
</style>
Example of switching theme (helpfull link):
<v-app :dark="setTheme"
:style="{background: $vuetify.theme.themes[theme].background}"
>
JS:
computed: {
setTheme() {
this.$vuetify.theme.dark = this.goDark;
}
},
data() {
return {
goDark: false
}
}