Files
cv-site/internal/handlers/cv_htmx.go
T

209 lines
5.6 KiB
Go
Raw Normal View History

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)
// Get language from query or use current preference
lang := r.URL.Query().Get("lang")
if lang == "" {
lang = prefs.CVLanguage
}
// Prepare template data with length state
cvLengthClass := "cv-short"
if newLength == "long" {
cvLengthClass = "cv-long"
}
data := map[string]interface{}{
"Lang": lang,
"CVLengthClass": cvLengthClass,
}
// Render length-toggle template with out-of-band swaps
tmpl, err := h.templates.Render("length-toggle.html")
if err != nil {
HandleError(w, r, TemplateError(err, "length-toggle.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, "length-toggle.html"))
return
}
}
// 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)
// Get language from query or use current preference
lang := r.URL.Query().Get("lang")
if lang == "" {
lang = prefs.CVLanguage
}
// Prepare template data with logo state
data := map[string]interface{}{
"Lang": lang,
"ShowIcons": (newIcons == "show"),
}
// Render logo-toggle template with out-of-band swaps
tmpl, err := h.templates.Render("logo-toggle.html")
if err != nil {
HandleError(w, r, TemplateError(err, "logo-toggle.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, "logo-toggle.html"))
return
}
}
// 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)
// Get language from query or use current preference
lang := r.URL.Query().Get("lang")
if lang == "" {
lang = prefs.CVLanguage
}
// Prepare template data with theme state
data := map[string]interface{}{
"Lang": lang,
"ThemeClean": (newTheme == "clean"),
}
// Render theme-toggle template with out-of-band swaps
tmpl, err := h.templates.Render("theme-toggle.html")
if err != nil {
HandleError(w, r, TemplateError(err, "theme-toggle.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, "theme-toggle.html"))
return
}
}