fixing rolodex and search
This commit is contained in:
@@ -12,20 +12,20 @@
|
||||
|
||||
const TYPE_CLASSES = {
|
||||
success: {
|
||||
container: 'border-success-200 dark:border-success-800',
|
||||
icon: 'fa-solid fa-circle-check text-success-600 dark:text-success-400'
|
||||
container: 'border-green-300 dark:border-green-500 bg-green-50 dark:bg-green-800',
|
||||
icon: 'fa-solid fa-circle-check text-green-600 dark:text-green-300'
|
||||
},
|
||||
danger: {
|
||||
container: 'border-danger-200 dark:border-danger-800',
|
||||
icon: 'fa-solid fa-triangle-exclamation text-danger-600 dark:text-danger-400'
|
||||
container: 'border-red-300 dark:border-red-500 bg-red-50 dark:bg-red-800',
|
||||
icon: 'fa-solid fa-triangle-exclamation text-red-600 dark:text-red-300'
|
||||
},
|
||||
warning: {
|
||||
container: 'border-warning-200 dark:border-warning-800',
|
||||
icon: 'fa-solid fa-triangle-exclamation text-warning-600 dark:text-warning-400'
|
||||
container: 'border-yellow-300 dark:border-yellow-500 bg-yellow-50 dark:bg-yellow-800',
|
||||
icon: 'fa-solid fa-triangle-exclamation text-yellow-600 dark:text-yellow-300'
|
||||
},
|
||||
info: {
|
||||
container: 'border-info-200 dark:border-info-800',
|
||||
icon: 'fa-solid fa-circle-info text-info-600 dark:text-info-400'
|
||||
container: 'border-blue-300 dark:border-blue-500 bg-blue-50 dark:bg-blue-800',
|
||||
icon: 'fa-solid fa-circle-info text-blue-600 dark:text-blue-300'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,6 +34,30 @@
|
||||
return TYPE_ALIASES[key] || 'info';
|
||||
}
|
||||
|
||||
// ---- DOMPurify Lazy Loader ------------------------------------------------
|
||||
// Delegated sanitizer: uses shared htmlSanitizer if available, else performs a minimal fallback
|
||||
function sanitizeHTML(dirty) {
|
||||
if (window.htmlSanitizer && typeof window.htmlSanitizer.sanitize === 'function') {
|
||||
return window.htmlSanitizer.sanitize(dirty);
|
||||
}
|
||||
|
||||
// Minimal inline fallback to guarantee some protection until sanitizer.js loads
|
||||
const temp = document.createElement('div');
|
||||
temp.innerHTML = dirty;
|
||||
temp.querySelectorAll('script, style').forEach((el) => el.remove());
|
||||
temp.querySelectorAll('*').forEach((el) => {
|
||||
Array.from(el.attributes).forEach((attr) => {
|
||||
const name = attr.name;
|
||||
const value = attr.value;
|
||||
if (/^on/i.test(name)) el.removeAttribute(name);
|
||||
if ((name === 'href' || name === 'src') && value && value.trim().toLowerCase().startsWith('javascript:')) {
|
||||
el.removeAttribute(name);
|
||||
}
|
||||
});
|
||||
});
|
||||
return temp.innerHTML;
|
||||
}
|
||||
|
||||
function getOrCreateContainer(containerId = 'notification-container') {
|
||||
let container = document.getElementById(containerId);
|
||||
if (!container) {
|
||||
@@ -63,7 +87,7 @@
|
||||
const container = getOrCreateContainer(containerId);
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = `alert-notification max-w-sm w-[22rem] bg-white dark:bg-neutral-800 border rounded-lg shadow-lg p-4 transition-all duration-300 translate-x-4 opacity-0 ${
|
||||
wrapper.className = `alert-notification max-w-sm w-[22rem] border-2 rounded-lg shadow-xl p-4 transition-all duration-300 translate-x-4 opacity-0 ${
|
||||
(TYPE_CLASSES[tone] || TYPE_CLASSES.info).container
|
||||
}`;
|
||||
wrapper.setAttribute('role', role);
|
||||
@@ -84,17 +108,17 @@
|
||||
|
||||
if (title) {
|
||||
const titleEl = document.createElement('p');
|
||||
titleEl.className = 'text-sm font-semibold text-neutral-900 dark:text-neutral-100';
|
||||
titleEl.className = 'text-sm font-bold text-neutral-900 dark:text-white';
|
||||
titleEl.textContent = String(title);
|
||||
content.appendChild(titleEl);
|
||||
}
|
||||
|
||||
const text = document.createElement('div');
|
||||
text.className = 'text-xs mt-1 text-neutral-800 dark:text-neutral-200';
|
||||
text.className = 'text-sm mt-1 font-semibold text-neutral-900 dark:text-white';
|
||||
if (message instanceof Node) {
|
||||
text.appendChild(message);
|
||||
} else if (html) {
|
||||
text.innerHTML = String(message || '');
|
||||
text.innerHTML = sanitizeHTML(String(message || ''));
|
||||
} else {
|
||||
text.textContent = String(message || '');
|
||||
}
|
||||
@@ -177,7 +201,10 @@
|
||||
error: (message, options = {}) => show(message, 'danger', options),
|
||||
warning: (message, options = {}) => show(message, 'warning', options),
|
||||
info: (message, options = {}) => show(message, 'info', options),
|
||||
getOrCreateContainer
|
||||
getOrCreateContainer,
|
||||
// Internal: exposed for unit testing only (non-enumerable by default prototype iteration)
|
||||
_sanitize: sanitizeHTML,
|
||||
_ensureDOMPurifyLoaded: () => window.htmlSanitizer ? window.htmlSanitizer.ensureDOMPurifyLoaded() : Promise.resolve(null)
|
||||
};
|
||||
|
||||
// Expose globally
|
||||
|
||||
Reference in New Issue
Block a user