package ersteller_lib import ( "maragu.dev/gomponents" htmx "maragu.dev/gomponents-htmx" "net/http" "strings" ) type HtmxContext interface { Render(node gomponents.Node) SetError(err error) GetLanguage() Language GetActivePath() *ActivePath HasActivePath() bool SetActivePath(activePath *ActivePath) GetPath() string GetPathParam(key string, defaultValue ...string) string } type HtmxContextImpl struct { req *http.Request res http.ResponseWriter language Language activePath *ActivePath } func (c *HtmxContextImpl) SetError(err error) { _, writeErr := c.res.Write([]byte(err.Error())) if writeErr != nil { Error("failed to write error", writeErr) } c.res.WriteHeader(500) } func (c *HtmxContextImpl) GetPathParam(key string, defaultValue ...string) string { pathParam := c.req.PathValue(key) if pathParam != "" { return pathParam } if len(defaultValue) > 0 { return defaultValue[0] } return "" } func (c *HtmxContextImpl) GetPath() string { return c.req.URL.Path } func (c *HtmxContextImpl) SetActivePath(activePath *ActivePath) { c.activePath = activePath } func (c *HtmxContextImpl) GetActivePath() *ActivePath { return c.activePath } func (c *HtmxContextImpl) HasActivePath() bool { return c.activePath != nil } func (c *HtmxContextImpl) GetLanguage() Language { return c.language } func NewHtmxContext(req *http.Request, res http.ResponseWriter, language Language) HtmxContext { return &HtmxContextImpl{req: req, res: res, language: language} } func (c *HtmxContextImpl) Render(node gomponents.Node) { err := node.Render(c.res) if err != nil { Error("failed to render", err) c.SetError(err) } } type HtmxRouteFunc func(ctx HtmxContext) type HtmxPathParam struct { Key string Value string } type HtmxRoute interface { WithPathParams(params ...HtmxPathParam) HtmxRoute ToUrl(language Language, queryParams ...HtmxPathParam) string GetHtmx(language Language, queryParams ...HtmxPathParam) gomponents.Node SetActivePath(activePath *ActivePath) HtmxRoute Add(server *http.ServeMux) Execute(c HtmxContext) } func addLanguageToPath(path string, language Language) string { return "/" + string(language) + path } type HtmxGetRoute struct { Paths LanguagePaths RouteFunc HtmxRouteFunc PathParams []HtmxPathParam ActivePath *ActivePath } func (h HtmxGetRoute) Execute(c HtmxContext) { h.RouteFunc(c) } func (h HtmxGetRoute) SetActivePath(activePath *ActivePath) HtmxRoute { h.ActivePath = activePath return h } func NewHtmxGetRoute(routeFunc HtmxRouteFunc, paths LanguagePaths) *HtmxGetRoute { return &HtmxGetRoute{RouteFunc: routeFunc, Paths: paths} } func (h HtmxGetRoute) Add(server *http.ServeMux) { for language, path := range h.Paths { server.HandleFunc("GET "+addLanguageToPath(path, language), func(res http.ResponseWriter, req *http.Request) { context := NewHtmxContext(req, res, language) if h.ActivePath != nil { context.SetActivePath(h.ActivePath) } h.RouteFunc(context) }) } } func (h HtmxGetRoute) WithPathParams(params ...HtmxPathParam) HtmxRoute { h.PathParams = params return h } func (h HtmxGetRoute) ToUrl(language Language, queryParams ...HtmxPathParam) string { path := addLanguageToPath(h.Paths[language], language) if len(h.PathParams) == 0 { return path } for _, param := range h.PathParams { path = strings.ReplaceAll(path, "{"+param.Key+"}", param.Value) } return path } func (h HtmxGetRoute) GetHtmx(language Language, queryParams ...HtmxPathParam) gomponents.Node { return htmx.Get(h.ToUrl(language, queryParams...)) }