package internal import ( "bytes" "fmt" "html/template" "log" "net/http" "slices" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) var PAGES = []string { "home", "projects", "resume", "contact", } var SECTIONS = map[string][]string { "home": {"intro", "about"}, "projects": {"intro", "kal"}, "resume": {"intro", "BSc in Computer Science"}, "contact": {"contact"}, } var tmpl *template.Template type Server struct { echo *echo.Echo } func init() { var err error // Create the root template tmpl = template.New("") // Load base/layout templates tmpl, err = tmpl.ParseGlob("views/*.html") if err != nil { log.Fatalf("Error parsing layout templates: %v", err) } // Load page section templates (e.g., pages/home/intro.html) tmpl, err = tmpl.ParseGlob("views/pages/*/*.html") if err != nil { log.Fatalf("Error parsing page templates: %v", err) } log.Println("Templates loaded successfully") } func NewSever() *Server { e := echo.New() e.Use(middleware.Logger()) e.Use(middleware.Recover()) e.Renderer = &TemplateRenderer{Template: tmpl} e.Static("/css", "css") e.Static("/js", "js") s := &Server{echo: e} s.setupRoutes() return s } func (s *Server) setupRoutes() { e := s.echo e.GET("/", func(c echo.Context) error { page := PAGES[0] section := SECTIONS[page][0] content, err := renderContent(page, section) if err != nil { fmt.Printf("Error rendering content for %s/%s: %v\n", page, section, err) return c.String( http.StatusInternalServerError, "Error loading content") } data := PageData{ Title: page, Content: template.HTML(content), Page: page, Pages: PAGES, Sections: SECTIONS[page], } return c.Render(http.StatusOK, "layout.html", data) }) e.GET("/:page", func(c echo.Context) error { page := c.Param("page") if !slices.Contains(PAGES, page) { return c.String(http.StatusNotFound, "Page not found") } section := SECTIONS[page][0] content, err := renderContent(page, section) if err != nil { fmt.Printf("Error rendering content for %s/%s: %v\n", page, section, err) return c.String( http.StatusInternalServerError, "Error loading content") } data := PageData{ Content: template.HTML(content), Page: page, Pages: PAGES, Sections: SECTIONS[page], } return c.Render(http.StatusOK, "layout.html", data) }) // Full page load with section (HTML page with layout) e.GET("/:page/:section", func(c echo.Context) error { page := c.Param("page") if !slices.Contains(PAGES, page) { return c.String(http.StatusNotFound, "Page not found") } section := c.Param("section") sections := SECTIONS[page] if !slices.Contains(sections, section) { return c.String(http.StatusNotFound, "Section not found") } content, err := renderContent(page, section) if err != nil { fmt.Printf("Error rendering content for %s/%s: %v\n", page, section, err) return c.String( http.StatusInternalServerError, "Error loading content") } data := PageData{ Title: fmt.Sprintf("%s - %s", page, section), Content: template.HTML(content), Page: page, Pages: PAGES, Sections: sections, } return c.Render(http.StatusOK, "layout.html", data) }) // API endpoint - return only content (for HTMX) e.GET("/api/:page", func(c echo.Context) error { page := c.Param("page") if !slices.Contains(PAGES, page) { return c.String(http.StatusNotFound, "Page not found") } section := SECTIONS[page][0] content, err := renderContent(page, section) if err != nil { fmt.Printf("Error rendering content for %s/%s: %v\n", page, section, err) return c.String( http.StatusInternalServerError, "Error loading content") } data := SectionData { Content: template.HTML(content), Page: page, Sections: SECTIONS[page], } return c.Render(http.StatusOK, "page.html", data) }) // API endpoint with section - return only content (for HTMX) e.GET("/api/:page/:section", func(c echo.Context) error { page := c.Param("page") if !slices.Contains(PAGES, page) { return c.String(http.StatusNotFound, "Page not found") } section := c.Param("section") if !slices.Contains(SECTIONS[page], section) { return c.String(http.StatusNotFound, "Section not found") } content, err := renderContent(page, section) if err != nil { fmt.Printf("Error rendering content for %s/%s: %v\n", page, section, err) return c.String( http.StatusInternalServerError, "Error loading content") } return c.HTML(http.StatusOK, content) }) } // Helper function to render template content func renderContent(page, section string) (string, error) { // Template name is "{page}_{section}" (e.g., "home_intro", "home_about") templateName := fmt.Sprintf("%s_%s", page, section) var buf bytes.Buffer err := tmpl.ExecuteTemplate(&buf, templateName, nil) if err != nil { return "", err } return buf.String(), nil } func (s *Server) Start(addr string) error { return s.echo.Start(addr) }