Files
memory-infrastructure-palace/code/websites/pokedex.online/src/directives/highlight.js

96 lines
2.6 KiB
JavaScript

/**
* v-highlight directive
* Lazy loads syntax highlighting for code blocks using highlight.js
* Only highlights when element enters viewport (IntersectionObserver)
*/
import hljs from 'highlight.js/lib/core';
import json from 'highlight.js/lib/languages/json';
// Register JSON language
hljs.registerLanguage('json', json);
/**
* Apply syntax highlighting to a code element
* @param {HTMLElement} el - The code element to highlight
* @param {string} theme - Theme name ('github' or 'github-dark')
*/
function applyHighlight(el, theme = 'github-dark') {
if (el.classList.contains('hljs')) {
// Already highlighted
return;
}
try {
hljs.highlightElement(el);
// Remove any existing theme classes
el.className = el.className.replace(/hljs-theme-\w+/, '');
el.classList.add(`hljs-theme-${theme}`);
} catch (error) {
console.error('Highlight.js error:', error);
}
}
/**
* Create IntersectionObserver for lazy highlighting
* @param {HTMLElement} el - Element to observe
* @param {string} theme - Theme to apply
* @returns {IntersectionObserver}
*/
function createHighlightObserver(el, theme) {
const observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
applyHighlight(entry.target, theme);
observer.disconnect();
}
});
},
{
rootMargin: '50px', // Start highlighting slightly before entering viewport
threshold: 0.01
}
);
observer.observe(el);
return observer;
}
/**
* v-highlight directive
* Usage: <code v-highlight="{ theme: 'github', language: 'json' }">...</code>
*/
export const vHighlight = {
mounted(el, binding) {
const config = binding.value || {};
const theme = typeof config === 'string' ? config : (config.theme || 'github-dark');
// Store observer on element for cleanup
el._highlightObserver = createHighlightObserver(el, theme);
},
updated(el, binding) {
const newConfig = binding.value || {};
const newTheme = typeof newConfig === 'string' ? newConfig : (newConfig.theme || 'github-dark');
const oldConfig = binding.oldValue || {};
const oldTheme = typeof oldConfig === 'string' ? oldConfig : (oldConfig.theme || 'github-dark');
// If theme changed, re-highlight
if (newTheme !== oldTheme && el.classList.contains('hljs')) {
el.classList.remove(`hljs-theme-${oldTheme}`);
el.classList.add(`hljs-theme-${newTheme}`);
}
},
unmounted(el) {
// Cleanup observer
if (el._highlightObserver) {
el._highlightObserver.disconnect();
delete el._highlightObserver;
}
}
};
export default vHighlight;