diff --git a/code/websites/pokedex.online/src/directives/highlight.js b/code/websites/pokedex.online/src/directives/highlight.js index e69de29..f753b94 100644 --- a/code/websites/pokedex.online/src/directives/highlight.js +++ b/code/websites/pokedex.online/src/directives/highlight.js @@ -0,0 +1,90 @@ +/** + * 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); + 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: ... + */ +export const vHighlight = { + mounted(el, binding) { + const theme = binding.value || 'github-dark'; + + // Store observer on element for cleanup + el._highlightObserver = createHighlightObserver(el, theme); + }, + + updated(el, binding) { + const newTheme = binding.value || 'github-dark'; + const oldTheme = binding.oldValue || '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;