feat: dynamische icon-kleuring gegenereerd voor elke .lucide-<naam>
This commit is contained in:
+94
-31
@@ -1,9 +1,20 @@
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
import { api } from './api';
|
||||
|
||||
// Legacy standaard-icoonkleuren (alle Lucide-iconen op de pagina een unieke kleur)
|
||||
function hashCode(str) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
function generateColor(name) {
|
||||
const hue = Math.abs(hashCode(name)) % 360;
|
||||
return `hsl(${hue}, 65%, 55%)`;
|
||||
}
|
||||
|
||||
export const DEFAULT_ICON_COLORS = {
|
||||
// Navigation & Core Domains
|
||||
'layout-dashboard': '#58a6ff',
|
||||
'users': '#3fb950',
|
||||
'briefcase': '#d29922',
|
||||
@@ -27,13 +38,9 @@ export const DEFAULT_ICON_COLORS = {
|
||||
'radar': '#d29922',
|
||||
'sparkles': '#bc8cff',
|
||||
'settings': '#8b9bb8',
|
||||
|
||||
// Legacy & Platform
|
||||
'shield-check': '#3fb950',
|
||||
'pen-tool': '#bc8cff',
|
||||
'file-search': '#d29922',
|
||||
|
||||
// Actions & Tools
|
||||
'plus': '#00d4ff',
|
||||
'pencil': '#79c0ff',
|
||||
'trash-2': '#f85149',
|
||||
@@ -48,15 +55,11 @@ export const DEFAULT_ICON_COLORS = {
|
||||
'star': '#d29922',
|
||||
'bot': '#bc8cff',
|
||||
'filter': '#8b9bb8',
|
||||
|
||||
// Infra & Entities
|
||||
'building-2': '#bc8cff',
|
||||
'factory': '#bc8cff',
|
||||
'map-pin': '#58a6ff',
|
||||
'cable': '#58a6ff',
|
||||
'workflow': '#bc8cff',
|
||||
|
||||
// Status & Info
|
||||
'bell': '#d29922',
|
||||
'file-text': '#f778ba',
|
||||
'lightbulb': '#d29922',
|
||||
@@ -69,43 +72,104 @@ export const DEFAULT_ICON_COLORS = {
|
||||
'external-link': '#8b9bb8',
|
||||
'log-out': '#f85149',
|
||||
'menu': '#8b9bb8',
|
||||
'x': '#8b9bb8'
|
||||
'x': '#8b9bb8',
|
||||
'arrow-left': '#79c0ff',
|
||||
'arrow-right': '#79c0ff',
|
||||
'chevron-left': '#8b9bb8',
|
||||
'chevron-right': '#8b9bb8',
|
||||
'globe': '#58a6ff',
|
||||
'phone': '#3fb950',
|
||||
'loader-2': '#8b9bb8'
|
||||
};
|
||||
|
||||
// Injecteert globale CSS-regels voor alle .lucide-<name> elementen op de pagina
|
||||
export function injectIconStyles(customColors) {
|
||||
let styleEl = document.getElementById('mek-icon-colors');
|
||||
if (!styleEl) {
|
||||
styleEl = document.createElement('style');
|
||||
styleEl.id = 'mek-icon-colors';
|
||||
document.head.appendChild(styleEl);
|
||||
let processedIcons = new Set();
|
||||
|
||||
function getStyleEl() {
|
||||
let el = document.getElementById('mek-icon-colors');
|
||||
if (!el) {
|
||||
el = document.createElement('style');
|
||||
el.id = 'mek-icon-colors';
|
||||
document.head.appendChild(el);
|
||||
}
|
||||
const merged = { ...DEFAULT_ICON_COLORS, ...(customColors || {}) };
|
||||
let css = '/* Dynamic Icon Colors */\n';
|
||||
return el;
|
||||
}
|
||||
|
||||
function scanAndInject(styleEl, merged) {
|
||||
let css = '/* Icon Colors */\n';
|
||||
for (const [name, color] of Object.entries(merged)) {
|
||||
if (!color) continue;
|
||||
css += `.lucide-${name}, [data-lucide="${name}"] { color: ${color}; }\n`;
|
||||
css += `.lucide-${name}, [data-lucide="${name}"] { color: ${color} }\n`;
|
||||
processedIcons.add(name);
|
||||
}
|
||||
const els = document.querySelectorAll('[class*="lucide-"]');
|
||||
for (const el of els) {
|
||||
for (const cls of el.classList) {
|
||||
if (cls.startsWith('lucide-') && cls !== 'lucide') {
|
||||
const name = cls.replace('lucide-', '');
|
||||
if (!processedIcons.has(name)) {
|
||||
const c = generateColor(name);
|
||||
css += `.lucide-${name}, [data-lucide="${name}"] { color: ${c} }\n`;
|
||||
processedIcons.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
el.setAttribute('data-ic', '1');
|
||||
}
|
||||
styleEl.textContent = css;
|
||||
}
|
||||
|
||||
export function injectIconStyles(customColors) {
|
||||
processedIcons.clear();
|
||||
const merged = { ...DEFAULT_ICON_COLORS, ...(customColors || {}) };
|
||||
scanAndInject(getStyleEl(), merged);
|
||||
}
|
||||
|
||||
let observer = null;
|
||||
|
||||
function startObserver() {
|
||||
if (observer) return;
|
||||
observer = new MutationObserver(() => {
|
||||
const els = document.querySelectorAll('[class*="lucide-"]:not([data-ic])');
|
||||
if (!els.length) return;
|
||||
const styleEl = getStyleEl();
|
||||
let extra = '';
|
||||
for (const el of els) {
|
||||
for (const cls of el.classList) {
|
||||
if (cls.startsWith('lucide-') && cls !== 'lucide') {
|
||||
const name = cls.replace('lucide-', '');
|
||||
if (!processedIcons.has(name)) {
|
||||
const c = generateColor(name);
|
||||
extra += `.lucide-${name}, [data-lucide="${name}"] { color: ${c} }\n`;
|
||||
processedIcons.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
el.setAttribute('data-ic', '1');
|
||||
}
|
||||
if (extra) styleEl.textContent += extra;
|
||||
});
|
||||
observer.observe(document.body || document.documentElement, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
function stopObserver() {
|
||||
if (observer) { observer.disconnect(); observer = null; }
|
||||
}
|
||||
|
||||
const SettingsContext = createContext({ settings: null, loading: true });
|
||||
|
||||
export function SettingsProvider({ children }) {
|
||||
const [settings, setSettings] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Injecteer meteen de standaardkleuren voor snelle weergave
|
||||
injectIconStyles(null);
|
||||
|
||||
startObserver();
|
||||
api.get('/settings')
|
||||
.then(s => {
|
||||
setSettings(s);
|
||||
if (s?.icon_colors) {
|
||||
injectIconStyles(s.icon_colors);
|
||||
}
|
||||
if (s?.icon_colors) injectIconStyles(s.icon_colors);
|
||||
})
|
||||
.catch(() => setSettings(null));
|
||||
return stopObserver;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@@ -115,13 +179,12 @@ export function SettingsProvider({ children }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function useSettings() {
|
||||
return useContext(SettingsContext);
|
||||
}
|
||||
export function useSettings() { return useContext(SettingsContext); }
|
||||
|
||||
export function iconColor(name, settings) {
|
||||
if (settings?.icon_colors && settings.icon_colors[name]) return settings.icon_colors[name];
|
||||
return DEFAULT_ICON_COLORS[name] || null;
|
||||
if (settings?.icon_colors?.[name]) return settings.icon_colors[name];
|
||||
if (DEFAULT_ICON_COLORS[name]) return DEFAULT_ICON_COLORS[name];
|
||||
return generateColor(name);
|
||||
}
|
||||
|
||||
export function brandName(settings) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Mek-Tech — Consultancy Platform</title>
|
||||
<script type="module" crossorigin src="/app/assets/index-zN5ia3Gj.js"></script>
|
||||
<script type="module" crossorigin src="/app/assets/index-BsMRi0iE.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/app/assets/index-Cmof3-vz.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user