// package templates handles Go html/template rendering for the website. package templates import ( "embed" "html/template" "log" "net/http" "gitea.mrixs.me/Mrixs/MrixsCraft-server/internal/config" "gitea.mrixs.me/Mrixs/MrixsCraft-server/internal/database" ) //go:embed html/*.html var templateFS embed.FS // pageData is passed to all templates. type pageData struct { Title string Username string UUID string } // Handler serves template-rendered pages. type Handler struct { db *database.DB cfg *config.Config templates map[string]*template.Template } // NewHandler creates a new templates handler and parses embedded templates. func NewHandler(db *database.DB, cfg *config.Config) *Handler { h := &Handler{db: db, cfg: cfg, templates: make(map[string]*template.Template)} h.parseTemplates() return h } // RegisterRoutes mounts template-rendered pages. func (h *Handler) RegisterRoutes(mux *http.ServeMux) { mux.HandleFunc("GET /", h.index) mux.HandleFunc("GET /login", h.loginPage) mux.HandleFunc("GET /register", h.registerPage) mux.HandleFunc("GET /profile", h.profilePage) } // ── Page handlers ────────────────────────────────────────────── func (h *Handler) index(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } h.render(w, "index.html", pageData{Title: "Главная"}) } func (h *Handler) loginPage(w http.ResponseWriter, r *http.Request) { h.render(w, "login.html", pageData{Title: "Вход"}) } func (h *Handler) registerPage(w http.ResponseWriter, r *http.Request) { h.render(w, "register.html", pageData{Title: "Регистрация"}) } func (h *Handler) profilePage(w http.ResponseWriter, r *http.Request) { h.render(w, "profile.html", pageData{Title: "Профиль"}) } // render executes the "base.html" template which {{template "content" .}} // pulls in the per-page content block. func (h *Handler) render(w http.ResponseWriter, page string, data pageData) { w.Header().Set("Content-Type", "text/html; charset=utf-8") tmpl, ok := h.templates[page] if !ok { log.Printf("Template not found: %s", page) http.Error(w, "Template not found", http.StatusInternalServerError) return } if err := tmpl.ExecuteTemplate(w, "base.html", data); err != nil { log.Printf("Template error (%s): %v", page, err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } } // ── Template parsing ─────────────────────────────────────────── // parseTemplates parses each page template individually by combining the base // layout with the specific page content. This avoids the issue where // multiple {{define "content"}} blocks in wildcard-parsed files overwrite // each other (last alphabetically wins). func (h *Handler) parseTemplates() { pages := []string{"index.html", "login.html", "register.html", "profile.html"} for _, page := range pages { tmpl, err := template.New("base.html").Funcs(template.FuncMap{}).ParseFS(templateFS, "html/base.html", "html/"+page) if err != nil { log.Printf("Template parse error (%s): %v", page, err) continue } h.templates[page] = tmpl log.Printf("Loaded template: %s", page) } }