Generating TailwindCSS safelist with function? - tailwind-css

I'm attempting to generate a safelist for TailWindCSS 3.0.23 using a function so I can cover some ranges.
For some reason, the classes still seem to be purged.
module.exports = {
content: ['./app/**/*.php', './resources/**/*.{php,vue,js}'],
safelist: function(){
let list = [
'user-administrator:not(.wp-admin)',
];
for(let i = 0; i <= 100; i += 5 ){
list[list.length] = 'opacity-' + i;
}
return list;
},
Is this type of thing possible? Any ideas?

You could the following code in javascript.
const tailwindColors = require("./node_modules/tailwindcss/colors")
const colorSafeList = []
// Skip these to avoid a load of deprecated warnings when tailwind starts up
const deprecated = ["lightBlue", "warmGray", "trueGray", "coolGray", "blueGray"]
for (const colorName in tailwindColors) {
if (deprecated.includes(colorName)) {
continue
}
// Define all of your desired shades
const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900]
const pallette = tailwindColors[colorName]
if (typeof pallette === "object") {
shades.forEach((shade) => {
if (shade in pallette) {
// colorSafeList.push(`text-${colorName}-${shade}`) <-- You can add different colored text as well
colorSafeList.push(`bg-${colorName}-${shade}`)
}
})
}
}
// tailwind.config.js
module.exports = {
safelist: colorSafeList, // <-- add the safelist here
content: ["{pages,app}/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
colors: tailwindColors,
},
},
plugins: [],
}

I ended up solving this by adding a pair of parenthesis after the closing bracket of the function so it executes.
module.exports = {
content: ['./app/**/*.php', './resources/**/*.{php,vue,js}'],
safelist: function(){
let list = [
'user-administrator:not(.wp-admin)',
];
for(let i = 0; i <= 100; i += 5 ){
list[list.length] = 'opacity-' + i;
}
return list;
}(),

Related

FullCalendar angular

I'm using FullCalendar in angular and I would like to change the specific day grid background I have tried some options but it didn't work.
HTML
<full-calendar #calendar [options]="calendarOptions"></full-calendar>
TS
export class CalendarComponent implements OnInit{
calendarData: CalendarData[] = [];
calendarVisible = false;
calendarOptions: CalendarOptions = {
headerToolbar: {
right: 'title,prev,next',
center: '',
left: 'timeGridDay,timeGridWeek,dayGridMonth'
},
initialView: 'dayGridMonth',
eventColor: '#F4C584',
};
#ViewChild('calendar') calendarComponent!: FullCalendarComponent;
isData = false;
calendarPlugins = [listPlugin,dayGridPlugin,timeGridPlugin]
getCalendar(): void{
this.calendarService.getCalendar(2022).subscribe((res) => {
this.calendarOptions.events = [];
const data = Object.entries(res.data).map((val: any) => {
return val;
});
for(let i = 0; i < data.length; i++){
console.log(data[i][0]);
for(let j = 0; j < data[i][1].length; j++){
this.calendarOptions.events.push( //here I'm pushing into event options array my data
{
title : data[i][1][j].date.split(' ')[0],
date: data[i][0]
background: '#000000' //I tried to give a color like this but it didn't work
});
}
}
});
}
link to the full calendar
Had the same problem and I discovered that FullCalendar styles for Angular just work after the page is rendered, meaning, if you apply the style into your styles.scss it will work :)
For example, i did this:
.fc .fc-daygrid-day.fc-day-today {
background-color: rgb(229, 248, 225, 0.5) !important;
}
Hope that it helps :)
If you use bootstrap in your project, then u must use ": host ::ng-deep" before the property u want to modify in the CSS file. This works I have applied it.
e.g. :- : host:: ng-deep color: '#ffffff'

Change font size and font color in Chartjs Angular 5

