diff --git a/builder/scripts/sprite.js b/builder/scripts/sprite.js
index a2fa4e038..0204ffe0f 100644
--- a/builder/scripts/sprite.js
+++ b/builder/scripts/sprite.js
@@ -30,6 +30,15 @@ const path = require("path");
const defaultPlugins = require("../conf/svgoDefaultPlugins");
const SVGSpriter = require("svg-sprite");
+let svgMarkup;
+
+const addSvgMarkup = (filePath) => {
+ const fileContents = fs.readFileSync(filePath, { encoding: "utf-8" });
+ svgMarkup = svgMarkup += ""; // Closing svg tag.
+ const updatedContents = fileContents.replace("", svgMarkup);
+ fs.writeFileSync(filePath, updatedContents);
+};
+
module.exports = (entry, dest, options) => {
const iconList = Array.isArray(options.list)
? options.list.flat(1)
@@ -64,7 +73,7 @@ module.exports = (entry, dest, options) => {
},
},
});
-
+ let svgYPosition = 0;
files.forEach((file) => {
let filePath;
if (Array.isArray(entry)) {
@@ -75,6 +84,10 @@ module.exports = (entry, dest, options) => {
} else {
filePath = path.resolve(entry, file);
}
+ const id = path.basename(file, path.extname(file)); // Extracting file name without extension as id
+ svgMarkup =
+ svgMarkup += ``;
+ svgYPosition = svgYPosition + 16;
spriter.add(
filePath,
file,
@@ -90,6 +103,8 @@ module.exports = (entry, dest, options) => {
result[mode][resource].path,
result[mode][resource].contents
);
+ const outputPath = result[mode][resource].path;
+ addSvgMarkup(outputPath);
});
});
});
diff --git a/src/compositions/bcl-icons-list/icons-list.story.js b/src/compositions/bcl-icons-list/icons-list.story.js
index 0e8e0232b..d5311b73a 100644
--- a/src/compositions/bcl-icons-list/icons-list.story.js
+++ b/src/compositions/bcl-icons-list/icons-list.story.js
@@ -1,7 +1,9 @@
import icons_list from "@openeuropa/bcl-icons-list/icons-list.html.twig";
+import icons_manager from "@openeuropa/bcl-icons-list/icons-manager.html.twig";
import icons from "@openeuropa/bcl-theme-default/src/icons/icons";
import customIcons from "@openeuropa/bcl-theme-default/src/icons/custom-icons";
import defaultSprite from "@openeuropa/bcl-theme-default/icons/bcl-default-icons.svg";
+import { addIconPath } from "@openeuropa/bcl-story-utils";
let iconsList = icons.concat(customIcons);
iconsList = iconsList.map((icon) => icon.substring(0, icon.length - 4));
@@ -17,3 +19,8 @@ export default {
export const Default = () =>
icons_list({ icons: iconsList, path: defaultSprite });
+
+export const Attribute = () =>
+ icons_manager({ icons: iconsList, path: defaultSprite });
+
+Attribute.decorators = [addIconPath];
diff --git a/src/compositions/bcl-icons-list/icons-manager.html.twig b/src/compositions/bcl-icons-list/icons-manager.html.twig
new file mode 100644
index 000000000..8cf66c7cf
--- /dev/null
+++ b/src/compositions/bcl-icons-list/icons-manager.html.twig
@@ -0,0 +1,105 @@
+{% apply spaceless %}
+
+{# Parameters:
+ - icons: (icon[]) (default: [])
+ - path (string) (default: '')
+#}
+
+{% set _icons = icons|default([]) %}
+{% set _path = path|default('') %}
+
+{% if _icons is not empty and _icons is iterable %}
+
+
+
Icon Colours
+
+
+
+
Primary
icon-color-primary
+
+
+
+
Secondary
icon-color-secondary
+
+
+
+
Success
icon-color-success
+
+
+
+
Info
icon-color-info
+
+
+
+
Warning
icon-color-warning
+
+
+
+
Danger
icon-color-danger
+
+
+
+
Dark
icon-color-dark
+
+
+
+
+
+
Light
icon-color-light
+
+
+
+
Icon Sizes
+
+
+
+
+
+
+
+
Fluid - icon--fluid
+
+
+
+
+
Icons List
+ {% for _icon in _icons %}
+
+ {% endfor %}
+
+
+{% endif %}
+
+{% endapply %}
diff --git a/src/themes/default/src/js/icon-manager/icon-manager.js b/src/themes/default/src/js/icon-manager/icon-manager.js
new file mode 100644
index 000000000..6e9d9f500
--- /dev/null
+++ b/src/themes/default/src/js/icon-manager/icon-manager.js
@@ -0,0 +1,37 @@
+/**
+ * --------------------------------------------------------------------------
+ * IconManager Class Documentation
+ * --------------------------------------------------------------------------
+ *
+ * Overview:
+ * The `IconManager` class is a utility for dynamically setting the `mask-image`
+ * of HTML elements based on custom data attributes. It uses CSS custom properties
+ * and JavaScript to ensure the correct SVG icon is applied to elements with the class `.icon`.
+ *
+ */
+
+import { defineJQueryPlugin } from '@openeuropa/bcl-bootstrap/js/src/util/index'
+
+class IconManager {
+ initializeIcons() {
+ this.iconPath = getComputedStyle(document.body).getPropertyValue('--icon-path').trim().replace(/['"]/g, '');
+ document.querySelectorAll('.icon[data-icon]').forEach(icon => {
+ const iconId = icon.getAttribute('data-icon');
+ this.setIconMask(icon, iconId);
+ });
+ }
+
+ setIconMask(icon, iconId) {
+ icon.style.maskImage = `url(${this.iconPath}#${iconId}-view)`;
+ icon.style.webkitMaskImage = `url(${this.iconPath}#${iconId}-view)`;
+ }
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const iconManager = new IconManager();
+ iconManager.initializeIcons();
+});
+
+defineJQueryPlugin(IconManager);
+
+export default IconManager;
diff --git a/src/themes/default/src/js/index.esm.js b/src/themes/default/src/js/index.esm.js
index 16e946ebc..4b9057fc4 100644
--- a/src/themes/default/src/js/index.esm.js
+++ b/src/themes/default/src/js/index.esm.js
@@ -19,6 +19,7 @@ import ScrollSpy from "@openeuropa/bcl-bootstrap/js/src/scrollspy-legacy";
import Tab from "@openeuropa/bcl-bootstrap/js/src/tab";
import Toast from "@openeuropa/bcl-bootstrap/js/src/toast";
import Tooltip from "@openeuropa/bcl-bootstrap/js/src/tooltip";
+import IconManager from "@openeuropa/bcl-theme-default/src/js/icon-manager/icon-manager";
export {
Alert,
@@ -35,4 +36,5 @@ export {
Tab,
Toast,
Tooltip,
+ IconManager,
};
diff --git a/src/themes/default/src/js/index.umd.js b/src/themes/default/src/js/index.umd.js
index 8a3f1ec16..cdf884df3 100644
--- a/src/themes/default/src/js/index.umd.js
+++ b/src/themes/default/src/js/index.umd.js
@@ -19,6 +19,7 @@ import ScrollSpy from "@openeuropa/bcl-bootstrap/js/src/scrollspy-legacy";
import Tab from "@openeuropa/bcl-bootstrap/js/src/tab";
import Toast from "@openeuropa/bcl-bootstrap/js/src/toast";
import Tooltip from "@openeuropa/bcl-bootstrap/js/src/tooltip";
+import IconManager from "@openeuropa/bcl-theme-default/src/js/icon-manager/icon-manager";
export default {
Alert,
@@ -35,4 +36,5 @@ export default {
Tab,
Toast,
Tooltip,
+ IconManager,
};
diff --git a/src/themes/default/src/scss/_icon_manager.scss b/src/themes/default/src/scss/_icon_manager.scss
new file mode 100644
index 000000000..d3a22fcca
--- /dev/null
+++ b/src/themes/default/src/scss/_icon_manager.scss
@@ -0,0 +1,16 @@
+.icon {
+ width: 1em;
+ height: 1em;
+ display: block;
+ background-color: var(--bs-dark);
+ -webkit-mask-size: contain;
+ mask-size: contain;
+ -webkit-mask-repeat: no-repeat;
+ mask-repeat: no-repeat;
+}
+
+@each $color, $value in $theme-colors {
+ .icon-color-#{$color} {
+ background-color: $value;
+ }
+}
diff --git a/src/themes/default/src/scss/oe-bcl-default.scss b/src/themes/default/src/scss/oe-bcl-default.scss
index 66afc8eb8..09f92140c 100644
--- a/src/themes/default/src/scss/oe-bcl-default.scss
+++ b/src/themes/default/src/scss/oe-bcl-default.scss
@@ -67,6 +67,7 @@
@import "@openeuropa/bcl-theme-default/src/scss/header";
@import "@openeuropa/bcl-theme-default/src/scss/footer";
@import "@openeuropa/bcl-theme-default/src/scss/tabs";
+@import "@openeuropa/bcl-theme-default/src/scss/icon_manager";
@import "@openeuropa/bcl-theme-default/src/scss/icon";
@import "@openeuropa/bcl-theme-default/src/scss/search-form";
@import "@openeuropa/bcl-theme-default/src/scss/input";
diff --git a/tools/story-utils/index.js b/tools/story-utils/index.js
index 6448f21d5..7e71703c7 100644
--- a/tools/story-utils/index.js
+++ b/tools/story-utils/index.js
@@ -342,6 +342,15 @@ export const initScrollspy = (story) => {
${demo}`;
};
+export const addIconPath = (story) => {
+ const demo = story();
+ return `
+
+ ${demo}`;
+};
+
export const initBadges = (story) => {
const demo = story();
return `