fix todo mvc

This commit is contained in:
maddalax 2024-09-21 12:08:23 -05:00
parent da7e22c446
commit 1f98f49735
6 changed files with 57 additions and 55 deletions

View file

@ -8,8 +8,6 @@ import (
"strings" "strings"
) )
type Headers = map[string]string
type Partial struct { type Partial struct {
Headers *Headers Headers *Headers
Root *Element Root *Element
@ -51,6 +49,13 @@ func NewPartial(root *Element) *Partial {
} }
} }
func SwapManyPartialWithHeaders(ctx *RequestContext, headers *Headers, swaps ...*Element) *Partial {
return NewPartialWithHeaders(
headers,
SwapMany(ctx, swaps...),
)
}
func SwapManyPartial(ctx *RequestContext, swaps ...*Element) *Partial { func SwapManyPartial(ctx *RequestContext, swaps ...*Element) *Partial {
return NewPartial( return NewPartial(
SwapMany(ctx, swaps...), SwapMany(ctx, swaps...),

View file

@ -5,10 +5,16 @@ import (
"net/url" "net/url"
) )
type Headers = map[string]string
func ReplaceUrlHeader(url string) *Headers { func ReplaceUrlHeader(url string) *Headers {
return NewHeaders(hx.ReplaceUrlHeader, url) return NewHeaders(hx.ReplaceUrlHeader, url)
} }
func PushUrlHeader(url string) *Headers {
return NewHeaders(hx.PushUrlHeader, url)
}
func CombineHeaders(headers ...*Headers) *Headers { func CombineHeaders(headers ...*Headers) *Headers {
m := make(Headers) m := make(Headers)
for _, h := range headers { for _, h := range headers {

View file

@ -90,28 +90,10 @@ func (m *AttributeMap) Render(builder *strings.Builder) {
} }
} }
func toHtmxTriggerName(event string) string {
if strings.HasPrefix(event, "htmx:") {
return event[5:]
}
if strings.HasPrefix(event, "on") {
return event[2:]
}
return event
}
func formatEventName(event string, isDomEvent bool) string {
raw := toHtmxTriggerName(event)
if isDomEvent {
return "on" + raw
}
return event
}
func (l *LifeCycle) fromAttributeMap(event string, key string, value string, builder *strings.Builder) { func (l *LifeCycle) fromAttributeMap(event string, key string, value string, builder *strings.Builder) {
if key == hx.GetAttr || key == hx.PatchAttr || key == hx.PostAttr { if key == hx.GetAttr || key == hx.PatchAttr || key == hx.PostAttr {
TriggerString(toHtmxTriggerName(event)).Render(builder) TriggerString(hx.ToHtmxTriggerName(event)).Render(builder)
} }
Attribute(key, value).Render(builder) Attribute(key, value).Render(builder)
@ -125,7 +107,7 @@ func (l *LifeCycle) Render(builder *strings.Builder) {
for _, command := range commands { for _, command := range commands {
switch c := command.(type) { switch c := command.(type) {
case JsCommand: case JsCommand:
eventName := formatEventName(event, true) eventName := hx.FormatEventName(event, true)
m[eventName] += fmt.Sprintf("%s;", c.Command) m[eventName] += fmt.Sprintf("%s;", c.Command)
case *AttributeMap: case *AttributeMap:
for k, v := range c.ToMap() { for k, v := range c.ToMap() {

View file

@ -13,11 +13,32 @@ type TriggerEvent struct {
modifiers []Modifier modifiers []Modifier
} }
func ToHtmxTriggerName(event string) string {
if strings.HasPrefix(event, "htmx:") {
return event[5:]
}
if strings.HasPrefix(event, "on") {
return event[2:]
}
return event
}
func FormatEventName(event string, isDomEvent bool) string {
raw := ToHtmxTriggerName(event)
if isDomEvent {
return "on" + raw
}
return event
}
func NewTrigger(opts ...TriggerEvent) *Trigger { func NewTrigger(opts ...TriggerEvent) *Trigger {
t := Trigger{ t := Trigger{
events: make([]TriggerEvent, 0), events: make([]TriggerEvent, 0),
} }
if len(opts) > 0 { if len(opts) > 0 {
for i, opt := range opts {
opts[i].event = ToHtmxTriggerName(opt.event)
}
t.events = opts t.events = opts
} }
return &t return &t
@ -31,11 +52,7 @@ func NewStringTrigger(trigger string) Trigger {
split := strings.Split(trigger, ", ") split := strings.Split(trigger, ", ")
for _, s := range split { for _, s := range split {
parts := strings.Split(s, " ") parts := strings.Split(s, " ")
event := parts[0] event := ToHtmxTriggerName(parts[0])
if strings.HasPrefix(event, "htmx:") {
event = event[5:]
}
modifiers := make([]Modifier, 0) modifiers := make([]Modifier, 0)
if len(parts) > 1 { if len(parts) > 1 {

View file

@ -11,15 +11,6 @@ import (
"todolist/partials/load" "todolist/partials/load"
) )
type CustomContext struct {
echo.Context
locator *service.Locator
}
func (c *CustomContext) ServiceLocator() *service.Locator {
return c.locator
}
func main() { func main() {
locator := service.NewLocator() locator := service.NewLocator()

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/maddalax/htmgo/framework/h" "github.com/maddalax/htmgo/framework/h"
"github.com/maddalax/htmgo/framework/hx"
"todolist/ent" "todolist/ent"
"todolist/internal/tasks" "todolist/internal/tasks"
) )
@ -55,7 +56,7 @@ func Input(list []*ent.Task) *h.Element {
h.Class("pl-12 text-xl p-4 w-full outline-none focus:outline-2 focus:outline-rose-400"), h.Class("pl-12 text-xl p-4 w-full outline-none focus:outline-2 focus:outline-rose-400"),
h.Placeholder("What needs to be done?"), h.Placeholder("What needs to be done?"),
h.Post(h.GetPartialPath(Create)), h.Post(h.GetPartialPath(Create)),
h.HxTrigger("keyup[keyCode==13]"), h.HxTrigger(hx.OnEvent(hx.TriggerKeyUpEnter)),
), ),
CompleteAllIcon(list), CompleteAllIcon(list),
) )
@ -70,7 +71,7 @@ func CompleteAllIcon(list []*ent.Task) *h.Element {
h.ClassX("absolute top-0 left-0 p-4 rotate-90 text-2xl cursor-pointer", map[string]bool{ h.ClassX("absolute top-0 left-0 p-4 rotate-90 text-2xl cursor-pointer", map[string]bool{
"text-slate-400": notCompletedCount > 0, "text-slate-400": notCompletedCount > 0,
}), h.Text(""), }), h.Text(""),
h.PostPartialOnClickQs(CompleteAll, h.Ternary(notCompletedCount > 0, "complete=true", "complete=false")), h.PostPartialWithQs(CompleteAll, h.NewQs("complete", h.Ternary(notCompletedCount > 0, "true", "false"))),
) )
} }
@ -92,7 +93,7 @@ func Footer(list []*ent.Task, activeTab Tab) *h.Element {
h.Class("flex items-center gap-4"), h.Class("flex items-center gap-4"),
h.List(tabs, func(tab Tab, index int) *h.Element { h.List(tabs, func(tab Tab, index int) *h.Element {
return h.P( return h.P(
h.PostOnClick(h.GetPartialPathWithQs(ChangeTab, "tab="+tab)), h.PostOnClick(h.GetPartialPathWithQs(ChangeTab, h.NewQs("tab", tab))),
h.ClassX("cursor-pointer px-2 py-1 rounded", map[string]bool{ h.ClassX("cursor-pointer px-2 py-1 rounded", map[string]bool{
"border border-rose-600": activeTab == tab, "border border-rose-600": activeTab == tab,
}), }),
@ -147,7 +148,7 @@ func Task(task *ent.Task, editing bool) *h.Element {
), ),
h.Input( h.Input(
"text", "text",
h.PostPartialOnTrigger(UpdateName, h.TriggerBlur, h.TriggerKeyUpEnter), h.PostPartial(UpdateName, hx.TriggerBlur, hx.TriggerKeyUpEnter),
h.Attributes(&h.AttributeMap{ h.Attributes(&h.AttributeMap{
"placeholder": "What needs to be done?", "placeholder": "What needs to be done?",
"autofocus": "true", "autofocus": "true",
@ -162,8 +163,7 @@ func Task(task *ent.Task, editing bool) *h.Element {
), ),
), ),
h.P( h.P(
h.HxTrigger("dblclick"), h.GetPartialWithQs(EditNameForm, h.NewQs("id", task.ID.String()), hx.TriggerDblClick),
h.GetPartialWithQs(EditNameForm, "id="+task.ID.String()),
h.ClassX("text-xl break-all text-wrap truncate", map[string]bool{ h.ClassX("text-xl break-all text-wrap truncate", map[string]bool{
"line-through text-slate-400": task.CompletedAt != nil, "line-through text-slate-400": task.CompletedAt != nil,
}), }),
@ -174,8 +174,8 @@ func Task(task *ent.Task, editing bool) *h.Element {
func CompleteIcon(task *ent.Task) *h.Element { func CompleteIcon(task *ent.Task) *h.Element {
return h.Div( return h.Div(
h.HxTrigger("click"), h.HxTrigger(hx.OnClick()),
h.Post(h.GetPartialPathWithQs(ToggleCompleted, "id="+task.ID.String())), h.Post(h.GetPartialPathWithQs(ToggleCompleted, h.NewQs("id", task.ID.String()))),
h.Class("flex items-center justify-center cursor-pointer"), h.Class("flex items-center justify-center cursor-pointer"),
h.Div( h.Div(
h.ClassX("w-10 h-10 border rounded-full flex items-center justify-center", map[string]bool{ h.ClassX("w-10 h-10 border rounded-full flex items-center justify-center", map[string]bool{
@ -259,11 +259,11 @@ func ToggleCompleted(ctx *h.RequestContext) *h.Partial {
list, _ := service.List() list, _ := service.List()
return h.NewPartial(h.Fragment( return h.SwapManyPartial(ctx,
h.OobSwap(ctx, List(list, getActiveTab(ctx))), List(list, getActiveTab(ctx)),
h.OobSwap(ctx, Footer(list, getActiveTab(ctx))), Footer(list, getActiveTab(ctx)),
h.OobSwap(ctx, CompleteAllIcon(list)), CompleteAllIcon(list),
)) )
} }
func CompleteAll(ctx *h.RequestContext) *h.Partial { func CompleteAll(ctx *h.RequestContext) *h.Partial {
@ -302,7 +302,9 @@ func Create(ctx *h.RequestContext) *h.Partial {
list, _ := service.List() list, _ := service.List()
return h.NewPartial(h.Fragment(h.OobSwap(ctx, CardBody(list, getActiveTab(ctx))))) return h.SwapManyPartial(ctx,
CardBody(list, getActiveTab(ctx)),
)
} }
func ChangeTab(ctx *h.RequestContext) *h.Partial { func ChangeTab(ctx *h.RequestContext) *h.Partial {
@ -311,10 +313,9 @@ func ChangeTab(ctx *h.RequestContext) *h.Partial {
tab := ctx.QueryParam("tab") tab := ctx.QueryParam("tab")
return h.NewPartialWithHeaders(&h.Headers{"hx-push-url": fmt.Sprintf("/tasks?tab=%s", tab)}, return h.SwapManyPartialWithHeaders(ctx,
h.Fragment( h.PushUrlHeader(fmt.Sprintf("/tasks?tab=%s", tab)),
h.OobSwap(ctx, List(list, tab)), List(list, tab),
h.OobSwap(ctx, Footer(list, tab)), Footer(list, tab),
),
) )
} }