Font color in chartjs is light gray, then when you want to print from page, it does not appear.
I change the font color of chartjs in options attribute, but it does not work.
How can I change the font color in chartjs angular
public options:any = {
legend: {
labels: {
// This more specific font property overrides the global property
fontColor: 'red',
fontSize: '30'
}
}
};
in template :
<canvas baseChart
height=100
[datasets]="barChartData"
[labels]="barChartLabels"
[options]="barChartOptions"
[legend]="barChartLegend"
[colors]="chartColors"
[chartType]="barChartType"
[options]="options"
>
</canvas>
I use chartjs like following in ts file.
This is my complete ts file:
import { Component, Input, OnInit } from '#angular/core';
import { Test } from './models/test.model';
#Component({
selector: 'app-customer-report-test',
templateUrl: './customer-report-test.component.html',
styleUrls: ['./customer-report-test.component.css']
})
export class CustomerReportTestComponent implements OnInit {
#Input('test') test: Test = new Test();
public barChartOptions:any = {
scaleShowVerticalLines: false,
responsive: true
};
public barChartLabels:string[];
public barChartType:string = 'bar';
public barChartLegend:boolean = true;
public barChartData:any[];
backgroundColorList: string[];
public chartColors: any[] = [
{
backgroundColor: this.backgroundColorList
}];
public options:any;
constructor() { }
//----------------------------------------------------------------------------
ngOnInit() {
//set Label
this.barChartLabels = [];
for(let i=1; i<= this.test.data_array.length; i++){
this.barChartLabels.push('' + i);
}
//set data chart
this.barChartData = [{data: this.test.data_array, label: this.test.test_type[1]}]
this.test.test_type[1]}, {data: [20,20, 20, 20],type: "line",label: ['0', '1', '2', '3'] ,fill:'none'}]
// set color to line according to state_array
this.backgroundColorList = [];
if(this.test.state_array.length != 0){
for(let i=0; i<this.test.data_array.length; i++){
if(this.test.state_array[i] == 0){
this.backgroundColorList.push('#069ed6');
}else if(this.test.state_array[i] == 1){
this.backgroundColorList.push('#F5482D');
}else if(this.test.state_array[i] == 2){
this.backgroundColorList.push('#CAC409');
}
}
}
else{
for(let d of this.test.data_array){
this.backgroundColorList.push('#069ed6');
}
}
this.chartColors = [
{
backgroundColor: this.backgroundColorList
}];
this.options = {
responsive: true,
title: {
display: true,
text: 'Custom Chart Title'
},
legend: {
display: true,
labels: {
fontColor: 'red'
}
}
};
}
}
for changing the color of numbers and lines in coordinate plane,we can do:
for example in xAxes:
xAxes: [{
gridLines: {
display: true,
color: "red" // this here
},
ticks: {
fontColor: "red", // this here
}
}],
and font and color of labels:
legend: {
display: true,
labels:{
fontSize: 10,
fontColor: 'red',
}
},
DEMO.
You may try to edit the source code.
1. Go to the link /node_modules/chart.js/src/core/core.js in your node modules folder.
2. edit the following code i.e the core.js file. change the
defaultFontColor: '#0000ff'
to any color you want. I have implemented this in my code for pie chart. and it worked.
`
defaults._set('global', {
responsive: true,
responsiveAnimationDuration: 0,
maintainAspectRatio: true,
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
hover: {
onHover: null,
mode: 'nearest',
intersect: true,
animationDuration: 400
},
onClick: null,
defaultColor: 'rgba(0,0,0,0.1)',
defaultFontColor: '#0000ff',
defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
defaultFontSize: 12,
defaultFontStyle: 'normal',
showLines: true,
// Element defaults defined in element extensions
elements: {},
// Layout options such as padding
layout: {
padding: {
top: 0,
right: 0,
bottom: 0,
left: 0
}
}
});
module.exports = function() {
// Occupy the global variable of Chart, and create a simple base class
var Chart = function(item, config) {
this.construct(item, config);
return this;
};
Chart.Chart = Chart;
return Chart;
};`

Can we restrict CSS keyframe animations to a scope

