mirror of
https://github.com/iconify/iconify.git
synced 2025-01-05 15:02:09 +00:00
chore: tailwind plugin redesign
This commit is contained in:
parent
3365d71a42
commit
f6eb380836
@ -6,42 +6,100 @@
|
||||
<link href="../dist/output.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body class="m-0 p-2">
|
||||
<p>
|
||||
Few icons that change color on hover (first icon also changes icon
|
||||
on hover):
|
||||
<span class="text-3xl demo">
|
||||
<section class="mb-2">
|
||||
<h1 class="text-2xl">Main plugin</h1>
|
||||
<p>
|
||||
Monotone icons (changes color, blue):
|
||||
<span class="text-2xl demo">
|
||||
<span class="iconify mdi-light--home"></span>
|
||||
<span
|
||||
class="iconify mdi-light--arrow-left text-blue-600"
|
||||
></span>
|
||||
<span
|
||||
class="iconify vscode-icons--file-type-light-ini text-blue-600"
|
||||
></span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
Color icons:
|
||||
<span class="text-2xl demo">
|
||||
<span class="iconify-color mdi-light--home"></span>
|
||||
<span
|
||||
class="iconify-color vscode-icons--file-type-firebase"
|
||||
></span>
|
||||
<span
|
||||
class="iconify-color vscode-icons--file-type-js-official"
|
||||
></span>
|
||||
</span>
|
||||
</p>
|
||||
</section>
|
||||
<section class="mb-2">
|
||||
<h1 class="text-2xl">Dynamic selectors plugin, custom options</h1>
|
||||
<p>Icons should scale to 1.5em, which is about 24px</p>
|
||||
<p>
|
||||
Monotone icons (red, blue):
|
||||
<span
|
||||
class="icon-[mdi-light--arrow-left] hover:icon-hover-[mdi-light--arrow-right]"
|
||||
class="custom-monotone i-mdi-light-home text-red-600"
|
||||
></span>
|
||||
<span class="icon-[mdi-light--forum]"></span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
Custom icons, imported from "svg" directory (first icon's animation
|
||||
slowed down using "customise" option):
|
||||
<span class="text-3xl demo">
|
||||
<span class="icon-[custom--spinner1]"></span>
|
||||
<span class="icon-[custom--spinner2]"></span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
Icons with hardcoded palette:
|
||||
<span class="text-3xl demo">
|
||||
<span
|
||||
class="icon-[vscode-icons--file-type-access] hover:icon-hover-[vscode-icons--file-type-access2]"
|
||||
class="custom-monotone i-custom-spinner1 text-blue-600"
|
||||
></span>
|
||||
<span class="icon-[vscode-icons--file-type-vue]"></span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
Clean selector:
|
||||
<span
|
||||
class="icon--mdi-light icon--mdi-light--home text-3xl demo"
|
||||
></span>
|
||||
</p>
|
||||
<p>
|
||||
Custom size:
|
||||
<span class="h-12 w-12 scaled-icon-[mdi-light--forum]"></span>
|
||||
</p>
|
||||
</p>
|
||||
<p>
|
||||
Failed icon (should not be pre-rendered):
|
||||
<span
|
||||
class="custom-monotone i-mdi-light-arrow-left text-red-600"
|
||||
></span>
|
||||
</p>
|
||||
<p>
|
||||
Colored icons:
|
||||
<span class="custom-background i-mdi-light-home"></span>
|
||||
<span class="custom-background i-custom-spinner2"></span>
|
||||
</p>
|
||||
</section>
|
||||
<section class="mb-2">
|
||||
<h1 class="text-2xl">Dynamic selectors plugin</h1>
|
||||
<p>
|
||||
Few icons that change color on hover (first icon also changes
|
||||
icon on hover):
|
||||
<span class="text-2xl demo">
|
||||
<span
|
||||
class="icon-[mdi-light--arrow-left] hover:icon-hover-[mdi-light--arrow-right]"
|
||||
></span>
|
||||
<span class="icon-[mdi-light--forum]"></span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
Custom icons, imported from "svg" directory (first icon's
|
||||
animation slowed down using "customise" option):
|
||||
<span class="text-2xl demo">
|
||||
<span class="icon-[custom--spinner1]"></span>
|
||||
<span class="icon-[custom--spinner2]"></span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
Icons with hardcoded palette:
|
||||
<span class="text-3xl demo">
|
||||
<span
|
||||
class="icon-[vscode-icons--file-type-access] hover:icon-hover-[vscode-icons--file-type-access2]"
|
||||
></span>
|
||||
<span class="icon-[vscode-icons--file-type-vue]"></span>
|
||||
</span>
|
||||
</p>
|
||||
</section>
|
||||
<section class="mb-2">
|
||||
<h1 class="text-2xl">Clean selectors plugin (deprecated)</h1>
|
||||
<p>
|
||||
Monotone icon: 1em size (changing color), text-2xl size (red):
|
||||
<span class="icon--mdi-light icon--mdi-light--home demo"></span>
|
||||
<span
|
||||
class="icon--mdi-light icon--mdi-light--home text-2xl text-red-600"
|
||||
></span>
|
||||
</p>
|
||||
<p>
|
||||
Custom size set via width/height:
|
||||
<span class="h-12 w-12 scaled-icon-[mdi-light--forum]"></span>
|
||||
</p>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,6 +1,7 @@
|
||||
const {
|
||||
addCleanIconSelectors,
|
||||
addDynamicIconSelectors,
|
||||
addIconSelectors,
|
||||
} = require('@iconify/tailwind');
|
||||
const {
|
||||
importDirectorySync,
|
||||
@ -59,6 +60,30 @@ customSet.forEachSync((name, type) => {
|
||||
module.exports = {
|
||||
content: ['./src/*.html'],
|
||||
plugins: [
|
||||
// Main plugin, default options
|
||||
addIconSelectors(['mdi-light', 'vscode-icons']),
|
||||
// Main plugin, custom options
|
||||
addIconSelectors({
|
||||
maskSelector: '.custom-monotone',
|
||||
backgroundSelector: '.custom-background',
|
||||
// Like UnoCSS
|
||||
iconSelector: '.i-{prefix}-{name}',
|
||||
scale: 1.5,
|
||||
prefixes: [
|
||||
{
|
||||
prefix: 'mdi-light',
|
||||
icons: ['home'],
|
||||
customise: (content) =>
|
||||
content.replace(/currentColor/g, '#40f'),
|
||||
},
|
||||
{
|
||||
prefix: 'custom',
|
||||
source: customSet.export(),
|
||||
customise: (content) =>
|
||||
content.replace(/currentColor/g, '#f20'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
// Plugin with clean selectors: requires writing all used icons in first parameter
|
||||
addCleanIconSelectors(['mdi-light:home']),
|
||||
// Plugin with dynamic selectors
|
||||
|
@ -1,21 +1,8 @@
|
||||
import type { IconCSSIconSetOptions } from '@iconify/utils/lib/css/types';
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
|
||||
// Callback for customising icon
|
||||
type IconifyCustomiseCallback = (
|
||||
content: string,
|
||||
name: string,
|
||||
prefix: string
|
||||
) => string;
|
||||
|
||||
// Callback for loading icon set
|
||||
type IconifyJSONLoaderCallback = () => IconifyJSON;
|
||||
|
||||
// Source for icon set: icon set, filename, or callback that loads icon set
|
||||
export type IconifyIconSetSource =
|
||||
| IconifyJSON
|
||||
| string
|
||||
| IconifyJSONLoaderCallback;
|
||||
// Source for icon set: icon set, filename, or synchronous callback that loads icon set
|
||||
export type IconifyIconSetSource = IconifyJSON | string | (() => IconifyJSON);
|
||||
|
||||
/**
|
||||
* Common options
|
||||
@ -26,7 +13,7 @@ export interface CommonIconifyPluginOptions {
|
||||
iconSets?: Record<string, IconifyIconSetSource>;
|
||||
|
||||
// Replace icon content
|
||||
customise?: IconifyCustomiseCallback;
|
||||
customise?: (content: string, name: string, prefix: string) => string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,26 +40,12 @@ export interface DynamicIconifyPluginOptions
|
||||
scale?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for reusable selectors
|
||||
*/
|
||||
export interface ReusableIconifyPluginOptions {
|
||||
// Selector for mask, defaults to ".iconify"
|
||||
mask?: string;
|
||||
|
||||
// Selector for background, defaults to ".iconify-color"
|
||||
background?: string;
|
||||
|
||||
// Variable name, defaults to "svg"
|
||||
varName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for main plugin
|
||||
*/
|
||||
|
||||
// Icons to include: array of names or callback
|
||||
type IconsListOption = string[] | ((name: string) => boolean);
|
||||
export type IconsListOption = string[] | ((name: string) => boolean);
|
||||
|
||||
// Source filename or icon set
|
||||
type IconSetSource = string | IconifyJSON;
|
||||
@ -88,16 +61,44 @@ interface IconSetOptions {
|
||||
|
||||
// Icons to load
|
||||
icons?: IconsListOption;
|
||||
|
||||
// Customise callback. If set, it will be used instead of global customise callback
|
||||
customise?: (content: string, name: string) => string;
|
||||
}
|
||||
|
||||
// Array of icon sets to load
|
||||
type IconifyPluginListOptions = (string | IconSetOptions)[];
|
||||
|
||||
// Full object
|
||||
export interface IconifyPluginOptionsObject
|
||||
extends ReusableIconifyPluginOptions {
|
||||
export interface IconifyPluginOptionsObject {
|
||||
// Selector for mask, defaults to ".iconify"
|
||||
// If empty string, mask selector will not be generated
|
||||
maskSelector?: string;
|
||||
|
||||
// Extra rules to add to mask selector
|
||||
extraMaskRules?: Record<string, string>;
|
||||
|
||||
// Selector for background, defaults to ".iconify-color"
|
||||
// If empty string, background selector will not be generated
|
||||
backgroundSelector?: string;
|
||||
|
||||
// Extra rules to add to background selector
|
||||
extraBackgroundRules?: Record<string, string>;
|
||||
|
||||
// Selector for icons, default is `.{prefix}--{name}`
|
||||
iconSelector?: string;
|
||||
|
||||
// Variable name that contains icon, defaults to "svg"
|
||||
varName?: string;
|
||||
|
||||
// Scale for icons, defaults to 1
|
||||
scale?: number;
|
||||
|
||||
// Prefixes to load
|
||||
prefixes: IconifyPluginListOptions;
|
||||
|
||||
// Customise callback
|
||||
customise?: (content: string, name: string, prefix: string) => string;
|
||||
}
|
||||
|
||||
// Full options
|
||||
|
@ -5,12 +5,13 @@ import type {
|
||||
CleanIconifyPluginOptions,
|
||||
DynamicIconifyPluginOptions,
|
||||
IconifyPluginOptions,
|
||||
IconifyPluginOptionsObject,
|
||||
} from './helpers/options';
|
||||
import { getCommonCSSRules } from '@iconify/utils/lib/css/common';
|
||||
import { getCSSRulesForPlugin } from './preparsed';
|
||||
|
||||
/**
|
||||
* Generate styles for dynamic selector: class="icon-[mdi-light--home]"
|
||||
* Generate styles for dynamic selector
|
||||
*
|
||||
* Usage in HTML: <span class="icon-[mdi-light--home]" />
|
||||
*/
|
||||
export function addDynamicIconSelectors(options?: DynamicIconifyPluginOptions) {
|
||||
const prefix = options?.prefix || 'icon';
|
||||
@ -28,8 +29,30 @@ export function addDynamicIconSelectors(options?: DynamicIconifyPluginOptions) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate rules for mask, background and selected icon sets
|
||||
*
|
||||
* Icons should combine either mask or background selector and icon selector
|
||||
*
|
||||
* This plugin generates only square icons. Icons that are not square will be resized to fit square.
|
||||
*
|
||||
* Usage in HTML: <span class="iconify mdi-light--home" />
|
||||
*/
|
||||
export function addIconSelectors(options: IconifyPluginOptions) {
|
||||
const rules = getCSSRulesForPlugin(options);
|
||||
return plugin(({ addUtilities }) => {
|
||||
addUtilities(rules);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate styles for preset list of icons
|
||||
*
|
||||
* Requires knowing full list of icons
|
||||
*
|
||||
* Usage in HTML: <span class="icon--mdi-light icon--mdi-light--home" />
|
||||
*
|
||||
* @deprecated Use addIconSelectors instead
|
||||
*/
|
||||
export function addCleanIconSelectors(
|
||||
icons: string[] | string,
|
||||
@ -41,49 +64,6 @@ export function addCleanIconSelectors(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iconify plugin
|
||||
*
|
||||
* TODO: export it when ready
|
||||
*/
|
||||
function iconifyPlugin(options: IconifyPluginOptions) {
|
||||
return plugin(({ addUtilities }) => {
|
||||
const rules = Object.create(null) as Record<
|
||||
string,
|
||||
Record<string, string>
|
||||
>;
|
||||
|
||||
// Convert options to object
|
||||
const fullOptions: IconifyPluginOptionsObject = Array.isArray(options)
|
||||
? {
|
||||
prefixes: options,
|
||||
}
|
||||
: options;
|
||||
|
||||
// Variable name, default to 'svg' (cannot be empty string)
|
||||
const varName = fullOptions.varName || 'svg';
|
||||
|
||||
// Add common rules
|
||||
const mask = fullOptions.mask ?? '.iconify';
|
||||
const background = fullOptions.background ?? '.iconify-color';
|
||||
if (mask) {
|
||||
rules[mask] = getCommonCSSRules({
|
||||
mode: 'mask',
|
||||
varName,
|
||||
});
|
||||
}
|
||||
if (background) {
|
||||
rules[background] = getCommonCSSRules({
|
||||
mode: 'background',
|
||||
varName,
|
||||
});
|
||||
}
|
||||
addUtilities(rules);
|
||||
|
||||
// TODO: add icon sets
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Export types
|
||||
*/
|
||||
|
155
plugins/tailwind/src/preparsed.ts
Normal file
155
plugins/tailwind/src/preparsed.ts
Normal file
@ -0,0 +1,155 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
import {
|
||||
generateItemCSSRules,
|
||||
getCommonCSSRules,
|
||||
} from '@iconify/utils/lib/css/common';
|
||||
import { defaultIconProps } from '@iconify/utils/lib/icon/defaults';
|
||||
import { parseIconSet } from '@iconify/utils/lib/icon-set/parse';
|
||||
import type {
|
||||
IconifyPluginOptions,
|
||||
IconifyPluginOptionsObject,
|
||||
IconsListOption,
|
||||
} from './helpers/options';
|
||||
import { loadIconSet } from './helpers/loader';
|
||||
|
||||
/**
|
||||
* Get CSS rules for main plugin
|
||||
*/
|
||||
export function getCSSRulesForPlugin(options: IconifyPluginOptions) {
|
||||
const rules = Object.create(null) as Record<string, Record<string, string>>;
|
||||
|
||||
// Convert options to object
|
||||
const fullOptions: IconifyPluginOptionsObject = Array.isArray(options)
|
||||
? {
|
||||
prefixes: options,
|
||||
}
|
||||
: options;
|
||||
|
||||
// Variable name, default to 'svg' (cannot be empty string)
|
||||
const varName = fullOptions.varName || 'svg';
|
||||
|
||||
// Scale icons
|
||||
const overrideRules: Record<string, string> = fullOptions.scale
|
||||
? {
|
||||
width: fullOptions.scale + 'em',
|
||||
height: fullOptions.scale + 'em',
|
||||
}
|
||||
: {};
|
||||
|
||||
// Add common rules
|
||||
const maskSelector = fullOptions.maskSelector ?? '.iconify';
|
||||
const backgroundSelector =
|
||||
fullOptions.backgroundSelector ?? '.iconify-color';
|
||||
if (maskSelector) {
|
||||
rules[maskSelector] = Object.assign(
|
||||
getCommonCSSRules({
|
||||
mode: 'mask',
|
||||
varName,
|
||||
}),
|
||||
overrideRules,
|
||||
fullOptions.extraMaskRules || {}
|
||||
);
|
||||
}
|
||||
if (backgroundSelector) {
|
||||
rules[backgroundSelector] = Object.assign(
|
||||
getCommonCSSRules({
|
||||
mode: 'background',
|
||||
varName,
|
||||
}),
|
||||
overrideRules,
|
||||
fullOptions.extraBackgroundRules || {}
|
||||
);
|
||||
}
|
||||
|
||||
// Add icon sets
|
||||
const iconSelector = fullOptions.iconSelector || '.{prefix}--{name}';
|
||||
|
||||
fullOptions.prefixes.forEach((item) => {
|
||||
let prefix: string;
|
||||
let iconSet: IconifyJSON | undefined;
|
||||
let iconsList: IconsListOption | undefined;
|
||||
let customise: ((content: string, name: string) => string) | undefined;
|
||||
|
||||
// Load icon set
|
||||
if (typeof item === 'string') {
|
||||
// Prefix
|
||||
prefix = item;
|
||||
iconSet = loadIconSet(prefix);
|
||||
} else if (item.source) {
|
||||
// Source, possibly with prefix
|
||||
iconSet = loadIconSet(item.source);
|
||||
prefix = item.prefix || iconSet?.prefix;
|
||||
iconsList = item.icons;
|
||||
customise = item.customise;
|
||||
if (!prefix) {
|
||||
throw new Error(
|
||||
'Custom icon set does not have a prefix. Please set "prefix" property'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Prefix
|
||||
prefix = item.prefix || iconSet?.prefix;
|
||||
iconSet = prefix ? loadIconSet(prefix) : undefined;
|
||||
iconsList = item.icons;
|
||||
customise = item.customise;
|
||||
}
|
||||
|
||||
// Validate it
|
||||
if (!iconSet) {
|
||||
throw new Error(
|
||||
`Cannot load icon set for "${prefix}". Install "@iconify-json/${prefix}" as dev dependency?`
|
||||
);
|
||||
}
|
||||
if (!prefix) {
|
||||
throw new Error(
|
||||
'Bad icon set entry, must have either "prefix" or "source" set'
|
||||
);
|
||||
}
|
||||
|
||||
// Load icons
|
||||
parseIconSet(iconSet, (name, data) => {
|
||||
// Check if icon should be rendered
|
||||
if (iconsList) {
|
||||
if (Array.isArray(iconsList)) {
|
||||
if (!iconsList.includes(name)) {
|
||||
return;
|
||||
}
|
||||
} else if (!iconsList(name)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Customise icon
|
||||
const body = customise
|
||||
? customise(data.body, name)
|
||||
: fullOptions.customise
|
||||
? fullOptions.customise(data.body, name, prefix)
|
||||
: data.body;
|
||||
|
||||
// Generate CSS
|
||||
const iconRules = generateItemCSSRules(
|
||||
{
|
||||
...defaultIconProps,
|
||||
...data,
|
||||
body,
|
||||
},
|
||||
{
|
||||
mode: 'mask', // not used because varName is set, but required
|
||||
varName,
|
||||
forceSquare: true,
|
||||
}
|
||||
);
|
||||
|
||||
// Generate selector
|
||||
const selector = iconSelector
|
||||
.replace('{prefix}', prefix)
|
||||
.replace('{name}', name);
|
||||
|
||||
// Add to rules
|
||||
rules[selector] = iconRules;
|
||||
});
|
||||
});
|
||||
|
||||
// Return
|
||||
return rules;
|
||||
}
|
Loading…
Reference in New Issue
Block a user