30ed21ff7a
- Update all imports from 'constants' to 'c' for brevity - Replace all 'constants.' references with 'c.' - Fix remaining hardcoded content-type headers in httputil - Fix remaining hardcoded User-Agent and Accept headers - Rename CSRF receiver from 'c' to 'csrf' to avoid conflict - Add ContentTypePlainSimple constant for Accept header matching - Fix JSONCached to use proper integer formatting
134 lines
4.0 KiB
Go
134 lines
4.0 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
c "github.com/juanatsap/cv-site/internal/constants"
|
|
"github.com/juanatsap/cv-site/internal/httputil"
|
|
"github.com/juanatsap/cv-site/internal/middleware"
|
|
)
|
|
|
|
// ==============================================================================
|
|
// HTMX TOGGLE HANDLERS
|
|
// These handlers manage user preferences (length, icons, language, theme)
|
|
// using atomic out-of-band swaps for a smooth UX
|
|
// ==============================================================================
|
|
|
|
// ToggleLength handles CV length toggle (short/long) using atomic out-of-band swaps
|
|
func (h *CVHandler) ToggleLength(w http.ResponseWriter, r *http.Request) {
|
|
if !httputil.RequirePost(w, r) {
|
|
return
|
|
}
|
|
|
|
// Get current preferences from context (set by middleware, already migrated)
|
|
prefs := middleware.GetPreferences(r)
|
|
currentLength := prefs.CVLength
|
|
|
|
// Toggle state
|
|
newLength := c.CVLengthLong
|
|
if currentLength == c.CVLengthLong {
|
|
newLength = c.CVLengthShort
|
|
}
|
|
|
|
// Save new state
|
|
middleware.SetPreferenceCookie(w, c.CookieCVLength, newLength)
|
|
|
|
// Return 204 No Content - frontend uses hx-swap="none" so response body is ignored
|
|
// The cookie is set and hyperscript handles the UI state toggle
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// ToggleIcons handles icon visibility toggle using atomic out-of-band swaps
|
|
func (h *CVHandler) ToggleIcons(w http.ResponseWriter, r *http.Request) {
|
|
if !httputil.RequirePost(w, r) {
|
|
return
|
|
}
|
|
|
|
// Get current preferences from context (set by middleware, already migrated)
|
|
prefs := middleware.GetPreferences(r)
|
|
currentIcons := prefs.CVIcons
|
|
|
|
// Toggle state
|
|
newIcons := c.CVIconsHide
|
|
if currentIcons == c.CVIconsHide {
|
|
newIcons = c.CVIconsShow
|
|
}
|
|
|
|
// Save new state
|
|
middleware.SetPreferenceCookie(w, c.CookieCVIcons, newIcons)
|
|
|
|
// Return 204 No Content - frontend uses hx-swap="none" so response body is ignored
|
|
// The cookie is set and hyperscript handles the UI state toggle
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// SwitchLanguage handles language switching with atomic updates
|
|
// Uses HTMX out-of-band swaps to update both the language selector buttons
|
|
// and all CV content wrappers in a single response
|
|
func (h *CVHandler) SwitchLanguage(w http.ResponseWriter, r *http.Request) {
|
|
lang, ok := httputil.LangOrError(r)
|
|
if !ok {
|
|
HandleError(w, r, BadRequestError("Unsupported language. Use 'en' or 'es'"))
|
|
return
|
|
}
|
|
|
|
// Save language preference
|
|
middleware.SetPreferenceCookie(w, c.CookieCVLanguage, lang)
|
|
|
|
// Prepare template data
|
|
data, err := h.prepareTemplateData(lang)
|
|
if err != nil {
|
|
HandleError(w, r, DataLoadError(err, "CV"))
|
|
return
|
|
}
|
|
|
|
// Get current preferences from context (set by middleware)
|
|
prefs := middleware.GetPreferences(r)
|
|
|
|
// Add preferences to data
|
|
if prefs.CVLength == c.CVLengthLong {
|
|
data["CVLengthClass"] = "cv-long"
|
|
} else {
|
|
data["CVLengthClass"] = "cv-short"
|
|
}
|
|
data["ShowIcons"] = (prefs.CVIcons == c.CVIconsShow)
|
|
data["ThemeClean"] = (prefs.CVTheme == c.CVThemeClean)
|
|
|
|
// Render language-switch template with out-of-band swaps
|
|
tmpl, err := h.templates.Render("language-switch.html")
|
|
if err != nil {
|
|
HandleError(w, r, TemplateError(err, "language-switch.html"))
|
|
return
|
|
}
|
|
|
|
w.Header().Set(c.HeaderContentType, c.ContentTypeHTML)
|
|
if err := tmpl.Execute(w, data); err != nil {
|
|
HandleError(w, r, TemplateError(err, "language-switch.html"))
|
|
return
|
|
}
|
|
}
|
|
|
|
// ToggleTheme handles theme toggle (default/clean) using atomic out-of-band swaps
|
|
func (h *CVHandler) ToggleTheme(w http.ResponseWriter, r *http.Request) {
|
|
if !httputil.RequirePost(w, r) {
|
|
return
|
|
}
|
|
|
|
// Get current preferences from context (set by middleware)
|
|
prefs := middleware.GetPreferences(r)
|
|
currentTheme := prefs.CVTheme
|
|
|
|
// Toggle state
|
|
newTheme := c.CVThemeClean
|
|
if currentTheme == c.CVThemeClean {
|
|
newTheme = c.CVThemeDefault
|
|
}
|
|
|
|
// Save new state
|
|
middleware.SetPreferenceCookie(w, c.CookieCVTheme, newTheme)
|
|
|
|
// Return 204 No Content - frontend uses hx-swap="none" so response body is ignored
|
|
// The cookie is set and hyperscript handles the UI state toggle
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|