I wonder if it's possible to restrict keyframe animations to a scope based on classnames. The benefit would be to be able to use the same animation-name multiple times without getting issues. I couldn't find any infos about that..
In case it's not possible:
are there any best practices to handle naming conflicts?
I used to use something like SCSS to generate automatically created names for my keyframes. They might not be as descriptive, but they ensure uniqueness. Something like:
$animation-id-count: 0 !global;
#function animation-id {
$animation-id-count: $animation-id-count + 1;
#return animation-id-#{$animation-id-count};
}
After this, just use the function in your code like this:
.class {
$id: animation-id();
#keyframes #{$id}{
...keyframes
}
animation: $id 1s infinite;
}
That way if you insert it anywhere else in your SCSS or move it, it will still match the right animation, and it stops namespaces from overlapping in any way.
Here is a JSX approach (you will need object-hash for that).
The following example shows how to define different animations with respective unique ID based on transform: scale(n). For that purpose, define a function which returns the keyframes and its ID. The keyframes ID is a custom string suffixed with a hash of the function options (e.g. the scale factor).
(Be careful of CSS custom identifier, e.g. do not include a . in your ID. See MDN: < custom-ident >.)
import hash from "object-hash";
const keyFramesScale = (options = {}) => {
let { transforms, id, scale } = options;
transforms = transforms || "";
scale = scale || 1.25;
const keyFramesId = `scale${id ? "-" + id : ""}-${hash(options).substring(0, 6)}`;
const keyFrames = {
[`#keyframes ${keyFramesId}`]: {
"100%": {
transform: `scale(${scale}) ${transforms}`,
},
"0%": {
transform: `scale(1) ${transforms}`,
}
}
};
return [keyFramesId, keyFrames];
};
How to use it:
const [scaleUpId, keyFramesScaleUp] = keyFramesScale({ scale: 1.25, transforms: "rotate(-30deg)", id: "up" });
const [scaleDownId, keyFramesScaleDown] = keyFramesScale({ scale: 0.75, transforms: "rotate(-30deg)", id: "down" });
// scaleUpId = "scale-up-c61254"
// scaleDownId = "scale-down-6194d5"
// ...
<tag style={{
...keyFramesScaleUp,
...keyFramesScaleDown,
...(!hasTouchScreen && isActive && !isClicked && {
animation: `${scaleUpId} 0.5s infinite alternate linear`,
"&:hover": {
animation: "none",
},
}),
...(isClicked && {
animation: `${scaleDownId} .25s 1 linear`,
}),
}} />
Of course, you can write a more generic function that hashes the whole key frames and assign it an ID based on that.
EDIT
To concretize what has been said, here is the generic approach. We first define a generic function that takes an animation name (e.g. scale, pulse, etc.), its keyframes (which can be an object or a function), and optionally keyframes parameters and its default values.
import hash from "object-hash";
const createKeyFramesId = (id, keyFrames) => {
return `${id}-${hash(keyFrames).substring(0, 6)}`;
};
const genericKeyFrames = (name, keyFrames, defaults = {}, options = {}) => {
if (typeof keyFrames === "function") {
// The order of defaults & options is important: the latter overrides the former.
keyFrames = keyFrames({ ...defaults, ...options });
}
const keyFramesId = createKeyFramesId(name, keyFrames);
const keyFramesObject = {
[`#keyframes ${keyFramesId}`]: keyFrames
};
return [keyFramesId, keyFramesObject];
};
From now on, we can define all kind of animations. Their usage is the same as above.
export const keyFramesPulse = () =>
genericKeyFrames("pulse", {
"100%": {
opacity: "1",
},
"0%": {
opacity: "0.5",
},
});
export const keyFramesRotate = (options = {}) => {
const defaults = {
rotate: 360,
transforms: "",
};
const rotateKeyFrames = ({ rotate, transforms }) => {
return {
"100%": {
transform: `rotate(${rotate}deg) ${transforms}`,
}
}
};
return genericKeyFrames(`rotate`, rotateKeyFrames, defaults, options);
};
export const keyFramesScale = (options = {}) => {
const defaults = {
scale: 1.25,
transforms: ""
};
const scaleKeyFrames = ({ scale, transforms }) => {
return {
"100%": {
transform: `scale(${scale}) ${transforms}`,
},
"0%": {
transform: `scale(1) ${transforms}`,
}
}
};
return genericKeyFrames(`scale`, scaleKeyFrames, defaults, options);
};
What it looks like in DevTools:

Scripted Dashboard in Grafana with opentsdb as the source

