package handlers import ( "net/http" "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 r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } // Get current preferences from context (set by middleware, already migrated) prefs := middleware.GetPreferences(r) currentLength := prefs.CVLength // Toggle state newLength := "long" if currentLength == "long" { newLength = "short" } // Save new state middleware.SetPreferenceCookie(w, "cv-length", 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 r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } // Get current preferences from context (set by middleware, already migrated) prefs := middleware.GetPreferences(r) currentIcons := prefs.CVIcons // Toggle state newIcons := "hide" if currentIcons == "hide" { newIcons = "show" } // Save new state middleware.SetPreferenceCookie(w, "cv-icons", 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) { // 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 middleware.SetPreferenceCookie(w, "cv-language", 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 == "long" { data["CVLengthClass"] = "cv-long" } else { data["CVLengthClass"] = "cv-short" } data["ShowIcons"] = (prefs.CVIcons == "show") data["ThemeClean"] = (prefs.CVTheme == "clean") // 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 } // Get current preferences from context (set by middleware) prefs := middleware.GetPreferences(r) currentTheme := prefs.CVTheme // Toggle state newTheme := "clean" if currentTheme == "clean" { newTheme = "default" } // Save new state middleware.SetPreferenceCookie(w, "cv-theme", 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) }