2025-11-17 14:23:13 +00:00
# Hyperscript Development Rules
## MANDATORY RULES - ALWAYS FOLLOW
### Rule 1: Code Cleanliness
**More than 3 lines of hyperscript → Move to function in file**
- Inline hyperscript in HTML should be kept minimal (≤3 lines)
- Longer logic MUST be extracted to named functions in .\_hs files
- HTML templates should be clean and readable
2025-11-17 15:02:30 +00:00
### Rule 2: File Structure - Organized by Category
**✅ NO def statement limit with latest hyperscript!**
2025-11-17 14:23:13 +00:00
2025-11-17 15:02:30 +00:00
**HISTORICAL NOTE ** (2025-11-17): Hyperscript 0.9.12 had a 3 def limit. Latest version REMOVED this limitation.
- Test verification: `tests/mjs/9-hyperscript-def-limit.test.mjs` (all 5 def statements passed)
- Migration in progress: Moving functions from JavaScript back to hyperscript
2025-11-17 14:23:13 +00:00
2025-11-17 15:02:30 +00:00
**Current Best Practice ** : Organize hyperscript functions by category in separate files
2025-11-17 14:23:13 +00:00
2025-11-17 15:02:30 +00:00
```
static/hyperscript/
├── toggles._hs # Toggle functions (CV length, icons, theme)
├── hover-sync._hs # Hover synchronization functions
├── utils._hs # Utility functions (print, scroll, etc.)
└── keyboard._hs # Keyboard shortcut handlers
```
2025-11-17 14:23:13 +00:00
2025-11-17 15:02:30 +00:00
**Benefits of Hyperscript Organization: **
- ✅ Clean separation of concerns
- ✅ Easy to locate and maintain functions
- ✅ No artificial limitations
- ✅ Server-side hypermedia pattern (functions loaded with HTML)
- ✅ Still callable from anywhere using `call functionName(args)`
2025-11-17 14:23:13 +00:00
### Rule 3: HTML Structure Cleanliness
**HTML must be as clean as possible regarding hyperscript**
✅ **GOOD ** - Clean, readable:
``` html
< input type = "checkbox"
id = "lengthToggle"
_ = "on change call toggleCVLength(my.checked)" >
```
❌ **BAD ** - Inline logic nightmare:
``` html
< input type = "checkbox"
id = "lengthToggle"
_ = "on change
if my.checked
remove .cv-short from .cv-paper
add .cv-long to .cv-paper
set localStorage['cv-length'] to 'long'
set #lengthToggleMenu's checked to true
else
remove .cv-long from .cv-paper
add .cv-short to .cv-paper
set localStorage['cv-length'] to 'short'
set #lengthToggleMenu's checked to false
end" >
```
2025-11-20 09:17:09 +00:00
### Rule 4: Event Handler Externalization Guidelines (2025-11-20)
**Know what CAN and CANNOT be externalized**
#### ✅ **CAN Be Externalized:**
**Simple function calls without complex event inspection:**
``` html
<!-- Navigation handlers -->
< a href = "#section" _ = "on click call scrollToSection(event, 'section')" >
<!-- Toggle handlers -->
< input _ = "on change call toggleCVLength(my.checked)" >
<!-- Hover handlers -->
< button _ = "on mouseenter call syncPdfHover(true)
on mouseleave call syncPdfHover(false)" >
```
**External function example: **
``` hyperscript
def scrollToSection(event, sectionId)
call event.preventDefault()
set element to document.getElementById(sectionId)
if element then call element.scrollIntoView({behavior: 'smooth'}) end
end
```
#### ❌ **MUST Stay Inline:**
**Complex event handlers that inspect event properties:**
``` html
<!-- Keyboard handlers with event.key, event.target inspection -->
< body _ = "on keydown
set tagName to event.target.tagName
set isInputField to (tagName is 'INPUT' or tagName is 'TEXTAREA')
if event.key is 'l' and not event.ctrlKey and not isInputField
halt the event
-- handler logic here
end
end" >
```
**Why: ** The `event` variable in `_=""` attributes is a hyperscript runtime variable. External `def` functions don't have direct access to this event context, causing scoping issues.
#### 🎯 **Optimization for Inline Handlers:**
**Use `then` chains to make inline code more compact:**
``` hyperscript
-- Before (verbose)
if condition
do step1
do step2
do step3
end
-- After (compact with then chains)
if condition
do step1 then do step2 then do step3
end
```
**Example from body keyboard handler: **
``` html
if event.key is '?' and not event.ctrlKey and not event.metaKey and not event.altKey and not isInputField
halt the event then set modal to #shortcuts-modal then if modal then call modal.showModal() end
end
```
2025-11-17 14:23:13 +00:00
## File Organization
```
static/hyperscript/
2025-11-20 09:17:09 +00:00
├── utils._hs → Core utilities (scroll, print, etc.)
├── toggles._hs → Toggle functions (CV length, icons, theme)
├── hover-sync._hs → Hover sync functions (PDF, print, zoom)
├── navigation._hs → Navigation functions (scroll-to-section) [2025-11-20]
└── keyboard._hs → Keyboard handler reference (inline in body tag)
2025-11-17 14:23:13 +00:00
```
### Load Order in templates/index.html:
``` html
2025-11-20 09:17:09 +00:00
< script type = "text/hyperscript" src = "/static/hyperscript/utils._hs" > < / script >
2025-11-17 14:23:13 +00:00
< script type = "text/hyperscript" src = "/static/hyperscript/toggles._hs" > < / script >
2025-11-20 09:17:09 +00:00
< script type = "text/hyperscript" src = "/static/hyperscript/hover-sync._hs" > < / script >
< script type = "text/hyperscript" src = "/static/hyperscript/keyboard._hs" > < / script >
< script type = "text/hyperscript" src = "/static/hyperscript/navigation._hs" > < / script >
< script src = "https://unpkg.com/hyperscript.org@0.9.14" > < / script >
2025-11-17 14:23:13 +00:00
```
## Required Functions
2025-11-20 09:17:09 +00:00
### Core Functions (utils._hs)
2025-11-17 14:23:13 +00:00
1. `printFriendly()` - Handle print-friendly view
2. `initScrollBehavior()` - Initialize scroll variables
3. `handleScroll()` - Manage scroll behavior and fixed button positioning
### Toggle Functions (toggles._hs)
1. `toggleCVLength(isLong)` - Switch between short/long CV
2. `toggleIcons(showIcons)` - Show/hide icons
3. `toggleTheme(isClean)` - Switch between default/clean theme
2025-11-20 09:17:09 +00:00
### Hover Sync Functions (hover-sync._hs)
2025-11-17 14:23:13 +00:00
1. `syncPdfHover(show)` - Sync hover state across PDF buttons
2. `syncPrintHover(show)` - Sync hover state across print buttons
3. `highlightZoomControl(show)` - Highlight zoom control on hover
2025-11-20 09:17:09 +00:00
### Navigation Functions (navigation._hs) [2025-11-20]
1. `scrollToSection(event, sectionId)` - Smooth scroll to CV section
2025-11-17 14:23:13 +00:00
## Why These Rules Exist
### Maintainability
- Functions with descriptive names are self-documenting
- Easier to test and debug
- Changes in one place instead of scattered across templates
### Performance
- Browser caches .\_hs files
- Reduces HTML payload size
- Cleaner separation of concerns
### Hyperscript 0.9.12 Limitation
- Parser breaks with >3 `def` in single file
- MUST split into multiple files
- Each file: ≤3 `def` statements
## Common Mistakes to Avoid
❌ **DON'T ** : Put all functions in one file if you have >3 defs
❌ **DON'T ** : Write long inline hyperscript in HTML
❌ **DON'T ** : Delete functions to work around the 3-def limit
✅ **DO ** : Split functions across multiple .\_hs files
✅ **DO ** : Keep HTML clean with function calls
✅ **DO ** : Maintain all required functions for clean architecture
## Testing After Changes
1. Check browser console for parse errors
2. Verify all functions are defined (no "X is null" errors)
3. Test all toggles work correctly
4. Hard refresh browser (Ctrl+Shift+R) to clear cache
---
2025-11-20 09:17:09 +00:00
## Recent Changes
### 2025-11-20: Event Handler Externalization Guidelines
- ✅ Added Rule 4: Clear guidelines on what can/cannot be externalized
- ✅ Navigation handlers successfully externalized (9 links → 1 function)
- ✅ Documented `then` chain optimization for inline handlers
- ✅ Updated file organization with navigation._hs
- ⚠️ Keyboard handlers documented to stay inline (event context requirement)
---
**Last Updated ** : 2025-11-20
**Hyperscript Version ** : 0.9.14+
2025-11-17 14:23:13 +00:00
**Status ** : MANDATORY - ALWAYS FOLLOW