refactor: Migrate zoom control and expand/collapse to hyperscript

- Move initZoomControlButtons() from main.js to hyperscript handlers
  - zoom-toggle-button: on click call toggleZoomControl()
  - zoom-close: on click call hideZoomControl()
  - show-zoom-menu-btn: on click call showZoomControl()
- Move expandAllSections/collapseAllSections from JS to utils._hs
- Add zoom visibility functions to zoom._hs:
  - showZoomControl(), hideZoomControl(), toggleZoomControl()
- Update hamburger menu links to use hyperscript calls

Eliminates ~75 more lines of JavaScript in favor of declarative
hyperscript, continuing the pattern of moving behavior to ._hs files.
This commit is contained in:
juanatsap
2025-11-30 06:03:45 +00:00
parent ba44b435e7
commit 7ab150a48e
6 changed files with 63 additions and 91 deletions
+21
View File
@@ -134,6 +134,27 @@ def handleScroll()
set :lastScroll to currentScroll set :lastScroll to currentScroll
end end
-- ==============================================================================
-- EXPAND/COLLAPSE ALL SECTIONS
-- ==============================================================================
-- Expand all <details> elements in the CV
def expandAllSections(evt)
if evt then call evt.preventDefault() end
set details to document.querySelectorAll('details')
for d in details
set d's @open to ''
end
end
-- Collapse all <details> elements in the CV
def collapseAllSections(evt)
if evt then call evt.preventDefault() end
set details to document.querySelectorAll('details')
for d in details
call d.removeAttribute('open')
end
end
-- ============================================================================== -- ==============================================================================
-- FOOTER HOVER INTERACTION -- FOOTER HOVER INTERACTION
-- ============================================================================== -- ==============================================================================
+32 -4
View File
@@ -100,14 +100,42 @@ def initZoomControl(control)
end end
-- ============================================================================== -- ==============================================================================
-- ZOOM CLOSE HANDLER -- ZOOM VISIBILITY HANDLERS
-- ============================================================================== -- ==============================================================================
-- Called when clicking the close button on zoom control -- Show zoom control
def handleZoomClose(control) def showZoomControl()
set control to document.getElementById('zoom-control')
set menuBtn to document.getElementById('show-zoom-menu-btn')
if control is not null
remove .zoom-hidden from control
set localStorage['cv-zoom-visible'] to 'true'
end
if menuBtn is not null
add .zoom-hidden to menuBtn
end
end
-- Hide zoom control
def hideZoomControl()
set control to document.getElementById('zoom-control')
set menuBtn to document.getElementById('show-zoom-menu-btn')
if control is not null
add .zoom-hidden to control add .zoom-hidden to control
set localStorage['cv-zoom-visible'] to 'false' set localStorage['cv-zoom-visible'] to 'false'
set menuBtn to document.getElementById('show-zoom-menu-btn') end
if menuBtn is not null if menuBtn is not null
remove .zoom-hidden from menuBtn remove .zoom-hidden from menuBtn
end end
end end
-- Toggle zoom control visibility
def toggleZoomControl()
set control to document.getElementById('zoom-control')
if control is not null
if control.classList.contains('zoom-hidden')
call showZoomControl()
else
call hideZoomControl()
end
end
end
+1 -81
View File
@@ -55,24 +55,6 @@
} }
} }
/**
* Expand all <details> sections in the CV
* @param {Event} event - Click event
*/
window.expandAllSections = function(event) {
event.preventDefault();
document.querySelectorAll('details').forEach(d => d.setAttribute('open', ''));
};
/**
* Collapse all <details> sections in the CV
* @param {Event} event - Click event
*/
window.collapseAllSections = function(event) {
event.preventDefault();
document.querySelectorAll('details').forEach(d => d.removeAttribute('open'));
};
/** /**
* Auto-open sidebar accordions in landscape mobile mode AND desktop * Auto-open sidebar accordions in landscape mobile mode AND desktop
* Ensures sidebar content is always visible except in portrait mobile * Ensures sidebar content is always visible except in portrait mobile
@@ -504,68 +486,6 @@
// INITIALIZATION // INITIALIZATION
// ============================================================================= // =============================================================================
/**
* Initialize zoom control button handlers
* Handles close button, show button, and toggle button
*/
function initZoomControlButtons() {
const closeBtn = document.getElementById('zoom-close');
const showBtn = document.getElementById('show-zoom-menu-btn');
const toggleBtn = document.getElementById('zoom-toggle-button');
const zoomControl = document.getElementById('zoom-control');
// Helper function to toggle zoom visibility
function toggleZoom(show) {
if (show) {
zoomControl.classList.remove('zoom-hidden');
if (showBtn) showBtn.classList.add('zoom-hidden');
// Don't add zoom-active class - button stays same color
localStorage.setItem('cv-zoom-visible', 'true');
} else {
zoomControl.classList.add('zoom-hidden');
if (showBtn) showBtn.classList.remove('zoom-hidden');
// Don't remove zoom-active class - wasn't added
localStorage.setItem('cv-zoom-visible', 'false');
}
}
// Close button handler
if (closeBtn && zoomControl) {
closeBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
console.log('Zoom close clicked');
toggleZoom(false);
});
}
// Show button handler (hamburger menu)
if (showBtn && zoomControl) {
showBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
console.log('Zoom show clicked');
toggleZoom(true);
});
}
// Toggle button handler (fixed button)
if (toggleBtn && zoomControl) {
toggleBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const isVisible = !zoomControl.classList.contains('zoom-hidden');
console.log('Zoom toggle clicked, currently visible:', isVisible);
toggleZoom(!isVisible);
});
}
// No need to set initial state since we don't use zoom-active class anymore
const isVisible = localStorage.getItem('cv-zoom-visible');
console.log('Zoom control initialized. localStorage cv-zoom-visible:', isVisible);
}
/** /**
* Initialize all CV interactive features when DOM is ready * Initialize all CV interactive features when DOM is ready
*/ */
@@ -576,8 +496,8 @@
initErrorToastClose(); initErrorToastClose();
initHTMXHandlers(); initHTMXHandlers();
handleLandscapeAccordions(); // Auto-open sidebar accordions in landscape mode handleLandscapeAccordions(); // Auto-open sidebar accordions in landscape mode
initZoomControlButtons();
// Note: Scroll behavior now handled by hyperscript in index.html body tag // Note: Scroll behavior now handled by hyperscript in index.html body tag
// Note: Zoom control buttons now handled by hyperscript (zoom._hs)
// initScrollBehaviorJS() removed - hyperscript handleScroll() is preferred // initScrollBehaviorJS() removed - hyperscript handleScroll() is preferred
}); });
@@ -65,15 +65,16 @@
<span>{{if eq .Lang "es"}}Acciones Rápidas{{else}}Quick Actions{{end}}</span> <span>{{if eq .Lang "es"}}Acciones Rápidas{{else}}Quick Actions{{end}}</span>
</div> </div>
<a href="#" class="menu-item menu-item-action" onclick="collapseAllSections(event)"> <a href="#" class="menu-item menu-item-action" _="on click call collapseAllSections(event)">
<iconify-icon icon="mdi:arrow-collapse-all" width="20" height="20"></iconify-icon> <iconify-icon icon="mdi:arrow-collapse-all" width="20" height="20"></iconify-icon>
<span>{{if eq .Lang "es"}}Colapsar Todo{{else}}Collapse All{{end}}</span> <span>{{if eq .Lang "es"}}Colapsar Todo{{else}}Collapse All{{end}}</span>
</a> </a>
<a href="#" class="menu-item menu-item-action" onclick="expandAllSections(event)"> <a href="#" class="menu-item menu-item-action" _="on click call expandAllSections(event)">
<iconify-icon icon="mdi:arrow-expand-all" width="20" height="20"></iconify-icon> <iconify-icon icon="mdi:arrow-expand-all" width="20" height="20"></iconify-icon>
<span>{{if eq .Lang "es"}}Expandir Todo{{else}}Expand All{{end}}</span> <span>{{if eq .Lang "es"}}Expandir Todo{{else}}Expand All{{end}}</span>
</a> </a>
<a href="#" id="show-zoom-menu-btn" class="menu-item menu-item-action zoom-hidden"> <a href="#" id="show-zoom-menu-btn" class="menu-item menu-item-action zoom-hidden"
_="on click call showZoomControl()">
<iconify-icon icon="mdi:magnify" width="20" height="20"></iconify-icon> <iconify-icon icon="mdi:magnify" width="20" height="20"></iconify-icon>
<span>{{if eq .Lang "es"}}Zoom{{else}}Zoom{{end}}</span> <span>{{if eq .Lang "es"}}Zoom{{else}}Zoom{{end}}</span>
</a> </a>
+2 -1
View File
@@ -40,7 +40,8 @@
id="zoom-close" id="zoom-close"
class="zoom-close-btn" class="zoom-close-btn"
aria-label="{{if eq .Lang "es"}}Cerrar control de zoom{{else}}Close zoom control{{end}}" aria-label="{{if eq .Lang "es"}}Cerrar control de zoom{{else}}Close zoom control{{end}}"
title="{{if eq .Lang "es"}}Cerrar{{else}}Close{{end}}"> title="{{if eq .Lang "es"}}Cerrar{{else}}Close{{end}}"
_="on click call hideZoomControl()">
<iconify-icon icon="mdi:close" width="16" height="16" style="pointer-events: none;"></iconify-icon> <iconify-icon icon="mdi:close" width="16" height="16" style="pointer-events: none;"></iconify-icon>
</button> </button>
@@ -5,7 +5,8 @@
class="fixed-btn zoom-toggle-btn no-print has-tooltip" class="fixed-btn zoom-toggle-btn no-print has-tooltip"
aria-label="{{if eq .Lang "es"}}Alternar control de zoom{{else}}Toggle zoom control{{end}}" aria-label="{{if eq .Lang "es"}}Alternar control de zoom{{else}}Toggle zoom control{{end}}"
data-tooltip="{{if eq .Lang "es"}}Control de zoom{{else}}Zoom control{{end}}" data-tooltip="{{if eq .Lang "es"}}Control de zoom{{else}}Zoom control{{end}}"
_="on mouseenter call highlightZoomControl(true) _="on click call toggleZoomControl()
on mouseenter call highlightZoomControl(true)
on mouseleave call highlightZoomControl(false)"> on mouseleave call highlightZoomControl(false)">
<iconify-icon icon="mdi:magnify" width="28" height="28"></iconify-icon> <iconify-icon icon="mdi:magnify" width="28" height="28"></iconify-icon>
</button> </button>