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)
}