I want to create a scripted dashboard that takes one OpenTSDB metric as the datasource. On the Grafana website, I couldn't find any example. I hope I can add some line like:
metric = 'my.metric.name'
into the JavaScript code, and than I can access the dashboard on the fly.
var rows = 1;
var seriesName = 'argName';
if(!_.isUndefined(ARGS.rows)) {
rows = parseInt(ARGS.rows, 10);
}
if(!_.isUndefined(ARGS.name)) {
seriesName = ARGS.name;
}
for (var i = 0; i < rows; i++) {
dashboard.rows.push({
title: 'Scripted Graph ' + i,
height: '300px',
panels: [
{
title: 'Events',
type: 'graph',
span: 12,
fill: 1,
linewidth: 2,
targets: [
{
'target': "randomWalk('" + seriesName + "')"
},
{
'target': "randomWalk('random walk2')"
}
],
}
]
});
}
return dashboard;
Sorry to answer my own question. But I just figured it out and hopefully post here will benefit somebody.
The script is here. Access the dashboard on the fly with:
http://grafana_ip:3000/dashboard/script/donkey.js?name=tsdbmetricname
/* global _ */
/*
* Complex scripted dashboard
* This script generates a dashboard object that Grafana can load. It also takes a number of user
* supplied URL parameters (in the ARGS variable)
*
* Return a dashboard object, or a function
*
* For async scripts, return a function, this function must take a single callback function as argument,
* call this callback function with the dashboard object (look at scripted_async.js for an example)
*/
// accessible variables in this scope
var window, document, ARGS, $, jQuery, moment, kbn;
// Setup some variables
var dashboard;
// All url parameters are available via the ARGS object
var ARGS;
// Intialize a skeleton with nothing but a rows array and service object
dashboard = {
rows : [],
};
// Set a title
dashboard.title = 'From Shrek';
// Set default time
// time can be overriden in the url using from/to parameters, but this is
// handled automatically in grafana core during dashboard initialization
dashboard.time = {
from: "now-6h",
to: "now"
};
var rows = 1;
var metricName = 'argName';
//if(!_.isUndefined(ARGS.rows)) {
// rows = parseInt(ARGS.rows, 10);
//}
if(!_.isUndefined(ARGS.name)) {
metricName = ARGS.name;
}
for (var i = 0; i < rows; i++) {
dashboard.rows.push({
title: metricName,
height: '300px',
panels: [
{
title: metricName,
type: 'graph',
span: 12,
fill: 1,
linewidth: 2,
targets: [
{
"aggregator": "avg",
"downsampleAggregator": "avg",
"errors": {},
"metric":ARGS.name,
//"metric": "search-engine.relevance.latency.mean",
"tags": {
"host": "*"
}
}
],
tooltip: {
shared: true
}
}
]
});
}
return dashboard;

How to integrate syntax check in Ace Editor using custom mode?

