~repos /gromer
git clone
https://pyrossh.dev/repos/gromer.git
gromer is a framework and cli to build multipage web apps in golang using htmx and alpinejs.
file:
readme.md
# gromer
[](https://github.com/pyros2097/gromer)
**gromer** is a framework and cli to build multipage web apps in golang using [htmx](https://htmx.org/) and [alpinejs](https://alpinejs.dev/).
It uses a declarative syntax using inline jsx like templates for components and pages.
It also generates http handlers for your routes which follow a particular folder structure. Similar to other frameworks like nextjs, sveltekit.
You can install this extension [vscode-go-inline-html](https://marketplace.visualstudio.com/items?itemName=pyros2097.vscode-go-inline-html) to getsyntax highlighting for these templates.
# Requirements
```shgo >= v1.18```
# Install
```shgo get -u -v github.com/pyros2097/gromer/cmd/gromer```
# Using
You need to follow this directory structure similar to nextjs for the api route handlers to be generated and run the gromer command.
[Example](https://github.com/pyros2097/gromer/tree/master/_example)
**These are some components**
`routes/todo.go`
```gofunc Todo(c Context, todo *todos.Todo) *Node { return c.Render(` <li id="todo-{todo.ID}" class="{ completed: todo.Completed }"> <div class="view"> <form hx-target="#todo-{todo.ID}" hx-swap="outerHTML"> <input type="hidden" name="intent" value="complete" /> <input type="hidden" name="id" value="{todo.ID}" /> <input class="checkbox" type="checkbox" checked="{value}" /> </form> <label>{todo.Text}</label> <form hx-post="/" hx-target="#todo-{todo.ID}" hx-swap="delete"> <input type="hidden" name="intent" value="delete" /> <input type="hidden" name="id" value="{todo.ID}" /> <button class="destroy"></button> </form> </div> </li> `)}```
**These are normal page routes**
`routes/get.go`
```gotype GetParams struct { Page int `json:"page"` Filter string `json:"filter"`}
func GET(c Context, params GetParams) (*Node, int, error) { c.Meta("title", "Gromer Todos") c.Meta("description", "Gromer Todos") c.Meta("author", "gromer") c.Meta("keywords", "gromer") return c.Render(` <div class="todoapp"> <header class="header"> <h1>todos</h1> <form hx-post="/" hx-target="#todo-list" hx-swap="afterbegin" _="on htmx:afterOnLoad set #text.value to ''"> <input type="hidden" name="intent" value="create" /> <input class="new-todo" id="text" name="text" placeholder="What needs to be done?" autofocus="false" autocomplete="off" /> </form> </header> <section class="main"> <input class="toggle-all" id="toggle-all" type="checkbox" /> <label for="toggle-all">Mark all as complete</label> <TodoList id="todo-list" page="{params.Page}" filter="{params.Filter}" /> </section> <footer class="footer"> <TodoCount filter="{params.Filter}" /> <ul class="filters"> <li> <a href="?filter=all">All</a> </li> <li> <a href="?filter=active">Active</a> </li> <li> <a href="?filter=completed">Completed</a> </li> </ul> <form hx-target="#todo-list" hx-post="/"> <input type="hidden" name="intent" value="clear_completed" /> <button type="submit" class="clear-completed" >Clear completed</button> </form> </footer> </div> `), 200, nil}```
And then run the gromer cli command annd it will generate the route handlers in a main.go file,
`main.go`
```go// Code generated by gromer. DO NOT EDIT.package main
import ( "github.com/gorilla/mux" "github.com/pyros2097/gromer" "github.com/pyros2097/gromer/assets" "github.com/pyros2097/gromer/gsx" "github.com/rs/zerolog/log" "gocloud.dev/server"
"github.com/pyros2097/gromer/_example/assets" "github.com/pyros2097/gromer/_example/components" "github.com/pyros2097/gromer/_example/containers" "github.com/pyros2097/gromer/_example/routes/404" "github.com/pyros2097/gromer/_example/routes" "github.com/pyros2097/gromer/_example/routes/about"
)
func init() { gsx.RegisterComponent(components.Todo, "todo") gsx.RegisterComponent(components.Checkbox, "value") gsx.RegisterComponent(containers.TodoCount, "filter") gsx.RegisterComponent(containers.TodoList, "page", "filter")}
func main() { baseRouter := mux.NewRouter() baseRouter.Use(gromer.LogMiddleware) baseRouter.NotFoundHandler = gromer.StatusHandler(not_found_404.GET)
staticRouter := baseRouter.NewRoute().Subrouter() staticRouter.Use(gromer.CacheMiddleware) gromer.StaticRoute(staticRouter, "/gromer/", gromer_assets.FS) gromer.StaticRoute(staticRouter, "/assets/", assets.FS) gromer.StylesRoute(staticRouter, "/styles.css")
pageRouter := baseRouter.NewRoute().Subrouter() gromer.Handle(pageRouter, "GET", "/", routes.GET) gromer.Handle(pageRouter, "POST", "/", routes.POST) gromer.Handle(pageRouter, "GET", "/about", about.GET)
log.Info().Msg("http server listening on http://localhost:3000") srv := server.New(baseRouter, nil) if err := srv.ListenAndServe(":3000"); err != nil { log.Fatal().Stack().Err(err).Msg("failed to listen") }}```
## TODO:
Add inline css formatting
Add inline html formatting