mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-06 17:16:43 +02:00
Merge pull request #5430 from jakobskrym/feature/support-fa-kit-custom-icons
Feature/support fa kit custom icons
This commit is contained in:
@@ -1178,6 +1178,36 @@ Adding this snippet in the `<head>` would add support for Font Awesome v6.5.1
|
||||
/>
|
||||
```
|
||||
|
||||
### Custom icons
|
||||
|
||||
It is possible to use custom icons served from Font Awesome as long as the website imports the corresponding kit.
|
||||
|
||||
Note that this is currently a paid feature from Font Awesome.
|
||||
|
||||
For custom icons, you need to use the `fak` prefix.
|
||||
|
||||
**Example**
|
||||
|
||||
```
|
||||
flowchart TD
|
||||
B[fa:fa-twitter] %% standard icon
|
||||
B-->E(fak:fa-custom-icon-name) %% custom icon
|
||||
```
|
||||
|
||||
And trying to render it
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
B["fa:fa-twitter for peace"]
|
||||
B-->C["fab:fa-truck-bold a custom icon"]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
B["fa:fa-twitter for peace"]
|
||||
B-->C["fab:fa-truck-bold a custom icon"]
|
||||
```
|
||||
|
||||
## Graph declarations with spaces between vertices and link and without semicolon
|
||||
|
||||
- In graph declarations, the statements also can now end without a semicolon. After release 0.2.16, ending a graph statement with semicolon is just optional. So the below graph declaration is also valid along with the old declarations of the graph.
|
||||
|
@@ -3,6 +3,7 @@ import { log } from '../logger.js';
|
||||
import { getConfig } from '../diagram-api/diagramAPI.js';
|
||||
import { evaluate } from '../diagrams/common/common.js';
|
||||
import { decodeEntities } from '../utils.js';
|
||||
import { replaceIconSubstring } from '../rendering-util/createText.js';
|
||||
|
||||
/**
|
||||
* @param dom
|
||||
@@ -59,10 +60,7 @@ const createLabel = (_vertexText, style, isTitle, isNode) => {
|
||||
log.debug('vertexText' + vertexText);
|
||||
const node = {
|
||||
isNode,
|
||||
label: decodeEntities(vertexText).replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell: disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
label: replaceIconSubstring(decodeEntities(vertexText)),
|
||||
labelStyle: style.replace('fill:', 'color:'),
|
||||
};
|
||||
let vertexNode = addHtmlLabel(node);
|
||||
|
@@ -9,6 +9,7 @@ import common, { evaluate, renderKatex } from '../common/common.js';
|
||||
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
|
||||
import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||
import flowChartShapes from './flowChartShapes.js';
|
||||
import { replaceIconSubstring } from '../../rendering-util/createText.js';
|
||||
|
||||
const conf = {};
|
||||
export const setConf = function (cnf) {
|
||||
@@ -56,14 +57,9 @@ export const addVertices = async function (vert, g, svgId, root, _doc, diagObj)
|
||||
let vertexNode;
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
const replacedVertexText = replaceIconSubstring(vertexText);
|
||||
const node = {
|
||||
label: await renderKatex(
|
||||
vertexText.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
getConfig()
|
||||
),
|
||||
label: await renderKatex(replacedVertexText, getConfig()),
|
||||
};
|
||||
vertexNode = addHtmlLabel(svg, node).node();
|
||||
vertexNode.parentNode.removeChild(vertexNode);
|
||||
@@ -242,13 +238,7 @@ export const addEdges = async function (edges, g, diagObj) {
|
||||
edgeData.labelType = 'html';
|
||||
edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}" style="${
|
||||
edgeData.labelStyle
|
||||
}">${await renderKatex(
|
||||
edge.text.replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell:disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
getConfig()
|
||||
)}</span>`;
|
||||
}">${await renderKatex(replaceIconSubstring(edge.text), getConfig())}</span>`;
|
||||
} else {
|
||||
edgeData.labelType = 'text';
|
||||
edgeData.label = edge.text.replace(common.lineBreakRegex, '\n');
|
||||
|
@@ -799,6 +799,30 @@ Adding this snippet in the `<head>` would add support for Font Awesome v6.5.1
|
||||
/>
|
||||
```
|
||||
|
||||
### Custom icons
|
||||
|
||||
It is possible to use custom icons served from Font Awesome as long as the website imports the corresponding kit.
|
||||
|
||||
Note that this is currently a paid feature from Font Awesome.
|
||||
|
||||
For custom icons, you need to use the `fak` prefix.
|
||||
|
||||
**Example**
|
||||
|
||||
```
|
||||
flowchart TD
|
||||
B[fa:fa-twitter] %% standard icon
|
||||
B-->E(fak:fa-custom-icon-name) %% custom icon
|
||||
```
|
||||
|
||||
And trying to render it
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
B["fa:fa-twitter for peace"]
|
||||
B-->C["fab:fa-truck-bold a custom icon"]
|
||||
```
|
||||
|
||||
## Graph declarations with spaces between vertices and link and without semicolon
|
||||
|
||||
- In graph declarations, the statements also can now end without a semicolon. After release 0.2.16, ending a graph statement with semicolon is just optional. So the below graph declaration is also valid along with the old declarations of the graph.
|
||||
|
34
packages/mermaid/src/rendering-util/createText.spec.ts
Normal file
34
packages/mermaid/src/rendering-util/createText.spec.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { replaceIconSubstring } from './createText.js';
|
||||
|
||||
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>";
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
it('handles strings without FontAwesome icon notations', () => {
|
||||
const input = 'This string has no icons';
|
||||
const output = replaceIconSubstring(input);
|
||||
expect(output).toEqual(input); // No change expected
|
||||
});
|
||||
|
||||
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>";
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
it('correctly replaces a very long icon name with the fak prefix', () => {
|
||||
const input = 'Here is a long icon: fak:fa-truck-driving-long-winding-road in use';
|
||||
const output = replaceIconSubstring(input);
|
||||
const expected =
|
||||
"Here is a long icon: <i class='fak fa-truck-driving-long-winding-road'></i> in use";
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
});
|
@@ -168,6 +168,19 @@ 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
|
||||
*/
|
||||
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>`
|
||||
);
|
||||
}
|
||||
|
||||
// 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'
|
||||
// When not using htmlLabels => to set classes to 'title-row' when isTitle=true otherwise 'title-row'
|
||||
export const createText = (
|
||||
@@ -189,12 +202,10 @@ export const createText = (
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
|
||||
const htmlText = markdownToHTML(text, config);
|
||||
const decodedReplacedText = replaceIconSubstring(decodeEntities(htmlText));
|
||||
const node = {
|
||||
isNode,
|
||||
label: decodeEntities(htmlText).replace(
|
||||
/fa[blrs]?:fa-[\w-]+/g, // cspell: disable-line
|
||||
(s) => `<i class='${s.replace(':', ' ')}'></i>`
|
||||
),
|
||||
label: decodedReplacedText,
|
||||
labelStyle: style.replace('fill:', 'color:'),
|
||||
};
|
||||
const vertexNode = addHtmlSpan(el, node, width, classes, addSvgBackground);
|
||||
|
Reference in New Issue
Block a user