Working with Tailwind
In this section, we are going to dive inside the tailwind.config.js
file located at the root of the project. Everything happens there, so we need to give you all the info you'll need to be able to customize it for your needs.
Configuration imports
The tailwind configuration file starts with commonjs (using require
instead of import
) import statements:
const colors = require('tailwindcss/colors')
const plugin = require('tailwindcss/plugin')
We are doing 2 things:
- We first load the
colors
object from tailwind to be able to access the native colors later in the config file - We then load the
plugin
object to be able to use tailwind plugins later in the file.
Dark mode & Content
We then take care of configuring the Dark mode as well as the files to parse, looking for tailwind classnames tocompile in the final bundle:
module.exports = {
darkMode: 'class',
content: [
'./src/layouts/**/*.{html,js}',
'./src/partials/**/*.{html,js}',
'./src/root/**/*.{html,js}',
],
// ...rest of config
}
We are doing 2 things:
- We are first telling tailwind to use the
class
implementation of the dark mode. This means that when the dark mode is toggled, a.dark
class is added to thehtml
DOM element, affecting all the application styles and colors. See Tailwind docs for more details about dark mode.
<!--Dark mode disabled-->
<html></html>
<!--Dark mode enabled-->
<html class="dark"></html>
- We then tell tailwind to look for classes to compile inside all files residing inside the
src/layouts
,src/partials
andsrc/root
folders, including files ending with.html
and.js
extensions. Learn more about content parsing by taking a look at the Tailwind docs.
Extending the base theme
The tailwind configuration file provides a very convenient way of overwriting the default theme and set your own variables. Everything related to theme customization goes inside the extend theme section of the configuration file:
module.exports = {
// ...previous config elements
theme: {
extend: {
// The theme configuration goes here.
}
}
// ...rest of config
}
There are several things we can change in there. If you want more details about the tailwind configuration, you can always read the dedicated section of the Tailwind docs. Let's get back to Finity and deep dive in each subsection of the theme configuration.
Breakpoints
In Tailwind CSS, responsive breakpoints are known as screens
. Being a mobile first framework, screens are set in an ascending manner, so you alway design mobile first. Here is the defaul Tailwind configuration:
module.exports = {
// ...previous config elements
theme: {
extend: {
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
xxl: '1536px',
},
}
}
// ...rest of config
}
While the defaults are pretty satisfying, we though that we could tweak them a little bit to get the most out of it, and to be able to face those very particular edge cases that come up from time to time. Here is Finity's screens configuration:
module.exports = {
// ...previous config elements
theme: {
extend: {
screens: {
xs: { max: '639px' },
sm: '640px',
md: '768px',
lg: '1025px',
xl: '1280px',
xxl: '1536px',
ptablet: {
raw: '(min-width: 768px) and (max-width: 1024px) and (orientation: portrait)',
},
ltablet: {
raw: '(min-width: 768px) and (max-width: 1024px) and (orientation: landscape)',
},
},
}
}
// ...rest of config
}
Let's go through the changes we've made. We've added an xs
screen that, opposed to the others that follow an ascending pattern, is capped to 639px
to face some very rare edge cases where you'd like to have something only applied on very small screens. We've also decided to push the lg
breakpoint to 1025px
instead of 1024px
to exclude landscape tablets from desktop display, simply because there is not as much room on a landscape tablet as there is on a desktop screen, implying therefore layout adjustments between the two. And finally, we've added two raw screens called ptblet
(stands for portrait tablet) and ltablet
(stands for landscape tablet) to handle specific layouts rendered in both orientations at maximum design quality.
Colors
Tailwind CSS provides a very advanced and fully customizable color system. If you don't know anything about Tailwind colors, we recommend that you take a look at . the Tailwind docs to learn more about them. In Finity, we use the theme section of the configuration file to configure our own colors, that we will be using in the template. It also means, that you can do the same thing to change all the template colors to match your branding. Here is the color configuration of Finity:
module.exports = {
// ...previous config elements
theme: {
extend: {
colors: {
slate: {
1000: '#0a101f',
},
gray: {
1000: '#080c14',
},
zinc: {
1000: '#101012',
},
neutral: {
1000: '#080808',
},
stone: {
1000: '#0f0d0c',
},
muted: colors.slate,
primary: colors.indigo,
info: colors.sky,
success: colors.teal,
warning: colors.amber,
danger: colors.rose,
},
}
}
// ...rest of config
}
Tailwind CSS provides 22 prebuilt colors, each one having 10 different shades, from the lightest one to the darkest one. Let's talk about some of our choices. First, even if the system is pretty complete, we felt it needed an additional really darker shade to enhance dark mode renders. Therefore we decided to add an additional shade to the gray based Tailwind colors.
WARNING
Consider the slate
, gray
, zinc
, neutral
and stone
colors like base grey-ish backgrounds and tints for your design system and UI elements. Avoid at all costs mixing them as it will affect the consistency of your color system. Instead use one of those consistently throughout your design.
Following the gold rule in the above warning, we've decided to abstract the gray color we want to use for the template inside the muted
variable.
muted: colors.slate,
That simply is a shortcut to use our slate color through the template without taking the risk of mixing with another tint of gray. Therefore, instead of doing:
<span class="text-slate-600"></span>
We now simply write:
<span class="text-muted-600"></span>
Yeah, we pretty much know what you're going to say: "Hold on, this is pretty and nice, but how is it going to help me with my development? What benefit is this bringing?".
- First, you don't take the risk of mixing unconsistent gray shades, having
gray
in some parts,slate
in others, and maybestone
somewhere else. The main gray shade is abstracted in themuted
color variable and prevents any potential errors, like when multiple people work on the same project. - Second, if you want to change the overall look of your app, you can do it anytime. You just need to switch the color linked to the
muted
variable, like this:
// If you want a slate dominant in your layout
muted: colors.slate,
// If you want a gray dominant in your layout
muted: colors.gray,
// If you want a zinc dominant in your layout
muted: colors.zinc,
// If you want a neutral dominant in your layout
muted: colors.neutral,
// If you want a stone dominant in your layout
muted: colors.stone,
we use the same mecahnism to abstract other colors that you might need in a web project, like a primary
color or other colors like success
and danger
that symbolize some application states. You can configure those colors as shortcuts as well:
//The template primary color
primary: colors.indigo,
//The blue-ish info state
info: colors.sky,
//The green-ish success state
success: colors.teal,
//The orange-ish warning state
warning: colors.amber,
//The red-ish danger state
danger: colors.rose,
Therefore, instead of using the indigo color, we abstract it to primary:
<!--You shouldn't do that-->
<span class="text-indigo-600"></span>
<!--This is the right way-->
<span class="text-primary-600"></span>
You should now have a good understanding of how colors work in Finity. Take a look at how we use them inside the template to get a more precise idea of the possibilities.
Fonts
Tailwind CSS provides a very simple way to abstract your fonts, like we did with colors. If you don't know anything about Tailwind font families, we recommend that you take a look at the Tailwind docs to learn more about how to configure and use them. In Finity, we use the theme section of the configuration file to configure our own fonts. It also means, that you can do the same thing to change all the template fonts to match your branding. Here is the color configuration of Finity:
module.exports = {
// ...previous config elements
theme: {
extend: {
fontFamily: {
sans: ['Roboto Flex', 'sans-serif'],
heading: ['Inter', 'sans-serif'],
},
}
}
// ...rest of config
}
We are doing 2 things:
- We are first telling tailwind to overwrite its base
sans
font stack and to useRoboto flex
instead. You then simply call this font in your templates by using thefont-sans
class expression. - We then add a new utility for headings that is using the
Inter
font. You then call this font in your templates by using thefont-heading
class expression.
You could also follow the same pattern if you want to customize the native font-serif
and font-mono
stacks that Tailwind provides by default. You could add something like this in the configuration above:
module.exports = {
// ...previous config elements
theme: {
extend: {
fontFamily: {
serif: ['Some Font Name', 'serif'],
mono: ['Some Font Name', 'monospace'],
},
}
}
// ...rest of config
}
Typography
While we just saw how we can configure fonts in Finity, we also need to start talking about a particular Tailwind plugin, the typography
plugin. This plugin is made to facilitate styling of user generated content areas, like blog posts for instance. This controls how native Html elements without any CSS classes are styled and rendered. This is what Finity uses to style the content inside the blog post page. The section related to typography in the tailwind config file is bigger than the others, as you pretty much have to setup everything, as well as the dark mode styles:
module.exports = {
// ...previous config elements
theme: {
extend: {
typography: ({ theme }) => ({
DEFAULT: {
css: {
color: theme('colors.muted.600'),
'[class~="lead"]': {
color: theme('colors.muted.400'),
},
h2: {
fontFamily: theme('fontFamily.heading'),
fontWeight: 700,
color: theme('colors.muted.800'),
},
h3: {
fontFamily: theme('fontFamily.heading'),
fontWeight: 500,
color: theme('colors.muted.800'),
},
h4: {
fontFamily: theme('fontFamily.heading'),
fontWeight: 500,
fontSize: '1.25em',
color: theme('colors.muted.800'),
},
hr: {
borderColor: theme('colors.muted.200'),
},
li: {
fontSize: '1.15rem',
color: theme('colors.muted.600'),
padding: '0.35rem 0',
},
strong: {
color: theme('colors.muted.800'),
},
em: {
color: theme('colors.muted.500'),
fontSize: '1.1rem',
lineHeight: 1,
},
blockquote: {
fontSize: '1.1rem',
lineHeight: 1.4,
fontWeight: 500,
color: theme('colors.muted.500'),
borderLeftColor: theme('colors.primary.500'),
background: theme('colors.muted.100'),
padding: '1.75rem',
},
pre: {
fontFamily: theme('fontFamily.mono'),
},
code: {
fontFamily: theme('fontFamily.mono'),
background: theme('colors.primary.100'),
color: theme('colors.primary.500'),
padding: '0.35rem',
fontWeight: 600,
fontSize: '0.95rem !important',
},
},
},
dark: {
css: {
color: theme('colors.muted.400'),
'[class~="lead"]': {
color: theme('colors.muted.300'),
},
h2: {
color: theme('colors.muted.100'),
},
h3: {
color: theme('colors.muted.100'),
},
h4: {
color: theme('colors.muted.100'),
},
hr: {
borderColor: theme('colors.muted.800'),
},
li: {
color: theme('colors.muted.400'),
},
strong: {
color: theme('colors.muted.300'),
},
em: {
color: theme('colors.muted.400'),
},
blockquote: {
color: theme('colors.muted.200'),
background: theme('colors.muted.800'),
},
},
},
}),
}
}
// ...rest of config
}
See how the typography: ({ theme }) => ({})
function uses the theme
variable to gain access to Tailwind classes and utilities you defined earlier in your theme. We are using the css-in-js
syntax to style all native html elements like h1
, h2
, blockquote
, strong
or li
. We are then nesting an additional configuration inside the dark
property to style for dark mode.
Keyframes
Keyframes are animation definitions written in CSS. While Tailwind provides many of these out-of-the-box, we still needed to add specific ones for our template, using that theme configuration section of the tailwind.config.js
file:
module.exports = {
// ...previous config elements
theme: {
extend: {
keyframes: {
indeterminate: {
'0%': { 'margin-left': '-10%' },
'100%': { 'margin-left': '100%' },
},
placeload: {
'0%': { 'background-position': '-468px 0' },
'100%': { 'background-position': '468px 0' },
},
},
}
}
// ...rest of config
}
We extend the Tailwind default keyframes by adding two of our own, indeterminate
(to animate indeterminate progress bars) and placeload
(to animate placeload elements), that we will be using in the animations section.
animations
Like we saw in the previous section, we've added some new keyframes. We're now going to use them in new animation we are also going to add to Tailwind CSS.
module.exports = {
// ...previous config elements
theme: {
extend: {
animation: {
indeterminate: 'indeterminate 1s cubic-bezier(0.4, 0, 0.2, 1) infinite',
placeload: 'placeload 1s linear infinite forwards',
},
}
}
// ...rest of config
}
We are declaring the indeterminate
and placeload
animation that make use of the keyframes we've defined earlier. We also add the animation-timing-function
and duration
properties, like in traditional CSS. Once our animations are added, we can then simply use them in our Html template by calling the animate-indeterminate
or the animate-placeload
classes.
plugins
Like we saw in the very first section of this page, we are first importing the tailwind plugin object to be able to use plugins later in our configuration file.
const plugin = require('tailwindcss/plugin')
We can then use this plugin definition to actually load our plugins into Tailwind CSS. Keep in mind that those plugins need to be installed via npm
or it will result in an error when running the project.
module.exports = {
// ...previous config elements
theme: {
extend: {
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/line-clamp'),
require('@tailwindcss/aspect-ratio'),
require('@vidstack/player/tailwind.cjs'),
]
}
}
// ...rest of config
}
In the sample above, we are loading the typography
plugin, which we saw earlier, as well as the line-clamp
, aspect ratio
and @vidstack
plugins.
- The typography plugin is in charge of styling user generated Html or markdown content. You can read more about it in the official Tailwind documentaion.
- The line-clamp plugin is in charge of truncating lines of text, wether on a single or multi-line basis. You can read more about it in the official Tailwind blog.
- The aspect-ratio plugin is in charge of rendering correct aspect ratios like
1:1
,4:3
or16:9
. You can read more about it in the official Tailwind documentation. - The @vidstack plugin is an external plugin in charge of making the
@vidstack
video player compatible with Tailwind styling. You can read more about it in the official @vidstack player documentation.
Adding plugin utilities
we can also use the plugin object to add flat utilities directly in the config file:
module.exports = {
// ...previous config elements
theme: {
extend: {
plugins: [
plugin(function ({ addUtilities }) {
addUtilities({
'.slimscroll::-webkit-scrollbar': {
width: '6px',
},
'.slimscroll::-webkit-scrollbar-thumb': {
borderRadius: '.75rem',
background: 'rgba(0, 0, 0, 0.1)',
},
'.slimscroll-opaque::-webkit-scrollbar-thumb': {
background: 'rgba(0, 0, 0, 0) !important',
},
'.mask': {
'mask-size': 'contain',
'mask-repeat': 'no-repeat',
'mask-position': 'center',
},
// ...Other utilities added
})
}),
]
}
}
// ...rest of config
}
The classes added above will are available everywhere in the project and are also compatible with the Tailwind responsive-variants
that rely on the breakpoints you've defined earlier.
Adding plugin components
we can also use the plugin object to add flat CSS components directly in the config file:
module.exports = {
// ...previous config elements
theme: {
extend: {
plugins: [
plugin(function ({ addComponents }) {
addComponents({
'.placeload': {
position: 'relative',
background:
'linear-gradient(to right, rgb(0 0 0 / 7%) 8%, rgb(0 0 0 / 15%) 18%, rgb(0 0 0 / 7%) 33%)',
'background-size': '800px 104px',
color: 'transparent !important',
},
'.dark .placeload': {
background:
'linear-gradient(to right, rgb(255 255 255 / 15%) 8%, rgb(255 255 255 / 24%) 18%, rgb(255 255 255 / 15%) 33%)',
},
})
}),
]
}
}
// ...rest of config
}
The classes added above will are available everywhere in the project. They work like traditional CSS and you could as well chose not adding them here but direclty in the postcss
files located in src/root/postcss
instead. Also, keep in mind that unlike the plugin utility classes
we've added earlier, these component utilities are do not generate responsive-variants
.
Complete configuration
That's it! Now that we've been through the entire Tailwing configuration file, you should have a solid understanding of what's happening in there, how to make changes to adapt it to your context and to get the most out of it. Here is the complete configuration that we've been through:
const colors = require('tailwindcss/colors')
const plugin = require('tailwindcss/plugin')
module.exports = {
darkMode: 'class',
content: [
'./src/layouts/**/*.{html,js}',
'./src/partials/**/*.{html,js}',
'./src/root/**/*.{html,js}',
],
theme: {
extend: {
screens: {
xs: { max: '639px' },
sm: '640px',
md: '768px',
lg: '1025px',
xl: '1280px',
xxl: '1536px',
ptablet: {
raw: '(min-width: 768px) and (max-width: 1024px) and (orientation: portrait)',
},
ltablet: {
raw: '(min-width: 768px) and (max-width: 1024px) and (orientation: landscape)',
},
},
colors: {
slate: {
1000: '#0a101f',
},
gray: {
1000: '#080c14',
},
zinc: {
1000: '#101012',
},
neutral: {
1000: '#080808',
},
stone: {
1000: '#0f0d0c',
},
muted: colors.slate,
primary: colors.indigo,
info: colors.sky,
success: colors.teal,
warning: colors.amber,
danger: colors.rose,
},
fontFamily: {
sans: ['Roboto Flex', 'sans-serif'],
heading: ['Inter', 'sans-serif'],
},
typography: ({ theme }) => ({
DEFAULT: {
css: {
color: theme('colors.muted.600'),
'[class~="lead"]': {
color: theme('colors.muted.400'),
},
h2: {
fontFamily: theme('fontFamily.heading'),
fontWeight: 700,
color: theme('colors.muted.800'),
},
h3: {
fontFamily: theme('fontFamily.heading'),
fontWeight: 500,
color: theme('colors.muted.800'),
},
h4: {
fontFamily: theme('fontFamily.heading'),
fontWeight: 500,
fontSize: '1.25em',
color: theme('colors.muted.800'),
},
hr: {
borderColor: theme('colors.muted.200'),
},
li: {
fontSize: '1.15rem',
color: theme('colors.muted.600'),
padding: '0.35rem 0',
},
strong: {
color: theme('colors.muted.800'),
},
em: {
color: theme('colors.muted.500'),
fontSize: '1.1rem',
lineHeight: 1,
},
blockquote: {
fontSize: '1.1rem',
lineHeight: 1.4,
fontWeight: 500,
color: theme('colors.muted.500'),
borderLeftColor: theme('colors.primary.500'),
background: theme('colors.muted.100'),
padding: '1.75rem',
},
pre: {
fontFamily: theme('fontFamily.mono'),
},
code: {
fontFamily: theme('fontFamily.mono'),
background: theme('colors.primary.100'),
color: theme('colors.primary.500'),
padding: '0.35rem',
fontWeight: 600,
fontSize: '0.95rem !important',
},
},
},
dark: {
css: {
color: theme('colors.muted.400'),
'[class~="lead"]': {
color: theme('colors.muted.300'),
},
h2: {
color: theme('colors.muted.100'),
},
h3: {
color: theme('colors.muted.100'),
},
h4: {
color: theme('colors.muted.100'),
},
hr: {
borderColor: theme('colors.muted.800'),
},
li: {
color: theme('colors.muted.400'),
},
strong: {
color: theme('colors.muted.300'),
},
em: {
color: theme('colors.muted.400'),
},
blockquote: {
color: theme('colors.muted.200'),
background: theme('colors.muted.800'),
},
},
},
}),
keyframes: {
indeterminate: {
'0%': { 'margin-left': '-10%' },
'100%': { 'margin-left': '100%' },
},
placeload: {
'0%': { 'background-position': '-468px 0' },
'100%': { 'background-position': '468px 0' },
},
stroke: {
'100%': { 'stroke-dashoffset': '0' },
},
scale: {
0: { transform: 'scale(0)', opacity: 0 },
'100%': { transform: 'scale(1)', opacity: 1 },
},
kenburns: {
0: { 'background-size': '120% auto' },
'50%': { 'background-size': '100% auto' },
'100%': { 'background-size': '120% auto' },
},
stripemove: {
to: {
transform: 'rotateX(45deg) translate(0) skew(-60deg)',
},
},
},
animation: {
indeterminate: 'indeterminate 1s cubic-bezier(0.4, 0, 0.2, 1) infinite',
placeload: 'placeload 1s linear infinite forwards',
circle: 'stroke 1.2s cubic-bezier(0.65, 0, 0.45, 1) forwards',
check: 'stroke 0.9s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards',
scale: 'scale 0.5s linear 0.5s forwards',
kenburns: 'kenburns 12s linear infinite reverse',
wheel: 'spin 3s linear infinite',
rotation: 'spin 1.5s infinite linear reverse',
stripemove: 'stripemove 0.5s linear infinite',
},
},
},
variants: {
extend: {},
},
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/line-clamp'),
require('@tailwindcss/aspect-ratio'),
require('@vidstack/player/tailwind.cjs'),
plugin(function ({ addUtilities }) {
addUtilities({
'.slimscroll::-webkit-scrollbar': {
width: '6px',
},
'.slimscroll::-webkit-scrollbar-thumb': {
borderRadius: '.75rem',
background: 'rgba(0, 0, 0, 0.1)',
},
'.slimscroll-opaque::-webkit-scrollbar-thumb': {
background: 'rgba(0, 0, 0, 0) !important',
},
'.mask': {
'mask-size': 'contain',
'mask-repeat': 'no-repeat',
'mask-position': 'center',
},
'.mask-hex': {
'mask-image':
"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE4MiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNjQuNzg2IDE4MS40Yy05LjE5NiAwLTIwLjA2My02LjY4Ny0yNS4wNzktMTQuMjFMMy43NjIgMTA1LjMzYy01LjAxNi04LjM2LTUuMDE2LTIwLjkgMC0yOS4yNTlsMzUuOTQ1LTYxLjg2QzQ0LjcyMyA1Ljg1MSA1NS41OSAwIDY0Ljc4NiAwaDcxLjA1NWM5LjE5NiAwIDIwLjA2MyA2LjY4OCAyNS4wNzkgMTQuMjExbDM1Ljk0NSA2MS44NmM0LjE4IDguMzYgNC4xOCAyMC44OTkgMCAyOS4yNThsLTM1Ljk0NSA2MS44NmMtNC4xOCA4LjM2LTE1Ljg4MyAxNC4yMTEtMjUuMDc5IDE0LjIxMUg2NC43ODZ6Ii8+PC9zdmc+')",
},
'.mask-hexed': {
'mask-image':
"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgyIiBoZWlnaHQ9IjIwMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNLjMgNjUuNDg2YzAtOS4xOTYgNi42ODctMjAuMDYzIDE0LjIxMS0yNS4wNzhsNjEuODYtMzUuOTQ2YzguMzYtNS4wMTYgMjAuODk5LTUuMDE2IDI5LjI1OCAwbDYxLjg2IDM1Ljk0NmM4LjM2IDUuMDE1IDE0LjIxMSAxNS44ODIgMTQuMjExIDI1LjA3OHY3MS4wNTVjMCA5LjE5Ni02LjY4NyAyMC4wNjMtMTQuMjExIDI1LjA3OWwtNjEuODYgMzUuOTQ1Yy04LjM2IDQuMTgtMjAuODk5IDQuMTgtMjkuMjU4IDBsLTYxLjg2LTM1Ljk0NUM2LjE1MSAxNTcuNDQuMyAxNDUuNzM3LjMgMTM2LjU0VjY1LjQ4NnoiLz48L3N2Zz4=')",
},
'.mask-deca': {
'mask-image':
"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkyIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNOTYgMGw1OC43NzkgMTkuMDk4IDM2LjMyNyA1MHY2MS44MDRsLTM2LjMyNyA1MEw5NiAyMDBsLTU4Ljc3OS0xOS4wOTgtMzYuMzI3LTUwVjY5LjA5OGwzNi4zMjctNTB6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=')",
},
'.mask-blob': {
'mask-image':
"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAwIDBDMjAgMCAwIDIwIDAgMTAwczIwIDEwMCAxMDAgMTAwIDEwMC0yMCAxMDAtMTAwUzE4MCAwIDEwMCAweiIvPjwvc3ZnPg==')",
},
'.mask-diamond': {
'mask-image':
"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTAwIDBsMTAwIDEwMC0xMDAgMTAwTDAgMTAweiIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+')",
},
})
}),
plugin(function ({ addComponents }) {
addComponents({
'.placeload': {
position: 'relative',
background:
'linear-gradient(to right, rgb(0 0 0 / 7%) 8%, rgb(0 0 0 / 15%) 18%, rgb(0 0 0 / 7%) 33%)',
'background-size': '800px 104px',
color: 'transparent !important',
},
'.dark .placeload': {
background:
'linear-gradient(to right, rgb(255 255 255 / 15%) 8%, rgb(255 255 255 / 24%) 18%, rgb(255 255 255 / 15%) 33%)',
},
})
}),
],
}