2025-11-20 17:01:50 +00:00
|
|
|
package handlers
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"net/http"
|
2025-11-20 17:56:47 +00:00
|
|
|
|
|
|
|
|
"github.com/juanatsap/cv-site/internal/middleware"
|
2025-11-20 17:01:50 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ==============================================================================
|
|
|
|
|
// 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 r.Method != http.MethodPost {
|
|
|
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-20 17:56:47 +00:00
|
|
|
// Get current preferences from context (set by middleware, already migrated)
|
|
|
|
|
prefs := middleware.GetPreferences(r)
|
|
|
|
|
currentLength := prefs.CVLength
|
2025-11-20 17:01:50 +00:00
|
|
|
|
|
|
|
|
// Toggle state
|
|
|
|
|
newLength := "long"
|
|
|
|
|
if currentLength == "long" {
|
|
|
|
|
newLength = "short"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save new state
|
2025-11-20 17:56:47 +00:00
|
|
|
middleware.SetPreferenceCookie(w, "cv-length", newLength)
|
2025-11-20 17:01:50 +00:00
|
|
|
|
2025-12-01 14:16:24 +00:00
|
|
|
// 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)
|
2025-11-20 17:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ToggleIcons handles icon visibility toggle using atomic out-of-band swaps
|
|
|
|
|
func (h *CVHandler) ToggleIcons(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
if r.Method != http.MethodPost {
|
|
|
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-20 17:56:47 +00:00
|
|
|
// Get current preferences from context (set by middleware, already migrated)
|
|
|
|
|
prefs := middleware.GetPreferences(r)
|
|
|
|
|
currentIcons := prefs.CVIcons
|
2025-11-20 17:01:50 +00:00
|
|
|
|
|
|
|
|
// Toggle state
|
|
|
|
|
newIcons := "hide"
|
|
|
|
|
if currentIcons == "hide" {
|
|
|
|
|
newIcons = "show"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save new state
|
2025-11-20 17:56:47 +00:00
|
|
|
middleware.SetPreferenceCookie(w, "cv-icons", newIcons)
|
2025-11-20 17:01:50 +00:00
|
|
|
|
2025-12-01 14:16:24 +00:00
|
|
|
// 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)
|
2025-11-20 17:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
|
// Get language from query parameter
|
|
|
|
|
lang := r.URL.Query().Get("lang")
|
|
|
|
|
if lang == "" {
|
|
|
|
|
lang = "en"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validate language
|
|
|
|
|
if lang != "en" && lang != "es" {
|
|
|
|
|
HandleError(w, r, BadRequestError("Unsupported language. Use 'en' or 'es'"))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save language preference
|
2025-11-20 17:56:47 +00:00
|
|
|
middleware.SetPreferenceCookie(w, "cv-language", lang)
|
2025-11-20 17:01:50 +00:00
|
|
|
|
|
|
|
|
// Prepare template data
|
|
|
|
|
data, err := h.prepareTemplateData(lang)
|
|
|
|
|
if err != nil {
|
|
|
|
|
HandleError(w, r, DataLoadError(err, "CV"))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-20 17:56:47 +00:00
|
|
|
// Get current preferences from context (set by middleware)
|
|
|
|
|
prefs := middleware.GetPreferences(r)
|
2025-11-20 17:01:50 +00:00
|
|
|
|
|
|
|
|
// Add preferences to data
|
2025-11-20 17:56:47 +00:00
|
|
|
if prefs.CVLength == "long" {
|
2025-11-20 17:01:50 +00:00
|
|
|
data["CVLengthClass"] = "cv-long"
|
|
|
|
|
} else {
|
|
|
|
|
data["CVLengthClass"] = "cv-short"
|
|
|
|
|
}
|
2025-11-20 17:56:47 +00:00
|
|
|
data["ShowIcons"] = (prefs.CVIcons == "show")
|
|
|
|
|
data["ThemeClean"] = (prefs.CVTheme == "clean")
|
2025-11-20 17:01:50 +00:00
|
|
|
|
|
|
|
|
// 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("Content-Type", "text/html; charset=utf-8")
|
|
|
|
|
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 r.Method != http.MethodPost {
|
|
|
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-20 17:56:47 +00:00
|
|
|
// Get current preferences from context (set by middleware)
|
|
|
|
|
prefs := middleware.GetPreferences(r)
|
|
|
|
|
currentTheme := prefs.CVTheme
|
2025-11-20 17:01:50 +00:00
|
|
|
|
|
|
|
|
// Toggle state
|
|
|
|
|
newTheme := "clean"
|
|
|
|
|
if currentTheme == "clean" {
|
|
|
|
|
newTheme = "default"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save new state
|
2025-11-20 17:56:47 +00:00
|
|
|
middleware.SetPreferenceCookie(w, "cv-theme", newTheme)
|
2025-11-20 17:01:50 +00:00
|
|
|
|
2025-12-01 14:16:24 +00:00
|
|
|
// 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)
|
2025-11-20 17:01:50 +00:00
|
|
|
}
|