I'm new to ace-editor and I have included custom mode to validate my code and every line should end up with semicolon, If semicolon is not present in my query by mistake then the editor should gives up the warning like "Missing Semicolon".
define('ace/mode/javascript-custom', [], function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var ExampleHighlightRules = require("ace/mode/example_highlight_rules").ExampleHighlightRules;
var Mode = function() {
this.HighlightRules = ExampleHighlightRules;
};
oop.inherits(Mode, TextMode);
(function() {
this.lineCommentStart = "--";
this.blockComment = {
start: "->",
end: "<-"
};
}).call(Mode.prototype);
exports.Mode = Mode;
});
define('ace/mode/example_highlight_rules', [], function(require, exports, module) {
var oop = require("ace/lib/oop");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var ExampleHighlightRules = function() {
var keywordMapper = this.createKeywordMapper({
"variable.language": "this",
"keyword": "one|two",
"constant.language": "true|false|null"
}, "text", true);
this.$rules = {
"start": [{
token: "comment",
regex: "->",
next: [{
regex: "<-",
token: "comment",
next: "start"
}, {
defaultToken: "comment"
}]
}, {
regex: "\\w+\\b",
token: keywordMapper
}, {
token: "comment",
regex: "--.*"
}, {
token: "string",
regex: '"',
next: [{
regex: /\\./,
token: "escape.character"
}, {
regex: '"',
token: "string",
next: "start"
}, {
defaultToken: "string"
}]
}, {
token: "numbers",
regex: /\d+(?:[.](\d)*)?|[.]\d+/
}]
};
this.normalizeRules()
};
oop.inherits(ExampleHighlightRules, TextHighlightRules);
exports.ExampleHighlightRules = ExampleHighlightRules;
});
var langTools = ace.require("ace/ext/language_tools");
var editor = ace.edit("editor");
editor.session.setMode("ace/mode/javascript-custom");
editor.setOptions({
enableBasicAutocompletion: true,
enableLiveAutocompletion: true
});
editor.setTheme("ace/theme/monokai");
var lines = editor.session.doc.getAllLines();
var errors = [];
for (var i = 0; i < lines.length; i++) {
if (/[\w\d{(['"]/.test(lines[i])) {
alert("hello");
errors.push({
row: i,
column: lines[i].length,
text: "Missing Semicolon",
type: "error"
});
}
}
<script src="https://ajaxorg.github.io/ace-builds/src/ext-language_tools.js"></script>
<script src="https://ajaxorg.github.io/ace-builds/src/ace.js"></script>
<div id="editor" style="height: 200px; width: 400px"></div>
<div id="commandline" style="position: absolute; bottom: 10px; height: 20px; width: 800px;"></div>
UPDATE:
The following js files are generated from ace and added to my rails application, the files are loaded in rails app but the functionality (semicolon check) doesn't seem to be working.
worker-semicolonlineend - http://pastebin.com/2kZ2fYr9
mode-semicolonlineend - http://pastebin.com/eBY5VvNK
Update:
In ace editor, type in a query1, query2 in line 1 and line 2 respectively
Leave the third line blank
Now in fourth line, type a query without semicolon in the end, x mark appears in third line
5 And when the fifth line is also without a semicolon, then the x mark is displayed at fourth query
Ace editor widely support this kind analysis for JavaScript by default:
#editor {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
<div id="editor">function foo() { ; // unnessesary semicolon
var x = "bar" // missing semicolon
return x; // semicolon in place
}
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js" type="text/javascript"></script>
<script>
var editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.getSession().setMode("ace/mode/javascript");
</script>
Just make sure that worker file worker-javascript.js is available for your code. In code snippet above I use CDN to get Ace build, so worker is always available. You can configure JSHint via worker options.
Update: But if really need something beyond that you will need to do the following as my understanding goes:
Create Worker and Mode for you kind of analysis
Download Ace source code and install NodeJS
Put your new files within correspond Ace source code folders
Build Ace
Add build files to your project
Use new mode: editor.getSession().setMode("ace/mode/semicolonlineend");
Worker that perform line ending check will look something like that:
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var Mirror = require("../worker/mirror").Mirror;
var SemicolonLineEndCheckWorker = exports.SemicolonLineEndCheckWorker = function (sender) {
Mirror.call(this, sender);
this.setTimeout(500);
this.setOptions();
};
oop.inherits(SemicolonLineEndCheckWorker, Mirror);
(function() {
this.onUpdate = function () {
var text = this.doc.getValue();
var lines = text.replace(/^#!.*\n/, "\n").match(/[^\r\n]+/g);
var errors = [];
for (var i = 0; i < lines.length; i++) {
var lastLineCharacter = lines[i].trim().slice(-1);
if (lastLineCharacter === ';')
continue;
errors.push({
row: i,
column: lines[i].length-1,
text: "Missing semicolon at the end of the line",
type: "warning",
raw: "Missing semicolon"
});
}
this.sender.emit("annotate", errors);
};
}).call(SemicolonLineEndCheckWorker.prototype);
});
New mode that uses worker:
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var TextMode = require("./text").Mode;
var Mode = function() { };
oop.inherits(Mode, TextMode);
(function() {
this.createWorker = function(session) {
var worker = new WorkerClient(["ace"], "ace/mode/semicolonlineend_worker",
"SemicolonLineEndCheckWorker");
worker.attachToDocument(session.getDocument());
worker.on("annotate", function(results) {
session.setAnnotations(results.data);
});
worker.on("terminate", function() {
session.clearAnnotations();
});
return worker;
};
this.$id = "ace/mode/semicolonlineend";
}).call(Mode.prototype);
exports.Mode = Mode;
});

Resources