3c49f8f7cf
Replace verbose document.getElementById() and document.querySelectorAll()
with cleaner hyperscript syntax:
- #id for ID selectors
- .class and the first .class for class selectors
- <selector/> query literals for complex selectors
- #{variable} for dynamic ID interpolation
Files changed:
- utils._hs: scrollHeight, details, footer buttons, scrollToSection
- zoom._hs: all zoom control element selectors (14 changes)
- pdf-modal._hs: modal selector
- keyboard._hs: dynamic toggle and modal selectors
- contact-modal.html: response div and modal close
- index.html: ninja-keys bar selector
219 lines
7.4 KiB
Plaintext
219 lines
7.4 KiB
Plaintext
-- ==============================================================================
|
|
-- CV Site - Hyperscript Functions
|
|
-- ==============================================================================
|
|
-- Global hyperscript functions for CV interactive features
|
|
-- Keeps HTML templates clean and behavior organized
|
|
|
|
-- ==============================================================================
|
|
-- PRINT FUNCTIONS
|
|
-- ==============================================================================
|
|
|
|
def printFriendly()
|
|
-- Store current state
|
|
set container to the first .cv-container
|
|
set paper to the first .cv-paper
|
|
set wasClean to container.classList.contains('theme-clean')
|
|
set wasLong to paper.classList.contains('cv-long')
|
|
set currentZoom to localStorage.getItem('cv-zoom') or '100'
|
|
|
|
-- Apply print-friendly settings
|
|
if wasClean is false
|
|
add .theme-clean to container
|
|
end
|
|
remove .cv-long from paper
|
|
add .cv-short to paper
|
|
|
|
-- Reset zoom for consistent printing
|
|
set #zoom-wrapper's *zoom to 1
|
|
|
|
-- Let CSS apply, then print
|
|
wait 50ms
|
|
call window.print()
|
|
|
|
-- Wait for print dialog to close, then restore
|
|
wait 100ms
|
|
|
|
-- Restore original theme
|
|
if wasClean is false
|
|
remove .theme-clean from container
|
|
end
|
|
|
|
-- Restore original length
|
|
if wasLong is true
|
|
remove .cv-short from paper
|
|
add .cv-long to paper
|
|
end
|
|
|
|
-- Restore original zoom by triggering slider input event
|
|
if currentZoom is not '100'
|
|
set #zoom-slider's value to currentZoom
|
|
send input to #zoom-slider
|
|
end
|
|
end
|
|
|
|
-- ==============================================================================
|
|
-- SCROLL BEHAVIOR
|
|
-- ==============================================================================
|
|
|
|
def initScrollBehavior()
|
|
set :lastScroll to 0
|
|
set :scrollThreshold to 100
|
|
set :keepHeaderVisible to false
|
|
end
|
|
|
|
def handleScroll()
|
|
set currentScroll to window.pageYOffset
|
|
set menu to the first .navigation-menu
|
|
set isMenuOpen to menu.classList.contains('menu-open')
|
|
|
|
-- Calculate if at bottom (within 50px)
|
|
set scrollHeight to the document's documentElement's scrollHeight
|
|
set clientHeight to the document's documentElement's clientHeight
|
|
set isAtBottom to (scrollHeight - currentScroll - clientHeight) < 50
|
|
|
|
-- Reset keepHeaderVisible when scrolling up
|
|
if currentScroll < :lastScroll
|
|
set :keepHeaderVisible to false
|
|
end
|
|
|
|
-- Header visibility: Scrolling down past threshold
|
|
if currentScroll > :scrollThreshold and currentScroll > :lastScroll and :keepHeaderVisible is false
|
|
add .header-hidden to .action-bar
|
|
if isMenuOpen is true
|
|
add .header-hidden to menu
|
|
end
|
|
end
|
|
|
|
-- Header visibility: Scrolling up past threshold
|
|
if currentScroll > :scrollThreshold and (currentScroll <= :lastScroll or :keepHeaderVisible is true)
|
|
remove .header-hidden from .action-bar
|
|
if isMenuOpen is true
|
|
remove .header-hidden from menu
|
|
end
|
|
end
|
|
|
|
-- Header visibility: At top
|
|
if currentScroll <= :scrollThreshold
|
|
remove .header-hidden from .action-bar
|
|
if isMenuOpen is true
|
|
remove .header-hidden from menu
|
|
end
|
|
end
|
|
|
|
-- Back to top button visibility (with null check)
|
|
set backToTop to #back-to-top
|
|
if backToTop is not null
|
|
if currentScroll > 300
|
|
set backToTop's *display to 'flex'
|
|
end
|
|
if currentScroll <= 300
|
|
set backToTop's *display to 'none'
|
|
end
|
|
end
|
|
|
|
-- At-bottom class for fixed buttons (with null checks)
|
|
if isAtBottom
|
|
if backToTop is not null then add .at-bottom to backToTop end
|
|
if #info-button is not null then add .at-bottom to #info-button end
|
|
if #shortcuts-button is not null then add .at-bottom to #shortcuts-button end
|
|
if #download-button is not null then add .at-bottom to #download-button end
|
|
if #print-friendly-button is not null then add .at-bottom to #print-friendly-button end
|
|
if #cmd-k-button is not null then add .at-bottom to #cmd-k-button end
|
|
add .at-bottom to .color-theme-switcher
|
|
if #zoom-toggle-button is not null then add .at-bottom to #zoom-toggle-button end
|
|
end
|
|
|
|
if not isAtBottom
|
|
if backToTop is not null then remove .at-bottom from backToTop end
|
|
if #info-button is not null then remove .at-bottom from #info-button end
|
|
if #shortcuts-button is not null then remove .at-bottom from #shortcuts-button end
|
|
if #download-button is not null then remove .at-bottom from #download-button end
|
|
if #print-friendly-button is not null then remove .at-bottom from #print-friendly-button end
|
|
if #cmd-k-button is not null then remove .at-bottom from #cmd-k-button end
|
|
remove .at-bottom from .color-theme-switcher
|
|
if #zoom-toggle-button is not null then remove .at-bottom from #zoom-toggle-button end
|
|
end
|
|
|
|
-- Update last scroll position
|
|
set :lastScroll to currentScroll
|
|
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 <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 <details/>
|
|
for d in details
|
|
call d.removeAttribute('open')
|
|
end
|
|
end
|
|
|
|
-- ==============================================================================
|
|
-- FOOTER HOVER INTERACTION
|
|
-- ==============================================================================
|
|
-- Adds/removes footer-hovered class to fixed buttons when hovering footer
|
|
def setFooterHover(show)
|
|
set buttons to <.download-btn, .print-friendly-btn, .shortcuts-btn, .info-button, .back-to-top, .color-theme-switcher/>
|
|
for btn in buttons
|
|
if show
|
|
add .footer-hovered to btn
|
|
else
|
|
remove .footer-hovered from btn
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ==============================================================================
|
|
-- MODAL HELPERS
|
|
-- ==============================================================================
|
|
-- Close modal when clicking backdrop (outside content)
|
|
def closeOnBackdrop(modal, evt)
|
|
if evt.target is modal
|
|
call modal.close()
|
|
end
|
|
end
|
|
|
|
-- ==============================================================================
|
|
-- SCROLL HELPERS
|
|
-- ==============================================================================
|
|
-- Smooth scroll to top of page
|
|
def scrollToTop(evt)
|
|
call evt.preventDefault()
|
|
call window.scrollTo({top: 0, behavior: 'smooth'})
|
|
end
|
|
|
|
-- ==============================================================================
|
|
-- NAVIGATION SCROLL
|
|
-- ==============================================================================
|
|
-- Smooth scroll to a section by ID
|
|
def scrollToSection(evt, sectionId)
|
|
if evt then call evt.preventDefault() end
|
|
set el to #{sectionId}
|
|
if el is not null
|
|
call el.scrollIntoView({ behavior: 'smooth' })
|
|
-- Close the menu after navigation
|
|
set menu to the first .navigation-menu
|
|
if menu is not null
|
|
remove .menu-hover from menu
|
|
remove .menu-open from menu
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ==============================================================================
|
|
-- KEYBOARD SHORTCUTS
|
|
-- ==============================================================================
|
|
-- Note: Keyboard event handlers are now defined inline in the body tag
|
|
-- because hyperscript 0.9.12 doesn't support nested event handlers (on ... inside def)
|