// Utility functions for the resume website /** * Debounce a function to limit its execution rate * @param {Function} func - The function to debounce * @param {number} wait - The number of milliseconds to delay * @returns {Function} - The debounced function */ export function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } /** * Check if an element is in the viewport * @param {Element} element - The element to check * @returns {boolean} - Whether the element is in the viewport */ export function isInViewport(element) { const rect = element.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } /** * Format a date in a consistent way * @param {Date|string} date - The date to format * @returns {string} - The formatted date string */ export function formatDate(date) { if (!date) return ''; const d = new Date(date); return d.toLocaleDateString('en-US', { year: 'numeric', month: 'long' }); } /** * Safely get a value from an object using a path * @param {Object} obj - The object to traverse * @param {string} path - The path to the value * @param {*} defaultValue - The default value if not found * @returns {*} - The value at the path or the default value */ export function get(obj, path, defaultValue = undefined) { return path.split('.') .reduce((acc, part) => acc && acc[part], obj) ?? defaultValue; }