eleventy-plugin-phosphoricons
Version:
A flexible icon family for interfaces, diagrams, presentations — whatever, really.
148 lines (116 loc) • 5.36 kB
JavaScript
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { createRequire } from 'module';
import { parseHTML } from 'linkedom';
const require = createRequire(import.meta.url);
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const phosphorIcons = JSON.parse(fs.readFileSync(path.join(__dirname, 'icons.json'), 'utf8'));
export default (eleventyConfig, attributes = {}) => {
const defaultAttributes = {
class: `phicon`,
render: `svg`,
loading: `lazy`,
decoding: `async`,
altPrefix: `icon`,
eleventyIgnore: true,
transformClass: false,
transformFill: undefined
}
const globalAttributes = { ...defaultAttributes, ...attributes };
const phosphorCorePath = path.join(
path.dirname(require.resolve("@phosphor-icons/core")),
"../assets"
);
const shortcodeHandler = (iconName, iconType = 'regular', attributesOrClasses = {}) => {
if (!iconName) {
throw new Error(
"[eleventy-plugin-phosphoricons] the iconName must be specified"
);
}
// Handle 3rd arg: string = extra classes, object = attributes
let attributes = {};
if (typeof attributesOrClasses === 'string' && attributesOrClasses.trim()) {
// Liquid-style: {% phicon "icon" "type" "extra-classes" %}
const defaultClass = globalAttributes.class || '';
attributes.class = defaultClass ? `${defaultClass} ${attributesOrClasses}` : attributesOrClasses;
} else if (typeof attributesOrClasses === 'object' && attributesOrClasses !== null) {
// Nunjucks-style: {% phicon "icon", "type", { size: 64 } %}
attributes = attributesOrClasses;
}
attributes = { ...globalAttributes, ...attributes };
attributes.render = attributes.render.toLowerCase();
if (!['regular', 'thin', 'light', 'bold', 'fill', 'duotone'].includes(iconType)) {
iconType = 'regular';
}
const fileName = iconType === 'regular' ? iconName : `${iconName}-${iconType}`;
if (!phosphorIcons[iconType].includes(fileName)) {
throw new Error(
`[eleventy-plugin-phosphoricons] the iconName "${iconName}" does not exist in the ${iconType} type`
);
}
// warning if render not supported
if (!['svg', 'image', 'img'].includes(attributes.render)) {
attributes.render = 'svg';
console.warn(`[eleventy-plugin-phosphoricons] the render attribute must be one of the following: svg, image, img. Defaulting to svg.`);
}
if (typeof attributes.transformFill === 'function' && attributes.transformClass) {
try {
attributes.fill = attributes.transformFill(attributes.transformClass);
} catch (error) {
console.warn(`[eleventy-plugin-phosphoricons] the transformFill function failed: ${error}`);
console.warn(`[eleventy-plugin-phosphoricons] the attributes.transformClass will be ignored`);
}
}
// safety get SVG content
const svgContent = fs.readFileSync(
path.join(phosphorCorePath, `./${iconType}/${fileName}.svg`),
"utf8"
);
const { document } = parseHTML(svgContent);
const svgIcon = document.querySelector('svg');
if (attributes.render === 'svg') {
if (attributes.class) {
svgIcon.setAttribute('class', attributes.class);
}
// Remove the icon from the accessibility tree
svgIcon.setAttribute('aria-hidden', 'true');
}
if (attributes.style) {
svgIcon.setAttribute('style', attributes.style);
}
if (attributes.size) {
svgIcon.setAttribute('width', attributes.size);
svgIcon.setAttribute('height', attributes.size);
}
if (attributes.fill) {
svgIcon.setAttribute('fill', attributes.fill);
}
let iconString = svgIcon.outerHTML;
if (['image', 'img'].includes(attributes.render)) {
let defaultAltText = attributes.altPrefix ? [attributes.altPrefix, iconName] : [iconName];
let imageAttributes = {
src: `data:image/svg+xml,${encodeURIComponent(iconString)}`,
width: attributes.size,
height: attributes.size,
loading: attributes.loading,
decoding: attributes.decoding,
alt: attributes.alt || defaultAltText.join(' '),
"aria-hidden": true,
};
if (attributes.eleventyIgnore) {
imageAttributes["eleventy:ignore"] = true;
}
if (attributes.style) {
imageAttributes.style = attributes.style;
}
if (attributes.class) {
imageAttributes.class = attributes.class;
}
iconString = `<img ${Object.keys(imageAttributes).map(key => `${key}="${imageAttributes[key]}"`).join(' ')} />`;
}
return iconString.trim();
};
eleventyConfig.addShortcode("phosphor", shortcodeHandler);
eleventyConfig.addShortcode("phicon", shortcodeHandler);
};