f9e53c367a
This reverts commit 4c892c5828.
169 lines
5.0 KiB
Go
169 lines
5.0 KiB
Go
package todos
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
. "ersteller-lib"
|
|
"ersteller-lib/starter/ent"
|
|
"ersteller-lib/starter/ent/todo"
|
|
|
|
. "maragu.dev/gomponents"
|
|
. "maragu.dev/gomponents/html"
|
|
)
|
|
|
|
const TodosPath = "/todos"
|
|
const TodosPathDe = "/todos"
|
|
|
|
// i18n texts
|
|
var texts *Texts
|
|
|
|
type Texts struct {
|
|
PageTitle I18nText
|
|
PageDescription I18nText
|
|
HeroTitle I18nText
|
|
AddPlaceholder I18nText
|
|
AddButton I18nText
|
|
DeleteButton I18nText
|
|
SaveButton I18nText
|
|
}
|
|
|
|
type Page struct {
|
|
createPage CreateHtmxPageFunc
|
|
db *ent.Client
|
|
|
|
ViewRoute HtmxRoute
|
|
AddRoute HtmxRoute
|
|
UpdateRoute HtmxRoute
|
|
DeleteRoute HtmxRoute
|
|
}
|
|
|
|
func NewPage(createPage CreateHtmxPageFunc, server HtmxServer, path *ActivePath, db *ent.Client) *Page {
|
|
if texts == nil {
|
|
createTexts()
|
|
}
|
|
p := &Page{createPage: createPage, db: db}
|
|
p.ViewRoute = NewHtmxGetRoute(p.View, LanguagePaths{En: TodosPath, De: TodosPathDe}).SetActivePath(path)
|
|
p.ViewRoute.Add(server)
|
|
|
|
p.AddRoute = NewHtmxPostRoute(p.Add, LanguagePaths{En: TodosPath + "/add", De: TodosPathDe + "/add"})
|
|
p.AddRoute.Add(server)
|
|
p.UpdateRoute = NewHtmxPostRoute(p.Update, LanguagePaths{En: TodosPath + "/update", De: TodosPathDe + "/update"})
|
|
p.UpdateRoute.Add(server)
|
|
p.DeleteRoute = NewHtmxPostRoute(p.Delete, LanguagePaths{En: TodosPath + "/delete", De: TodosPathDe + "/delete"})
|
|
p.DeleteRoute.Add(server)
|
|
return p
|
|
}
|
|
|
|
func createTexts() {
|
|
texts = &Texts{
|
|
PageTitle: NewI18nText(map[Language]string{En: "Todos", De: "Todos"}),
|
|
PageDescription: NewI18nText(map[Language]string{En: "Manage your todos", De: "Verwalte deine Todos"}),
|
|
HeroTitle: NewI18nText(map[Language]string{En: "Todos", De: "Todos"}),
|
|
AddPlaceholder: NewI18nText(map[Language]string{En: "New todo title", De: "Neuer Todo-Titel"}),
|
|
AddButton: NewI18nText(map[Language]string{En: "Add", De: "Hinzufügen"}),
|
|
DeleteButton: NewI18nText(map[Language]string{En: "Delete", De: "Löschen"}),
|
|
SaveButton: NewI18nText(map[Language]string{En: "Save", De: "Speichern"}),
|
|
}
|
|
}
|
|
|
|
func (p *Page) getMetaData() PageWebsiteMetaData {
|
|
return PageWebsiteMetaData{
|
|
Title: texts.PageTitle,
|
|
Lang: En,
|
|
Description: texts.PageDescription,
|
|
}
|
|
}
|
|
|
|
func (p *Page) View(c HtmxContext) {
|
|
language := c.GetLanguage()
|
|
todos, _ := p.db.Todo.Query().Order(ent.Asc(todo.FieldCreatedAt)).All(context.Background())
|
|
content := Group{
|
|
Div(Class("hero-section"),
|
|
H1(Class("hero-title"), Text(texts.HeroTitle.FromLang(language))),
|
|
),
|
|
Div(Class("content-section"),
|
|
p.addForm(c),
|
|
Div(ID("todos-list"), p.todosList(c, todos)),
|
|
),
|
|
}
|
|
p.createPage(c, p.getMetaData(), content)
|
|
}
|
|
|
|
func (p *Page) addForm(c HtmxContext) Node {
|
|
lang := c.GetLanguage()
|
|
return Form(Action(p.AddRoute.ToUrlFromContext(c, lang)), Method("post"),
|
|
Div(Class("form-row"),
|
|
Input(Type("text"), Name("title"), Placeholder(texts.AddPlaceholder.FromLang(lang))),
|
|
Button(Type("submit"), Text(texts.AddButton.FromLang(lang))),
|
|
),
|
|
)
|
|
}
|
|
|
|
func (p *Page) todosList(c HtmxContext, list []*ent.Todo) Node {
|
|
lang := c.GetLanguage()
|
|
items := make([]Node, 0, len(list))
|
|
for _, t := range list {
|
|
items = append(items, p.todoItem(c, lang, t))
|
|
}
|
|
return Ul(Class("todo-list"), Group(items))
|
|
}
|
|
|
|
func (p *Page) todoItem(c HtmxContext, lang Language, t *ent.Todo) Node {
|
|
// Simple inline edit form per item
|
|
return Li(ID(p.itemDomID(t.ID)),
|
|
Form(Action(p.UpdateRoute.ToUrlFromContext(c, lang)), Method("post"),
|
|
Input(Type("hidden"), Name("id"), Value(fmt.Sprintf("%d", t.ID))),
|
|
Input(Type("checkbox"), Name("completed"), If(t.Completed, Attr("checked", "checked"))),
|
|
Input(Type("text"), Name("title"), Value(t.Title)),
|
|
Button(Type("submit"), Text(texts.SaveButton.FromLang(lang))),
|
|
),
|
|
Form(Action(p.DeleteRoute.ToUrlFromContext(c, lang)), Method("post"),
|
|
Input(Type("hidden"), Name("id"), Value(fmt.Sprintf("%d", t.ID))),
|
|
Button(Type("submit"), Class("danger"), Text(texts.DeleteButton.FromLang(lang))),
|
|
),
|
|
)
|
|
}
|
|
|
|
func (p *Page) itemDomID(id int) string { return fmt.Sprintf("todo-%d", id) }
|
|
|
|
// Handlers
|
|
func (p *Page) Add(c HtmxContext) {
|
|
title := strings.TrimSpace(c.GetFormValue("title"))
|
|
if title == "" {
|
|
p.renderList(c)
|
|
return
|
|
}
|
|
_, _ = p.db.Todo.Create().SetTitle(title).Save(context.Background())
|
|
p.renderList(c)
|
|
}
|
|
|
|
func (p *Page) Update(c HtmxContext) {
|
|
idStr := c.GetFormValue("id")
|
|
id, _ := strconv.Atoi(idStr)
|
|
if id == 0 {
|
|
p.renderList(c)
|
|
return
|
|
}
|
|
title := strings.TrimSpace(c.GetFormValue("title"))
|
|
completed := c.GetFormValue("completed") == "on"
|
|
_ = p.db.Todo.UpdateOneID(id).SetTitle(title).SetCompleted(completed).Exec(context.Background())
|
|
p.renderList(c)
|
|
}
|
|
|
|
func (p *Page) Delete(c HtmxContext) {
|
|
idStr := c.GetFormValue("id")
|
|
id, _ := strconv.Atoi(idStr)
|
|
if id != 0 {
|
|
_ = p.db.Todo.DeleteOneID(id).Exec(context.Background())
|
|
}
|
|
p.renderList(c)
|
|
}
|
|
|
|
func (p *Page) renderList(c HtmxContext) {
|
|
todos, _ := p.db.Todo.Query().Order(ent.Asc(todo.FieldCreatedAt)).All(context.Background())
|
|
c.Render(Div(ID("todos-list"), p.todosList(c, todos)))
|
|
}
|