mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-22 16:59:48 +02:00
embed free font awesome svg instead of i tag. pro icons will still work with i tag
This commit is contained in:
@@ -68,6 +68,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^7.0.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||
"@iconify/utils": "^2.1.32",
|
||||
"@mermaid-js/parser": "workspace:^",
|
||||
"@types/d3": "^7.4.3",
|
||||
|
@@ -1,12 +1,14 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { replaceIconSubstring } from './createText.js';
|
||||
import { icon } from '@fortawesome/fontawesome-svg-core';
|
||||
import { faUser, faArrowRight, faHome } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faGithub } from '@fortawesome/free-brands-svg-icons';
|
||||
|
||||
describe('replaceIconSubstring', () => {
|
||||
it('converts FontAwesome icon notations to HTML tags', () => {
|
||||
const input = 'This is an icon: fa:fa-user and fab:fa-github';
|
||||
const output = replaceIconSubstring(input);
|
||||
const expected =
|
||||
"This is an icon: <i class='fa fa-user'></i> and <i class='fab fa-github'></i>";
|
||||
const expected = `This is an icon: ${icon(faUser).html.join('')} and ${icon(faGithub).html.join('')}`;
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
@@ -19,8 +21,7 @@ describe('replaceIconSubstring', () => {
|
||||
it('correctly processes multiple FontAwesome icon notations in one string', () => {
|
||||
const input = 'Icons galore: fa:fa-arrow-right, fak:fa-truck, fas:fa-home';
|
||||
const output = replaceIconSubstring(input);
|
||||
const expected =
|
||||
"Icons galore: <i class='fa fa-arrow-right'></i>, <i class='fak fa-truck'></i>, <i class='fas fa-home'></i>";
|
||||
const expected = `Icons galore: ${icon(faArrowRight).html.join()}, <i class='fak fa-truck'></i>, ${icon(faHome).html.join()}`;
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
|
@@ -11,6 +11,22 @@ import { markdownToHTML, markdownToLines } from '../rendering-util/handle-markdo
|
||||
import { decodeEntities } from '../utils.js';
|
||||
import { splitLineToFitWidth } from './splitText.js';
|
||||
import type { MarkdownLine, MarkdownWord } from './types.js';
|
||||
import { library, icon } from '@fortawesome/fontawesome-svg-core';
|
||||
import * as fab from '@fortawesome/free-brands-svg-icons';
|
||||
import * as fas from '@fortawesome/free-solid-svg-icons';
|
||||
import * as far from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
const iconListFab = Object.keys(fab)
|
||||
.filter((key) => key !== 'fab' && key !== 'prefix')
|
||||
.map((icon) => fab[icon]);
|
||||
const iconListFas = Object.keys(fas)
|
||||
.filter((key) => key !== 'fas' && key !== 'prefix')
|
||||
.map((icon) => fas[icon]);
|
||||
const iconListFar = Object.keys(far)
|
||||
.filter((key) => key !== 'far' && key !== 'prefix')
|
||||
.map((icon) => far[icon]);
|
||||
|
||||
library.add(...iconListFab, ...iconListFas, ...iconListFar);
|
||||
|
||||
function applyStyle(dom, styleFn) {
|
||||
if (styleFn) {
|
||||
@@ -180,14 +196,36 @@ function updateTextContentAndStyles(tspan: any, wrappedLine: MarkdownWord[]) {
|
||||
/**
|
||||
* Convert fontawesome labels into fontawesome icons by using a regex pattern
|
||||
* @param text - The raw string to convert
|
||||
* @returns string with fontawesome icons as i tags
|
||||
* @returns string with fontawesome icons as i tags if they are from pro pack and as svg if they are from free pack
|
||||
*/
|
||||
export function replaceIconSubstring(text: string) {
|
||||
// The letters 'bklrs' stand for possible endings of the fontawesome prefix (e.g. 'fab' for brands, 'fak' for fa-kit) // cspell: disable-line
|
||||
return text.replace(
|
||||
/fa[bklrs]?:fa-[\w-]+/g, // cspell: disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
);
|
||||
export function replaceIconSubstring(text) {
|
||||
const iconRegex = /(fas|fab|far|fa|fal|fak|fad):fa-([a-z-]+)/g;
|
||||
const classNameMap = {
|
||||
fas: 'fa-solid',
|
||||
fab: 'fa-brands',
|
||||
far: 'fa-regular',
|
||||
fa: 'fa',
|
||||
fal: 'fa-light',
|
||||
fad: 'fa-duotone',
|
||||
fak: 'fak',
|
||||
} as const;
|
||||
const freeIconPack = ['fas', 'fab', 'far', 'fa'];
|
||||
|
||||
return text.replace(iconRegex, (match, prefix, iconName) => {
|
||||
const isFreeIcon = freeIconPack.includes(prefix);
|
||||
const className = classNameMap[prefix];
|
||||
if (!isFreeIcon) {
|
||||
log.warn(`Icon ${prefix}:fa-${iconName} is pro icon.`);
|
||||
return `<i class='${className} fa-${iconName}'></i>`;
|
||||
}
|
||||
const faIcon = icon({ prefix: prefix, iconName: iconName });
|
||||
if (!faIcon) {
|
||||
log.warn(`Icon ${prefix}:fa-${iconName} not found.`);
|
||||
return match;
|
||||
}
|
||||
|
||||
return faIcon.html.join('');
|
||||
});
|
||||
}
|
||||
|
||||
// Note when using from flowcharts converting the API isNode means classes should be set accordingly. When using htmlLabels => to sett classes to'nodeLabel' when isNode=true otherwise 'edgeLabel'
|
||||
|
50
pnpm-lock.yaml
generated
50
pnpm-lock.yaml
generated
@@ -217,6 +217,18 @@ importers:
|
||||
'@braintree/sanitize-url':
|
||||
specifier: ^7.0.1
|
||||
version: 7.1.0
|
||||
'@fortawesome/fontawesome-svg-core':
|
||||
specifier: ^6.7.2
|
||||
version: 6.7.2
|
||||
'@fortawesome/free-brands-svg-icons':
|
||||
specifier: ^6.7.2
|
||||
version: 6.7.2
|
||||
'@fortawesome/free-regular-svg-icons':
|
||||
specifier: ^6.7.2
|
||||
version: 6.7.2
|
||||
'@fortawesome/free-solid-svg-icons':
|
||||
specifier: ^6.7.2
|
||||
version: 6.7.2
|
||||
'@iconify/utils':
|
||||
specifier: ^2.1.32
|
||||
version: 2.1.33
|
||||
@@ -2225,6 +2237,26 @@ packages:
|
||||
'@floating-ui/vue@1.1.5':
|
||||
resolution: {integrity: sha512-ynL1p5Z+woPVSwgMGqeDrx6HrJfGIDzFyESFkyqJKilGW1+h/8yVY29Khn0LaU6wHBRwZ13ntG6reiHWK6jyzw==}
|
||||
|
||||
'@fortawesome/fontawesome-common-types@6.7.2':
|
||||
resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
'@fortawesome/fontawesome-svg-core@6.7.2':
|
||||
resolution: {integrity: sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
'@fortawesome/free-brands-svg-icons@6.7.2':
|
||||
resolution: {integrity: sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
'@fortawesome/free-regular-svg-icons@6.7.2':
|
||||
resolution: {integrity: sha512-7Z/ur0gvCMW8G93dXIQOkQqHo2M5HLhYrRVC0//fakJXxcF1VmMPsxnG6Ee8qEylA8b8Q3peQXWMNZ62lYF28g==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
'@fortawesome/free-solid-svg-icons@6.7.2':
|
||||
resolution: {integrity: sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
'@hapi/hoek@9.3.0':
|
||||
resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
|
||||
|
||||
@@ -12533,6 +12565,24 @@ snapshots:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
||||
'@fortawesome/fontawesome-common-types@6.7.2': {}
|
||||
|
||||
'@fortawesome/fontawesome-svg-core@6.7.2':
|
||||
dependencies:
|
||||
'@fortawesome/fontawesome-common-types': 6.7.2
|
||||
|
||||
'@fortawesome/free-brands-svg-icons@6.7.2':
|
||||
dependencies:
|
||||
'@fortawesome/fontawesome-common-types': 6.7.2
|
||||
|
||||
'@fortawesome/free-regular-svg-icons@6.7.2':
|
||||
dependencies:
|
||||
'@fortawesome/fontawesome-common-types': 6.7.2
|
||||
|
||||
'@fortawesome/free-solid-svg-icons@6.7.2':
|
||||
dependencies:
|
||||
'@fortawesome/fontawesome-common-types': 6.7.2
|
||||
|
||||
'@hapi/hoek@9.3.0': {}
|
||||
|
||||
'@hapi/topo@5.1.0':
|
||||
|
Reference in New Issue
Block a user